django-json-api/django-rest-framework-json-api

OpenApi Schema references non-existing JSON fields

aseidma opened this issue · 8 comments

Description of the Bug Report

When generating an OpenApi schema using python manage.py generateschema --file schema.yml, the schema is generated without errors, but references non-existent fields via $ref, making it unuseable.

E.g.:

paths:
  /login:
    post:
      operationId: create/login
      description: ''
      parameters: []
      tags:
      - login
      requestBody:
        content:
          application/vnd.api+json:
            schema:
              required:
              - data
              properties:
                data:
                  type: object
                  required:
                  - type
                  additionalProperties: false
                  properties:
                    type:
                      $ref: '#/components/schemas/type' # <--- This does not exist
                    id:
                      $ref: '#/components/schemas/id' # <--- This does not exist
                    links:
                      type: object
                      properties:
                        self:
                          $ref: '#/components/schemas/link' # <--- This does not exist
                    attributes:
                      type: object
                      properties: {}

For reference, this is what #/components looks like in the generated file:

components:
  schemas:
    Login:
      type: object
      required:
      - type
      - id
      additionalProperties: false
      properties:
        type:
          $ref: '#/components/schemas/type' # <--- This does not exist
        id:
          $ref: '#/components/schemas/id' # <--- This does not exist
        links:
          type: object
          properties:
            self:
              $ref: '#/components/schemas/link' # <--- This does not exist
        attributes:
          type: object
          properties:
            expiry:
              type: string
              readOnly: true
            token:
              type: string
              readOnly: true
    SuccessMessage:
      type: object
      required:
      - type
      - id
      additionalProperties: false
      properties:
        type:
          $ref: '#/components/schemas/type' # <--- This does not exist
        id:
          $ref: '#/components/schemas/id' # <--- This does not exist
        links:
          type: object
          properties:
            self:
              $ref: '#/components/schemas/link' # <--- This does not exist
        attributes:
          type: object
          properties:
            success:
              type: boolean
              readOnly: true

Checklist

  • Certain that this is a bug (if unsure or you have a question use discussions instead)
  • Code snippet or unit test added to reproduce bug

type, id and links are all automatically generated by DJA as per JSON:API specification, so that is why those are referenced in OpenAPI as well.

Hence, could you elaborate what you exactly mean with "does not exist"?

Thank you for getting back so quickly!
What I mean by "does not exist" ist that $ref is supposed to point to a JSON value within the schema document, but the value it points to in this case does not exist.
See how $ref should be used here: https://swagger.io/docs/specification/using-ref/

In the generated schema, an example of such an error would be that one of the $ref values points to #/components/schemas/type. This means it should reference the value of something like this:

components:
  schemas:
    type: 'REFERENCED VALUE'

However, as you can see in the provided example in the original post, the components.schemas object in the generated schema file does not have a type property. The structure is components => schemas => Login => type, not components => schemas => type as pointed to by the reference.

This leads to errors when trying to use the openapi schema anywhere (e.g. swagger as explained in the DJA docs), as the created schema is invalid.

@n2ygk could you have a look at this? Thanks.

n2ygk commented

@sliverc @aseidma hmm, I see them defined in the source code:

https://github.com/django-json-api/django-rest-framework-json-api/blob/main/rest_framework_json_api/schemas/openapi.py#L208-L221

And when viewing that dict definition they appear to be set:

>>> jsonapi_components["schemas"]["type"]
{'type': 'string', 'description': 'The [type](https://jsonapi.org/format/#document-resource-object-identification) member is used to describe resource objects that share common attributes and relationships.'}
>>> jsonapi_components["schemas"]["id"]
{'type': 'string', 'description': 'Each resource object’s type and id pair MUST [identify](https://jsonapi.org/format/#document-resource-object-identification) a single, unique resource.'}

However when I do a generateschema of my demo app, I also see that this must have gotten overwritten somewhere. Definitely a bug.

n2ygk commented

I'll try tracing this but I have to warn that Tom seems to have abandonded using internal schema generation in DRF and is recommending a different 3rd-party schema generator whose name escapes me at the moment.

n2ygk commented

@sliverc @aseidma ugh, I totally forgot that you have to override the generateschema generator class like documented here

./manage.py generateschema --generator_class rest_framework_json_api.schemas.openapi.SchemaGenerator

We could add a management command that overrides generateschema I suppose, but given the DRF trend away from an internal OAS schema generator, the effort is better put toward switching to using it.

n2ygk commented

See #1082

@n2ygk Do I understand you correctly, once the generateschema command is run as above, OpenAPI works as expected? If so, I guess we should clarify the docs to make this clearer. As it is written now, it seems that a custom generator class is needed, which is not really the case.