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

OAS3 Tag/template to define external-components URL #1979

Open
gerardbosch opened this issue Jul 19, 2019 · 9 comments
Open

OAS3 Tag/template to define external-components URL #1979

gerardbosch opened this issue Jul 19, 2019 · 9 comments
Labels
re-use: ref/id resolution how $ref, operationId, or anything else is resolved
Milestone

Comments

@gerardbosch
Copy link

gerardbosch commented Jul 19, 2019

Hi there,
I find myself using the power of $ref to reference external components in my API definitions, which is great as allows component reuse. But I find myself with this kind of code in my API definitions, where the links to external components are very long and hard to read:

  /foo/validate/{bar}:
    post:
      tags:
        - Foo
      summary: Validate Foo
      operationId: validateFoo
      parameters:
        # path
        - $ref: '#/components/parameters/bar'
      requestBody:
        $ref: '#/components/requestBodies/FooValidation'
      responses:
        '200':
          $ref: '#/components/responses/FooValidation'
        '400':
          $ref: 'http://repos.my-organization.foo/artifactory/libs-release-local/foo/myproject/api/contract/apicomponents-errors/1.0/apicomponents-errors-1.0-api.yaml#/components/responses/BadRequest'
        '401':
          $ref: 'http://repos.my-organization.foo/artifactory/libs-release-local/foo/myproject/api/contract/apicomponents-errors/1.0/apicomponents-errors-1.0-api.yaml#/components/responses/Unauthorized'
        '403':
          $ref: 'http://repos.my-organization.foo/artifactory/libs-release-local/foo/myproject/api/contract/apicomponents-errors/1.0/apicomponents-errors-1.0-api.yaml#/components/responses/Forbidden'
        '500':
          $ref: 'http://repos.my-organization.foo/artifactory/libs-release-local/foo/myproject/api/contract/apicomponents-errors/1.0/apicomponents-errors-1.0-api.yaml#/components/responses/InternalServerError'

I would really like to know if is there any way to define the base-path of that URLs in some kind of variable or YAML tag, so I could lead to $refs of this form:

$ref: '{apicomponents-errors}#/components/schemas/Something'

where I could define apicomponents-errors: http://... just once.

This is not only for better readability, but to allow update the versions all-in-once, as you can see from this example that the referenced components are versioned by its URL.

I have no idea if such kind of feature exists or can be implemented in OAS 3.

P.S. This does not only applies to schemas, but any kind of ref.

@handrews
Copy link
Member

handrews commented Jul 19, 2019

[EDIT: I misunderstood some stuff, see my next comment]

@gerardbosch $ref specifically takes a URI reference per RFC 3986, and unfortunately there is no concept of a base fragment against which you can resolve a partial fragment. Most fragment syntaxes do not have the sort of structure that JSON Pointer does, so the rule that when resolving references the fragment is always entirely replaced made a lot of sense when it was first created. If your fragments look like #foo, #bar, etc., there's no need for a base.

OpenAPI (or really JSON Schema as that is where this feature comes from) would need to come up with a completely different feature for this, because breaking RFC 3986 compatibility would be a huge problem.

In JSON Schema proper, this is handled by allowing $id to declare non-pointer fragments like #foo which can then be referenced from elsewhere in the document. That feature is not currently available in OpenAPI, though.

@gerardbosch
Copy link
Author

gerardbosch commented Jul 20, 2019

@handrews Do you think this issue could be treated as a "Feature Request" in some way? I think it would be very beneficial to have clean $refs to allow proper component reuse, specially when defining collaborative APIs that can have several common components (schemas,...). And that would help having a clear view of the component versions in use as well as per my example.

What I pretend is a way of shortening and reusing the URL part to the .yaml file that contain those reusable components. Defining it once, and using it several times inside an API definition.

@handrews
Copy link
Member

handrews commented Jul 20, 2019

@gerardbosch Actually I'm now realizing that I misread your primary use case of a base URI in the sense of referencing another file/resource. Not referencing a different location in the same file with some sort of relative fragment.

$ref does take relative URI references, but you need to be able to establish the base URI. You would not be able to get down to just a fragment, for reasons I'm not going to get into at the moment, but you could easily do a relative path. Your filesytem layout seems like that might not get you much because of a deep nesting structure, but... if you want short relative references you should structure your directories accordingly.

There might be something here around an OpenAPI-specific variable substitution thing, which would ore closely match what you wrote- I'll leave that to someone else to respond to, I'm mostly just here for JSON Schema stuff 😃

@handrews handrews added the $ref label Feb 24, 2020
@handrews
Copy link
Member

Coming back to this- the base URI is determined by the Server Object's URLs. You would need to at least have the file name of the external file, plus the fragment, but that is a way that you can dramatically shrink the URLs in your $refs.

@gerardbosch does that answer your question? If you still have it- sorry for the delay.

@handrews handrews added re-use re-use: ref/id resolution how $ref, operationId, or anything else is resolved and removed $ref labels Jan 29, 2024
@handrews
Copy link
Member

@gerardbosch Many years later... we now have a proposal for OAS 3.2 that allows OAS documents to self-identify, which also sets the base URI.

So you could do something like this:

openapi: 3.2.0
self: 'http://repos.my-organization.foo/artifactory/libs-release-local/foo/myproject/api/contract/openapi.yaml'
paths:
  /foo/validate/{bar}:
    post:
      responses:
        '200':
          $ref: '#/components/responses/FooValidation'
        '400':
          $ref: 'apicomponents-errors/1.0/apicomponents-errors-1.0-api.yaml#/components/responses/BadRequest'

@gerardbosch if you are still interested in this, would this be sufficient for your needs?

@handrews handrews added this to the v3.2.0 milestone Aug 18, 2024
@gerardbosch
Copy link
Author

Hi @handrews, it has been a long time and right now I'm not sure as I'm not working in the same project currently.

But from your snippet above it's not very clear to me the location where the error is referenced as there's no http://....

So in this case, where is $ref: 'apicomponents-errors/1.0/apicomponents-errors-1.0-api.yaml read from?

And thanks for following up after so much time :)

@handrews
Copy link
Member

@gerardbosch apologies again for the delayed reply, although shorter this time! My late Aug-Oct got rather hectic, and we weren't focusing on 3.2 yet which is where this would be addressed. We are now shifting to that release since 3.0.4 and 3.1.1 are finally out!

In this example, self sets a base URI of:

http://repos.my-organization.foo/artifactory/libs-release-local/foo/myproject/api/contract/openapi.yaml

When you see 'apicomponents-errors/1.0/apicomponents-errors-1.0-api.yaml#/components/responses/BadRequest', what happens (per RFC3986) is that, since the URI-reference starts with a relative path (apicomponents-errors/...) and the base URI ends with a non-empty path segment (openapi.yaml), we replace that segment with the URI-reference, resulting in:

http://repos.my-organization.foo/artifactory/libs-release-local/foo/myproject/api/contract/apicomponents-errors/1.0/apicomponents-errors-1.0-api.yaml#/components/responses/BadRequest

So the combination of the new self field and the relative URI-reference $ref:

  • self: http://repos.my-organization.foo/artifactory/libs-release-local/foo/myproject/api/contract/openapi.yaml in the OpenAPI Object
  • $ref: 'apicomponents-errors/1.0/apicomponents-errors-1.0-api.yaml#/components/responses/BadRequest' in place of a Response Object

is equivalent to:

  • $ref: 'http://repos.my-organization.foo/artifactory/libs-release-local/foo/myproject/api/contract/apicomponents-errors/1.0/apicomponents-errors-1.0-api.yaml#/components/responses/BadRequest' in place of a Response Object

Does that help?

@gerardbosch
Copy link
Author

Hi @handrews, thanks for taking time to check this after so long 🙏

Yes, this looks exactly what I was asking back in the day. I think it's a nice thing, although I had no time to investigate about the self field you mention. I understand that this new syntax will be only available when OAS 3.2 is released, right?

Anyway, thanks for the update! 🙂

@handrews
Copy link
Member

handrews commented Nov 12, 2024

@gerardbosch that is correct. I'm hoping we will get 3.2 out in the first half of 2025. Ideally by April, but hopefully at least by June. self (or possibly $self, there is some debate) will definitely be in 3.2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
re-use: ref/id resolution how $ref, operationId, or anything else is resolved
Projects
None yet
Development

No branches or pull requests

2 participants