Skip to content

PathNotFound error when trying to validate request with query parameter #242

Closed
@stojan-jovic

Description

@stojan-jovic

Found very strange bug, which is pretty critical for our work process, as it fully blocking endpoint validation (have no workaround for now).

I'm working with Falcon middleware at low level, but issue can be easy reproduced with even simpler example. I will provide most minimal working example that can be used for reproducing issue.

Falcon app (everything in single module, ugly, but only for testing purposes):

import logging
import json
import falcon
from wsgiref import simple_server

from openapi_core import create_spec
from openapi_spec_validator.schemas import read_yaml_file
from openapi_core.contrib.falcon.middlewares import FalconOpenAPIMiddleware

logging.basicConfig()
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


class Resource(object):

    def on_get(self, req, resp, path_param=None):
        req_data = {}

        if path_param is not None:
            req_data['path'] = path_param

        query_param = req.get_param('validate')
        if query_param is not None:
            req_data['query'] = query_param

        resp.body = json.dumps(req_data)
        resp.status = falcon.HTTP_200


if __name__ == '__main__':
    spec_dict = read_yaml_file('swagger.yml')
    spec = create_spec(spec_dict)
    openapi_middleware = FalconOpenAPIMiddleware.from_spec(spec)

    # falcon_app = falcon.API()
    falcon_app = falcon.API(middleware=[openapi_middleware])

    test_resource = Resource()
    falcon_app.add_route('/v1/test', test_resource)
    falcon_app.add_route('/v1/test/{path_param}', test_resource)

    httpd = simple_server.make_server('127.0.0.1', 8000, falcon_app)
    logger.info('Now serving on port 8000')
    httpd.serve_forever()

Swagger spec file content (swagger.yml):

openapi: 3.0.0

info:
  version: 1.0.0
  title: Test PathNotFound
  description: Test PathNotFound
  contact:
    name: Test
    url: http://www.test.com
    email: [email protected]
  license:
    name: Test
    url: https://www.test.com/terms-of-use/

servers:
  - url: http://localhost:8000
  - url: /

tags:
  - name: Test
    description: Test

paths:
  /v1/test:
    get:
      tags:
        - Test
      summary: Test
      description: Test
      parameters:
        - name: validate
          in: query
          description: Test query parameter
          schema:
            type: string
      responses:
        200:
          description: Successful
        400:
          description: BadRequest error
        default:
          description: Unexpected error
  /v1/test/{path_param}:
    get:
      tags:
        - Test
      summary: Test
      description: Test
      parameters:
        - name: path_param
          in: path
          required: true
          description: Test path parameter
          schema:
            type: string
        - name: validate
          in: query
          description: Test query parameter
          schema:
            type: string
      responses:
        200:
          description: Successful
        400:
          description: BadRequest error
        default:
          description: Unexpected error

When I try to make simple GET request:

curl http://localhost:8000/v1/test?validate=query_param

Getting following error:

{
  "errors": [
    {
      "title": "Path not found for http://localhost:8000/v1/test?validate=query_param",
      "status": 404,
      "class": "<class 'openapi_core.templating.paths.exceptions.PathNotFound'>"
    }
  ]
}

Strange thing is that if I have some path parameter in request, query parameter being properly validated, for example GET request:

curl http://localhost:8000/v1/test/path_param?validate=query_param

Request passing and returning result:

{
  "path": "path_param",
  "query": "query_param"
}

If we send the same requests without query parameters, everything working fine:

curl http://localhost:8000/v1/test
curl http://localhost:8000/v1/test/path_param

Here there is stack trace for the same error (from my app, generated by my low-level middleware logic:):

Traceback (most recent call last):
  File "falcon_svc.py", line 395, in process_resource
    result.raise_for_errors()
  File "D:\Work\workspace2\venvs\.sim_venv\lib\site-packages\openapi_core\validation\datatypes.py", line 11, in raise_for_errors
    raise error
  File "D:\Work\workspace2\venvs\.sim_venv\lib\site-packages\openapi_core\validation\request\validators.py", line 29, in validate
    path, operation, _, path_result, _ = self._find_path(request)
  File "D:\Work\workspace2\venvs\.sim_venv\lib\site-packages\openapi_core\validation\validators.py", line 19, in _find_path
    return finder.find(request)
  File "D:\Work\workspace2\venvs\.sim_venv\lib\site-packages\openapi_core\templating\paths\finders.py", line 23, in find
    raise PathNotFound(request.full_url_pattern)
openapi_core.templating.paths.exceptions.PathNotFound: Path not found for http://localhost:8000/v1/test?validate=query_param

I did some very quick debugging and found pretty strange behavior of PathFinder's find method (where error is raised), for example, request that has path parameter and being properly validated, looks like follows when parsed:

TemplateResult(pattern='/v1/test/{path_param}', variables={'path_param': 'path_param?validate=query_param'})

Which does not looks to me as expected behavior and leads me to conclusion that it being validated with lucky circumstances.

My environment:

Package                  Version                      
------------------------ -----------------------------
falcon                   1.4.1
openapi-core             0.13.3

Not checked is this behavior the same with some other framework (Flask, Django), but I would say that this issue probably is not dependent on used framework. However, on the other side, it's strange that nobody found it till now?! Or I'm doing something wrong?

If there is no plans to debug this and provide fix, I would be happy to help with one PR with fix, if you can confirm that this is really bug and give me short directions where to look first!?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions