question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Are these OpenAPI 3 paths ambiguous?

See original GitHub issue

As 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:

  1. Neither path is concrete (term used in the spec)
  2. 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")
  3. 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:open
  • Created 2 years ago
  • Reactions:1
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
bfreudencommented, Nov 16, 2021

@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:

Templated paths with the same hierarchy but different templated names MUST NOT exist as they are identical. https://spec.openapis.org/oas/v3.0.3#paths-object

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:

function identicalPaths(oapth1, oapath2) {
  const pathParamRegex = /\{[^}]+\}/ 
  return oapth1.replaceAll(pathParamRegex, "{}") == oapth2.replaceAll(pathParamRegex, "{}")
}

A definition could be:

Paths are considered identical if they are lexicographically equal after removing their curly braces delimited template expressions (or after replacing them with a constant).

An example could be:

Those paths are identical:

/{pet}/name
/{owner}/name

Because replacing their delimited template expressions with the {} constant leads to the same string: /{}/name

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:

These are paths:

/
/{pet}
/{pet}/name
/faq

They are containing these path segments: {pet}, name, faq

A definition of parent path could be (inspired from https://en.wiktionary.org/wiki/subpath):

A subpath is a path relative to another path, called a parent path, defined by adding one or more segments at the end of that path. A direct subpath is a subpath defined by adding a single path segment at the end of a path, called the direct parent path.

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:

When matching URLs, concrete (non-templated) paths would be matched before their templated counterparts.

Into:

When matching URLs, if two paths have identical direct parent paths then the most concrete (least-templated) path would be matched before the other.

0reactions
karenetheridgecommented, Nov 21, 2021

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 variables bar, baz and bloop (if a match was found).

Read more comments on GitHub >

github_iconTop Results From Across the Web

Are those OpenAPI 3 paths ambiguous? - Stack Overflow
My reading of the spec is that they are not ambiguous, because one is more concrete than the other. The more concrete one...
Read more >
no-ambiguous-paths - Redocly
API design principles​​ Ambiguity can creep in when a single path can satisfy two different path items. Such paths are considered ambiguous and...
Read more >
OpenAPI Specification - Version 3.0.3 - Swagger
OpenAPI Specification. Version 3.0.3. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", ...
Read more >
vacuum OpenAPI Linter: no-ambiguous-paths - quobix
Every path in an OpenAPI specification, should be unambiguous and clearly resolvable. What this essentially means is that each path should be able...
Read more >
Swagger Error Ambiguous HTTP method for action and Failed ...
Actions require an explicit HttpMethod binding for Swagger/OpenAPI 3.0: Let's look at what happened. Our original Swagger for this app service ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found