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

OpenAPI bundling proposal #2685

Closed
char0n opened this issue Aug 26, 2021 · 8 comments
Closed

OpenAPI bundling proposal #2685

char0n opened this issue Aug 26, 2021 · 8 comments
Labels
Moved to Moonwalk Issues that can be closed or migrated as being addressed in Moonwalk re-use: ref/id resolution how $ref, operationId, or anything else is resolved

Comments

@char0n
Copy link
Contributor

char0n commented Aug 26, 2021

I was wondering if there is metaplan to formalize bundling of OAS definitions as well. Ben Hutton and Mike Ralphson did a great job of formalizing JSON Schema 2020-12 in their article and set guidelines how to bundle JSON Schemas when present in OAS definitions. That's a great start, but we have other specification objects that can be bundled within OAS spec:

Path Item Object

This will be eliminated in future versions of OAS spec and replaced by Reference Object. We have components/pathItems where we can bundle externally referenced Path Item Objects.

All spec objects replaceable by Reference Object

We have special fields for all of these objects in Components Object.

Example.externalValue field

Value of externalValue field is resolved and set as value of value field of Example Object

Link.operationRef field

This IMHO is a little bit problematic. If this field is referencing an Operation Object in external document, and there are multiple Link Objects pointing to the same Operation Object defined in this external document, we have no place where to bundle it as there is no reserved field in Components Object. We have reserved extension prefix so we could possibly use components/x-oas-operations field.

I'm not sure if my reasoning is correct here, but having an explicit guideline how to create Compound OAS definitions/documents would be great.

@char0n
Copy link
Contributor Author

char0n commented Aug 26, 2021

Good point raised on TDC Meeting: naming within Components Object will be challenging

@Relequestual
Copy link
Contributor

@darrelmiller If you have any follow up questions after you've read the article again, do let me know! Slack is probably the easiest way to get hold of me =]

@jdesrosiers
Copy link
Contributor

I'm quite sure there isn't a way to bundle non-schema object easily. You'd have to re-write $refs and deal with naming conflicts in components. However, if OpenAPI adopts the $id keyword from JSON Schema, bundling any type of object would become as simple as it is in JSON Schema.

Example ...

main.openapi.yaml

paths:
  /foo:
    $ref: './foo-path-item.openapi.yaml'

foo.path-item.yaml

get:
  parameters: []

... bundles to ...

bundled.openapi.yaml

paths:
  /foo:
    $ref: './foo-path-item.openapi.yaml'
components:
  'foo.path-item.yaml':
    $id: 'foo.path-item.yaml'
    get:
      parameters: []

We don't have to rewrite the $ref to point to a new location because the $id sets the URI for the Path Item Object as if it was still in the other document.

We can also add a place in components for full OpenAPI documents. This would allow for the external document to not just include the Path Item Object, but also other things that are specific to that Path Item Object such as schemas. (Personally, I'd rather put the schema in it's own file as well, but I couldn't think of another example. I'm sure they exist.)

Example:

bundled.openapi.yaml

paths:
  /:
    $ref: './foo.openapi.yaml#/components/pathItems/foo'
components:
  schemas: 
    createSchema:
      # the $ref below will not resolve here
  openapi:
    $id: './foo.openapi.yaml'
    components:
      pathItems:
        foo:
          post:
            requestBody:
              required: true
              content:
                'application/json':
                  schema:
                    $ref: '#/components/schemas/createFoo'
      schemas:
        createFoo:
          # The $ref resolves here
          type: object

This example shows how embedding like this resolves the naming conflict with the "createFoo" schema. #/components/schemas/createFoo resolves to the embedded foo.openapi.yaml document and not the root document. This also presents a solution to the problem that you can't reliably bundle a schema that uses discriminator because discriminator's behavior is coupled to components (although ideally we fix the problems with discriminator rather than work around them).

@karenetheridge
Copy link
Member

This is getting so complicated that my recommendation for "how should we bundle OpenAPI documents" would be "just don't".

@jdesrosiers
Copy link
Contributor

@karenetheridge

This is getting so complicated

It's really not. I expected that people who are not familiar with JSON Schema's $id keyword might find this confusing at first, but you're definitely not in that category. I think $id is a simple, elegant, and prooven way to enable bundling scenarios from simple to complex.

my recommendation for "how should we bundle OpenAPI documents" would be "just don't".

If you're suggesting that OpenAPI documents should always be developed as one document that can be many thousands of lines long, then that's absolutely not an acceptable solution. That wouldn't be an acceptable way to write and maintain code and writing and maintaining OpenAPI documents should be no different.

If you're suggesting that tooling needs to know how to follow external references, then that's more reasonable. However, once you support external references, supporting $id is fairly trivial, so there's really no reason not to include that as well and have support for bundling.

@ponelat
Copy link

ponelat commented Mar 24, 2022

Another level of bundling is inlining. We often do this for tools to consume definitions without de-referencing.
But we support recursion/cyclic dependencies when we introduced $refs. To accommodate that I'm thinking of proposing a new keyword to declare something as recursive. Then we'd be able to inline entire documents.

I'm putting the note here as a reminder, and I apologies if this isn't in scope of bundling. But thought it relevant.

@handrews
Copy link
Member

handrews commented Nov 6, 2022

Folks interested in this issue will likely be interested in the general referencing discussion that has recently started. Bundling is one topic covered.

@handrews handrews added $ref re-use: ref/id resolution how $ref, operationId, or anything else is resolved and removed $ref labels Jan 28, 2024
@handrews handrews added the Moved to Moonwalk Issues that can be closed or migrated as being addressed in Moonwalk label May 24, 2024
@handrews
Copy link
Member

This discussion is best continued in the context of Moonwalk (v4.0), specifically at:

Closing this in favor of that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Moved to Moonwalk Issues that can be closed or migrated as being addressed in Moonwalk re-use: ref/id resolution how $ref, operationId, or anything else is resolved
Projects
None yet
Development

No branches or pull requests

6 participants