Wrong api operation returned by ApiOperationResolver#findApiOperation in /{id} vs /

Issue #252 resolved
phil mora created an issue

I have 2 api operations:
/{id} - get a single foo
/ - get all the foos

The problem is that when the http request is / (get all the foos), I get an error saying 'id' is required but is missing.

It appears that ApiOperationResolver#findApiOperation returns the wrong api operation.
In the findApiOperation method, the matchingPaths list contains both ApiPath objects. The ApiOperationResolver::specificityScore method causes the "/{id} - get a single foo" to be returned (as its more specific).

=====possible solutions=====
Looking at ApiPathImpl#partMatches, the replacement regex "\\E(.*?)\\Q" is questionable, maybe it should be "\\E(.+)\\Q" ?

Alternatively, it would be good to be able to pass in a user defined function overriding ApiOperationResolver::specificityScore.

Or maybe a pass in a user defined predicate(ApiPath, NormalisedPath) -> Boolean that could be used as an additional filter.

=====error message=======

[com.atlassian.oai.validator.springmvc.InvalidRequestException: {
  "messages" : [ {
    "key" : "validation.request.parameter.missing",
    "level" : "ERROR",
    "message" : "Parameter 'id' is required but is missing.",
    "context" : {
      "requestPath" : "/v1/foos",
      "parameter" : {
        "name" : "id",
        "in" : "path",
        "description" : "identifier of the foo",
        "required" : true,
        "style" : "SIMPLE",
        "explode" : false,
        "schema" : {
          "type" : "string",
          "example" : "abc123"
        }
      },
      "location" : "REQUEST",
      "requestMethod" : "GET"
    }
  } ]
}]

====yaml sample=====

paths:
  '/{id}':
    get:
      description: get a single foo
      parameters:
        - $ref: '#/components/parameters/fooId'
      responses:
        '200':
          description: A single foo
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/singleFoo'
  /:
    get:
      description: get all the foos
      responses:
        '200':
          description: All foos
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/allFoos'

components:
  parameters:
    fooId:
      name: id
      in: path
      description: identifier of the foo
      required: true
      schema:
        type: string
        example: abc123

Comments (4)

  1. James Navin

    I reproduced the problem. It is caused by the two paths being scored the same, but then the first-defined path is being returned as the tie-breaker (e.g. if you swap the order of your paths in your spec it will work as expected).

    I have improved the path matching to look for exact matches first before applying the scoring. This should address the problem.

  2. Log in to comment