OpenAPI-Specification icon indicating copy to clipboard operation
OpenAPI-Specification copied to clipboard

Allow for overloading/aliasing of route path

Open brandonscript opened this issue 10 years ago • 34 comments

Per this question: http://stackoverflow.com/questions/27004847/provide-alternate-international-spelling-for-defined-swagger-route/27013027#27013027

It would be great to allow aliasing of route paths for such uses as international spellings of words

brandonscript avatar Nov 19 '14 17:11 brandonscript

I think that my change in #440 would also address this use case.

MattSANU avatar Aug 14 '15 06:08 MattSANU

Nice! Looks like it.

brandonscript avatar Aug 14 '15 15:08 brandonscript

Looking back at the question and the reply (SO), there's potentially a way to do that with 2.0 but it may not be a convenient way in some cases. Let's revisit this.

Parent: #560.

webron avatar Mar 27 '16 22:03 webron

Propose rejecting this per #639

fehguy avatar Apr 11 '16 21:04 fehguy

Not clear how setting allowed languages would solve the problem of internationalized spellings for routes? If you can elaborate, that'd be great.

brandonscript avatar Apr 11 '16 23:04 brandonscript

It's not, but this feels a bit of a niche case that doesn't warrant special treatment. Since Path Item Object can be referenced, it should suffice for this case.

Voting to reject explicit support for this.

webron avatar Apr 12 '16 06:04 webron

If we reject building in something for this, could we at least document the workaround here (with an example YAML)?

ePaul avatar Apr 12 '16 14:04 ePaul

I've also wanted a solution for this, not so much for internationalized variants, but for normal API evolution. For example, a path is called x, but after feedback from your users, you (they) decide it should really be called y. To avoid a breaking change, it would be better to declare x is an alias for y (or y is an alias for x) and mark x as a deprecated operation. One could even hide or suppress the doc for x (in Swagger UI for example), but code generation or generated SDKs or other tools could route requests correctly (i.e. a generated handler/controller could return a 301 Moved Permanently, or simply call the new implementation).

Note that a simple $ref "solution" is less than ideal because one might want to define more than just reuse - marking an operation as deprecated or adding other x- extensions would be useful/necessary, but using $ref may prohibit that since a reference object may contain only the $ref property and no others.

DavidBiesack avatar Oct 15 '18 20:10 DavidBiesack

Agreed David, I wonder if this belongs in a new thread as a proper feature request?

brandonscript avatar Oct 15 '18 22:10 brandonscript

@grapefruit since this is already tagged at "OpenAPI.Next Proposal" and remains Open, this ticket should suffice. If think adding another won't help.

DavidBiesack avatar Oct 16 '18 00:10 DavidBiesack

[Update: obsolete, I had just some different error in my .yaml ] Sorry if I'm wrong, but I would like to use this feature also for format spec. In http://wiki.open311.org/GeoReport_v2/ you can choose between xml and json via suffix. I don't get how to put it in route (/services.{format} does not work), so I would like to make a route /services and a route /services.xml and a route /services.json, which is an alias for services?format=json

flaschenpost avatar Jan 01 '19 17:01 flaschenpost

/services.{format} should work fine with whatever tools you're using, as long as you define a matching format parameter which is in: path.

MikeRalphson avatar Jan 01 '19 18:01 MikeRalphson

There must have been a different error in my .yaml, now it works like expected! Thanks very much for the very fast response andI wish all the programmers a happy new year!

flaschenpost avatar Jan 01 '19 18:01 flaschenpost

I'm researching migrating our existing API to OpenAPI, and this would be a killer feature to help with migration.

gitsakos avatar Sep 20 '19 22:09 gitsakos

Also looking for this feature!

biomadeira avatar Sep 25 '19 08:09 biomadeira

I think you would have to redefine the original X like this:

  /original-x:
    description: Redirects to the new X
    get:
      responses:
        '308':
          description: This resource has been moved
          headers:
            Location:
              schema:
                type: string
                default: /new-x

mattbishop avatar Jan 31 '20 18:01 mattbishop

@mattbishop The problem with this approach is that it is hard in automatic fashion to know what is content schema to expect in the response after the redirect. There should be some way to be able to say that Location will redirect always to some other route, so that client generators could know what response to expect and return. The problem is further complicated because generally those redirects are done automatically by the client (e.g., for fetch in a browser you cannot really usefully disable redirecting), so by calling /original-x, how to know what is the response schema?

mitar avatar Mar 26 '21 23:03 mitar

The content schema of /new-x isn't a concern of /original-x. All this is saying is the original-x has a different location that should be used instead.

This is the same behavior as HTTP now. The client will follow Location to /new-x and negotiate the content-type there.

See https://tools.ietf.org/html/rfc7538#section-3

mattbishop avatar Mar 27 '21 22:03 mattbishop

But codegenerators do not behave like that, at least not that one I have tried. When I try to generate code for /original-x, there are only two options really possible for code to do: or do manual redirects and not automatic, returning simply the Location header for the /original-x call, leaving to the caller of generated code to then do another call to /new-x. Or, follow redirect automatically, but then code cannot really know to which endpoint it is going, or cannot have response be validated/parsed without some dynamic introspection.

So there should be more concrete way to say where is the redirect going, to which API endpoint (and not that just to some URI).

mitar avatar Mar 28 '21 08:03 mitar

@mitar has a great point and maybe that's what the $ref idea earlier can solve for us.

mattbishop avatar Mar 31 '21 02:03 mattbishop

I opened https://github.com/OAI/OpenAPI-Specification/issues/2512 for better handling of redirects (which can be a different thing than aliasing).

mitar avatar Mar 31 '21 02:03 mitar

Just jumping back in here – I agree that an alias path is not the same thing as a redirect. A redirect implies the resource was originally there, and is now moved. Instead, we want a true alias, where both paths return the same value.

This is important for cases where one location might naturally spell a word differently than another, for example UK/Canada vs. US 'flavours' vs. 'flavors', or 'catalogue' vs. 'catalog' .

I'm not attached to one solution or the other, but I'll admit that the $ref solution feels mostly inline with the spirit of OpenAPI. There's just the operationId limitation mentioned in my very old SO post that would need to be addressed, and perhaps some documentation added to make this clear.

paths:
  /authorizations:
    get:
      description: Returns a list of authorizations
      responses:
        200:
          description: OK
  /authorisations:
    $ref: '#/paths/~1authorizations'

brandonscript avatar Apr 04 '21 05:04 brandonscript

wondering if this feature was added.

i have a controller with 2 paths as below, @PostMapping(path = {"/user/vehicle", "/user/car"}) public UserVehicle getUserVehicle(

But i want only "/user/vehicle" to be included in open api doc.

DKTIA avatar May 28 '21 23:05 DKTIA

I've also wanted a solution for this, not so much for internationalized variants, but for normal API evolution. For example, a path is called x, but after feedback from your users, you (they) decide it should really be called y. To avoid a breaking change, it would be better to declare x is an alias for y (or y is an alias for x) and mark x as a deprecated operation. One could even hide or suppress the doc for x (in Swagger UI for example), but code generation or generated SDKs or other tools could route requests correctly (i.e. a generated handler/controller could return a 301 Moved Permanently, or simply call the new implementation).

Note that a simple $ref "solution" is less than ideal because one might want to define more than just reuse - marking an operation as deprecated or adding other x- extensions would be useful/necessary, but using $ref may prohibit that since a reference object may contain only the $ref property and no others.

I'm exactly in that situation right now. A feature request on an API that I'm working on requires me to rename a path. So I need to first create an alias to that path, then tell the mobile app team to use that new path, and then remove the old path once the migration is completed.

But for the documentation part of this (that I do using Open API), I don't see any other solution rather than copy pasting the definition I've for the old path to create the new path.

Ideally, I'd want, in my Open API JSON file, to rename my old path into the new path, and then create a new entry with the old path and make it refer as being an alias to the new path.

But yeah, looks like I can't do that :'(

pierreminiggio avatar Sep 15 '21 14:09 pierreminiggio

OpenAPI 3.1 allows defining reusable path item objects so one can define the full operation(s) in as reusable path items in #/components/pathItems, then reference them:

paths:
  /route/a:
    $ref: '#/components/paths/my-reusable-ops'
  /route/b:
    $ref: '#/components/paths/my-reusable-ops'
components:
  pathItems:
    my-reusable-ops:
      get:
        parameters: ....
        responses: ....
      put:
        parameters: ....
        requestBody: ....
        responses: ....

This is almost a solution for the narrower "exact alias" case - both paths will have identical operations, no copy/paste.

However, it falls short in at least two regards:

  1. you cannot mark one operation as deprecated (or otherwise mark one as the "preferred" operation)
  2. you cannot add an operationId to each operation that is used more than once because OpenAPI requires "The id MUST be unique among all operations described in the API." If there are more than one $ref to the defined path items, the operationId becomes duplicated. Boom. (Many tools and style guides require an operationId on each operation.)

A path item may also be a $ref to another path item. Since OpenAPI 3.1 allows a $ref reference object to have a summary and description, you can differentiate the two cases.

paths:
  /route/a:
    put:
      summary: Update an A thing (deprecated)
      description: Perform a full replacement of the representation of an A thing.
        Instead of this path, use the `put` operation on `/route/b`.
      $ref: '#/components/paths/my-reusable-ops/put'
    get:
      summary: Fetch an A thing (deprecated)
      description: Return the representation of an A thing.
        Instead of this path, use the `get` operation on `/route/b`.
      $ref: '#/components/paths/my-reusable-ops/get'
  /route/b:
    put:
      summary: Update a B thing
      description: Perform a full replacement of the representation of a B thing.
        This replaces the `put` operation on `/route/a`.
      $ref: '#/components/paths/my-reusable-ops/put'
    get:
      summary: Fetch a B thing
      description: Return the representation of a B thing.
        This replaces the `get` operation on `/route/a`.
      $ref: '#/components/paths/my-reusable-ops/get'

However, you still cannot add an operationId or mark one as deprecated. Ideally one could do this:

paths:
  /route/a:
    put:
      summary: Update an A thing
      description: Perform a full replacement of the representation of an A thing.
        Instead of this path, use the `put` operation on `/route/b`.
      $ref: '#/components/paths/my-reusable-ops/put'
      operationId: updateAThing
      deprecated: true
    get:
      summary: Fetch an A thing
      description: Return the representation of an A thing.
        Instead of this path, use the `get` operation on `/route/b`.
      $ref: '#/components/paths/my-reusable-ops/get'
      operationId: getAThing
      deprecated: true

but reference objects cannot have such additional properties.

DavidBiesack avatar Sep 16 '21 01:09 DavidBiesack

@DavidBiesack Thanks for the detailed answer !

pierreminiggio avatar Sep 16 '21 07:09 pierreminiggio

So in recent JSON Schema (after 7, starting with draft-2019-09) they redefined $ref beyond its original standardization (which forbid extra properties next to it) and now they allow it. Maybe OpenAPI specification can follow the suit? See here: https://json-schema.org/understanding-json-schema/structuring.html#ref

mitar avatar Oct 21 '21 11:10 mitar

@mitar OAS 3.1 already allows a $ref in an object to have siblings. OAS 3.1 no longer defines its reference objects as JSON Reference objects (as was done in OAS 3.0). OAS 3.1 also adopts JSON Schema 2020-12 which similarly has no such restriction - $ref is just a keyword.

DavidBiesack avatar Oct 21 '21 11:10 DavidBiesack

Awesome. Then your comment:

but reference objects cannot have such additional properties.

Does not hold anymore? So we could do the "ideal" approach you described?

mitar avatar Oct 21 '21 11:10 mitar

OAS allows description and summary on $ref objects, but not specification extensions. So you can't add arbitrary other properties within the OAS structure. JSON Schema does not have this restriction however, so I believe you can add other properties to a $ref object within a JSON schema inside an OAS document. But most tools will not process them. It may be prudent to define a vocabulary for those.

DavidBiesack avatar Oct 21 '21 12:10 DavidBiesack