karenetheridge / OpenAPI-Modern

Validate HTTP requests and responses against an OpenAPI v3.1 document
https://metacpan.org/release/OpenAPI-Modern/
Other
6 stars 3 forks source link

request URI matching: include server object's url field #11

Open karenetheridge opened 2 years ago

karenetheridge commented 2 years ago

Path specifications (patterns under /paths) need to have the server object's url field prepended before matching against the real request URI.

karenetheridge commented 2 years ago

irrelevant until #7 is done.

karenetheridge commented 2 years ago

url is also templated, with server variables, so the incoming request URI must be matched against all combinations of server variables in the url before continuing on to attempt to match against path-specs under /paths.

save the results of all the template-variable-replaced server URIs on the document object for future reuse.

karenetheridge commented 2 years ago

remember, if the server url is relative, it must be resolved against the document's URI.

karenetheridge commented 2 years ago

effective_base_uri should also take servers into account when looking at the Host header - see #30.

karenetheridge commented 6 months ago

coming back to this, following a nudge by @corion...

  1. don't die when 'servers' is present. document that path prefixes in 'uri' are not used for path item matching yet (this is technically a spec violation, but at least it gets us farther than not allowing 'servers' at all, and caveat emptor!).
  2. at document load time, do some validation:
    • in server variables, validate that the 'default' value exists in the 'enum' list
    • validate that all the server variables exist as template variables in the uri (actually this req doesnt exist yet - get this added to https://spec.openapis.org/oas/v3.1.0#fixed-fields-3 for spec release 3.2)
    • disallow "identical and invalid" server urls that would conflict, e.g. "https://example.com/{version}" and "https://example.com/{v}". Also compare operation urls to path-item and root urls, and path-item urls to root urls. [also, the spec should be revised to explicitly mention this limitation.]
  3. proper matching in find_path: match the incoming request uri's scheme, host and path against servers entries at the root, path-item level and operation level. avoid anchoring: partial matches seem to be ok with the spec.
  4. extract server variable values and return them in the $options hash. (make sure to test suplicate names with respect to path templates - this should be valid)
  5. ensure that effective_schema_uri is updated with the path prefix being used by the matching servers entry. This effectively means we keep a copy of the string created by applying template variables to $servers->{uri} (and it might be useful for other things too?)
karenetheridge commented 6 months ago

Question, as the spec is ambiguous: do we use the specified enums in server variables as part of the matching process (if the values don't match, we keep iterating through path-items to look for a later match), or do we consider this a match and then a request validation failure? It feels like the intent was the former, but I lean towards the latter being more literally correct vs the spec because there is no provision elsewhere in the document for multiple path-item entries matching save mismatched server variables.

example:

openapi document looks like:

paths:
  /foo/bar:
    get:
      servers:
      - url: https://{environment}.example.com/v1
        variables:
          environment:
            default: prod
            enum: [staging, prod]
  /foo/{fooId}:
    get:
      servers:
      - url: https://test.example.com/v1

Incoming request is https://test.example.com/v1/foo/bar.

The first path-item that matches is /foo/bar (we always consider exact matches ahead of templated ones). However, the server url does not match ("environment" variable cannot be "test", as per the enum). Do we fail to find a matching path-item, or do we fall through to considering /foo/{fooId}?

karenetheridge commented 6 months ago

see also https://learn.openapis.org/specification/servers.html for a bit more colour

Corion commented 6 months ago

I have rough code implementing parsing at https://github.com/Corion/URI-Template-Extract/blob/master/lib/URI/Template/Extract.pm - I might release that to CPAN soonish.

karenetheridge commented 6 months ago

@Corion These aren't URI Templates though -- that's an actual thing with its own RFC.

Corion commented 6 months ago

Oh ? From https://spec.openapis.org/oas/v3.1.0#server-object , and the phrase Variable substitutions will be made when a variable is named in {brackets} I assumed that the url field would contain an URI template... Can you tell me where the differences live?

But as I see that you already have logic and code to extract the values, I guess the point is moot :)

karenetheridge commented 6 months ago

URI Templates are https://www.rfc-editor.org/rfc/rfc6570.html -- whereas the {varname} syntax being used here for servers (and for /paths/* entries) are just bracketed placeholders.

It's a bit confusing because real URI Templates are used elsewhere in the specification, in parameter serialization (https://spec.openapis.org/oas/v3.1.0#style-values).

Corion commented 6 months ago

Ugh - thanks for that clarification. I had assumed that the serversentries would have been URI Templates and not mere placeholders.

karenetheridge commented 3 months ago

This also depends on #74 (currently in progress).

karenetheridge commented 2 months ago

keep an eye on https://github.com/OAI/OpenAPI-Specification/issues/3256 also