Are these OpenAPI 3 paths ambiguous?
See original GitHub issueAs suggested by @MikeRalphson on Stackoverflow, I’m asking the question here as well.
Are those OpenAPI 3 paths ambiguous?
/shops/{shopId}/pets/{petId}
/shops/{shopId}/pets/_search
I want to answer no but, strictly reading the spec, I can’t decide because they seem to fall into none of the 3 statements made by the spec:
- Neither path is concrete (term used in the spec)
- Paths don’t seem to meet the Templated paths with the same hierarchy but different templated names criteria (that is not very clear to me, here is my understanding:
"/shops/{}/pets/{}" != "/shops/{}/pets/_search"
) - Paths do not look like the ambiguous example
In addition to the question asked on Stackoverflow, let me ask two additional questions (below).
Should the OA3 spec be improved?
@MikeRalphson’s reading of the spec: path are not ambiguous because one is more concrete than the other.
If paths are indeed not ambiguous, then the more concrete notion might need to be defined.
How could the OA3 spec be improved?
We might add an example like this:
Assuming paths sharing a common and identical prefix,
/shops/{shopId}/pets
, the more concrete definition,/shops/{shopId}/pets/_search
, will be matched first if used:/shops/{shopId}/pets/{petId} /shops/{shopId}/pets/_search
Or we might only show minimalistic examples involving templated names, and say that they also apply in case of common and identical prefixes:
First statement (concrete vs template case):
/{otherPlace} /here
Second statement (considered identical and invalid):
/{id} /{name}
Third statement is left unchanged (ambiguous resolution):
/{entity}/me /books/{id}
Related excerpt of the OA3 spec
The “Paths object” paragraph of the OpenAPI 3 specification (https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#paths-object) is stating (3 sentences, 3 statements):
When matching URLs, concrete (non-templated) paths would be matched before their templated counterparts. Templated paths with the same hierarchy but different templated names MUST NOT exist as they are identical. In case of ambiguous matching, it’s up to the tooling to decide which one to use.
Those 3 statements are followed by 3 examples (and that’s it):
Assuming the following paths, the concrete definition,
/pets/mine
, will be matched first if used:/pets/{petId} /pets/mine
The following paths are considered identical and invalid:
/pets/{petId} /pets/{name}
The following may lead to ambiguous resolution:
/{entity}/me /books/{id}
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:7 (3 by maintainers)
Top GitHub Comments
@darrelmiller Thanks for your comment. I agree it is not easy to find a good wording.
You will find below some thoughts about it.
First it might be worth defining the notion of identical paths:
because it seems confusing (see https://github.com/OAI/OpenAPI-Specification/issues/2356) and I admit I can only guess the meaning (I have a good guess but that’s only a guess).
I guess the algorithm is:
A definition could be:
An example could be:
Second it might be worth defining the notions of path, parent path and direct parent path.
A definition of path could be (inspired from https://en.wikipedia.org/wiki/URL):
A path is a sequence of path segments separated by a slash (/) and starting with a slash (/). A path segment MUST NOT contain any slash (/).
Some examples could be:
A definition of parent path could be (inspired from https://en.wiktionary.org/wiki/subpath):
Some examples could be:
/faq
is a subpath of/
/{pet}/name
is a subpath of/
but is NOT a direct subpath of/
/{pet}/name
is a direct subpath of/{pet}
/
and/{pet}
are parent paths of/{pet}/name
/{pet}
is the direct parent path of/{pet}/name
Third (and last) it might be possible to rephrase this:
Into:
I don’t think your case [2] is allowed – “The value for these path parameters MUST NOT contain any unescaped “generic syntax” characters described by [RFC3986]: forward slashes (/), question marks (?), or hashes (#).” in https://spec.openapis.org/oas/v3.1.0#path-templating. But perhaps the authors meant to say “the names for these path parameters”? Value (as in, populated from the actual request URI) sounds more like it, because
#
and?
should be excluded because they are markers for fragments and query parameters, respectively.If “value” is correct here, this is convenient for writing a path-matching algorithm, for one can split the list of possible path specifications by
/
and also split the incoming URI path by/
to give individual sections to match against – and if they are sections that do not contain a template ({..}
) then matching is straightforward, and lets us drill down to a small number of possible path items to match templated sections against.(Although personally I’ve found that replacing each templated
{...}
with named captures, for inserting into a single regular expression, works well enough - e.g./foo/{bar}-{baz}/{bloop}
becomes^/foo/(?<bar>[^/]+)-(?<baz>[^/]+)/(?<bloop>[^/]+)$
and the matched values show up in variablesbar
,baz
andbloop
(if a match was found).