Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use JSON Pointers to reference schemas/properties/components in configuration #144

Open
liamnichols opened this issue Aug 15, 2022 · 1 comment

Comments

@liamnichols
Copy link
Member

Related

Background

We currently have various configuration options that rely on references to schemas and properties defined in the original OpenAPI spec document however the approaches that we currently use today have drawbacks because you cannot reference properties/schemas everywhere in the document, particularly parameters within a path/operation.

For reference, the options that refer to specific components in a schema today:

Property Purpose Note
entities.typeOverrides Customising struct/class generation for an entity Uses name resolved by CreateAPI
entities.include Only generate the specified entities Uses name resolved by CreateAPI
entities.exclude Exclude specified entities (or properties) Uses entity name resolved by CreateAPI and property name defined in the schema (with dot notation syntax)
paths.include Only generated specified paths Uses path name from the Schema
paths.exclude Exclude the specified paths from generation Uses path name from the Schema
rename.properties Rename properties with a specific name in a specific entity Uses entity name resolved by CreateAPI and property name defined in the schema (with dot notation syntax)
rename.parameters Rename parameters with a given name Matches schema parameter name but is generate (I.e all status parameters would be renamed)
rename.enumCases Rename enum cases with the specified name Uses the enum name resolved by CreateAPI but raw case name
rename.entities Renaming entities Uses the name resolved by CreateAPI
rename.operations Renaming operations based on their operationId Uses the raw operationId
rename.collectionElements I need to look into this one more Looks like it uses the CreateAPI generated name

Figuring out the table above on its own was very complicated, let alone using these options. Ideally I'll build an example schema and config that can demonstrate these behaviours more clearly and commit them to the test suite.

Proposal

Moving forward however, I want to propose a more standardised approach which is to use JSON Pointer when it comes to referring to components/properties/paths/operations etc in the spec.

Lets take an example from some investigation into enum type overrides in the path parameters:

paths:
  /pet/findByStatus:
    get:
      operationId: findPetsByStatus
      parameters:
        - name: status
          in: query
          schema:
            type: array
            items:
              type: string
              enum:
                - available
                - pending
                - sold
              default: available

This is a particularly complicated one, but while CreateAPI will figure out a creative way to nest and name this enum, there isn't a clear name that we could use to reference this enum in the configuration file.

JSON Pointer is also how the fragment of the $ref (anything after #) is formatted so it should already be familiar. There is some more info here: https://swagger.io/docs/specification/using-ref/

With the complicated example above, the way to reference it would be the following:

enums:
  defaultType: enum
  typeOverride:
    /paths/~1pet~1findByStatus/get/parameters/0/schema/items: struct

Is it pretty in this case? No. But it works. Realistically this schema would be better off extracting that enum type out into a component like so:

paths:
  /pet/findByStatus:
    get:
      operationId: findPetsByStatus
      parameters:
        - name: status
          in: query
          schema:
            type: array
            items:
              $ref: '#/components/schemas/Status'
components:
  schemas:
    Status:
      type: string
      enum:
      - available
      - pending
      - sold
      default: available

That would make it somewhat easier to reference in our config:

enums:
  defaultType: enum
  typeOverride:
    /components/schemas/Status: struct

But we could probably also support a shorthand syntax for schema components which is pretty consistent with what we support already:

enums:
  defaultType: enum
  typeOverride:
    Status: struct # when no leading `/`, assume the value is a schema name

This is something that we could then consistently adapt across all of the other kind of customisations above. In most cases, you will continue to use them like you did before with the shorthand syntax, but if you need to be more specific, you can fallback to the JSON Pointer syntax to reference specific things.

Just note that this approach would require some refactoring to the generator since we don't currently track the pointer location as we iterate over the document. This would be a great addition though and it would then enable us to refactor of all of the configurations to use this approach.

This is currently still just an idea so feedback on the approach is welcome. I'll try and draw up some examples of how this configuration would look when used on the other configurations too.

@liamnichols
Copy link
Member Author

liamnichols commented Aug 15, 2022

Another example of where we hit this limitation today is overriddenResponses.. It currently uses the name of the reference meaning that if you don't have a reference, there is no way to override it.

For example, if I wanted to override the response of /pets/findByStatus, it would have to be written like this:

paths:
  /pets/findByStatus:
    get: 
      responses:
        '200':
          "$ref": "#/components/responses/pets"

This is because overriddenResponses matches on the name of the response (in this case pets), but if you didn't have a direct reference to the response, there would be nothing to match on.

We would be able to avoid this limitation with the use of JSON Pointers instead:

paths:
  overriddenResponses:
    /paths/~1pet~1findByStatus/get/responses/200: Void

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant