openapi-core icon indicating copy to clipboard operation
openapi-core copied to clipboard

Falcon request factory not working

Open stojan-jovic opened this issue 3 years ago • 4 comments

With the latest openapi-core version (i.e. 0.14.2) Falcon request factory (i.e. FalconOpenAPIRequestFactory) not working at all. It's the same behavior with embedded middleware and custom one.

Code for reproducing:

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.validation.request.validators import RequestValidator
from openapi_core.contrib.falcon import FalconOpenAPIRequestFactory
# from openapi_core.contrib.falcon.middlewares import FalconOpenAPIMiddleware

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


class Resource:
    def on_get(self, req, resp):
        logger.info('Calling GET...')
        resp.body = json.dumps({'foo': 'bar'})
        resp.status = falcon.HTTP_200


class OpenAPI3Middleware:
    def __init__(self, spec_dict):
        try:
            self.spec = create_spec(spec_dict)
            self.spec.security = []
        except Exception:
            logger.exception('Failed to create OpenAPI 3 spec from input dict.')
            raise

    def process_resource(self, req, resp, resource, params):
        logger.info('Processing request...')
        openapi_request = FalconOpenAPIRequestFactory().create(req)
        logger.info('Validating request...')
        validator = RequestValidator(self.spec)
        result = validator.validate(openapi_request)

        result.raise_for_errors()


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

    falcon_app = falcon.App(middleware=[openapi_middleware])

    test_resource = Resource()
    falcon_app.add_route('/v1/test', 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 for above example:

openapi: 3.0.1

info:
  version: 1.0.0
  title: Test
  description: Test description.

servers:
  - url: http://localhost:8000
    description: Local server instance

tags:
  - name: Test
    description: Test description.

paths:
  /v1/test:
    get:
      tags:
        - Test
      summary: Test resource
      description: Test resource
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/job_response'


components:
  securitySchemes:
    jwt_token:
      type: http
      scheme: bearer

  schemas:
    job_response:
      type: object

security:
  - jwt_token: []

GET to http://localhost:8000/v1/test gives error:

{
    "title": "415 Unsupported Media Type",
    "description": "text/plain is an unsupported media type."
}

Maybe I'm missing something here!? This is pretty critical issue for me, I'm not able to upgrade openapi-core to the latest version, which brings pretty much other bugfixes. :(

Falcon version is the latest one, i.e. 3.0.1. Btw, from which openapi-core version is dropped off support for Falcon <3.0.0? Not sure what is reason for this?!

stojan-jovic avatar Jun 26 '21 14:06 stojan-jovic

This behavior is reproducing from version 0.13.4, i.e. last working version is 0.13.3.

stojan-jovic avatar Jun 26 '21 22:06 stojan-jovic

Does it work for master branch?

Falcon <3.0 was dropped on master.

p1c2u avatar Jun 30 '21 08:06 p1c2u

@p1c2u Will check as soon as I get chance and respond here. Thanks!

stojan-jovic avatar Jun 30 '21 09:06 stojan-jovic

@p1c2u @stojan-jovic This is still happening on 0.14.2 with Falcon 3.0.1. Furthermore, if I try with:

curl --request GET \
  --url http://localhost:8000/v1/test \
  --header 'content-type: application/json'

I get the following:

2022-01-18 14:07:23 [FALCON] [ERROR] GET /v1/test => Traceback (most recent call last):
  File "/Users/alex/dev/recipe-book/backend/api/venv/lib/python3.10/site-packages/falcon/app.py", line 323, in __call__
    process_request(req, resp)
  File "/Users/alex/dev/recipe-book/backend/api/venv/lib/python3.10/site-packages/openapi_core/contrib/falcon/middlewares.py", line 29, in process_request
    req_result = super(FalconOpenAPIMiddleware, self).process_request(
  File "/Users/alex/dev/recipe-book/backend/api/venv/lib/python3.10/site-packages/openapi_core/validation/processors.py", line 11, in process_request
    return self.request_validator.validate(request)
  File "/Users/alex/dev/recipe-book/backend/api/venv/lib/python3.10/site-packages/openapi_core/validation/request/validators.py", line 30, in validate
    path, operation, _, path_result, _ = self._find_path(request)
  File "/Users/alex/dev/recipe-book/backend/api/venv/lib/python3.10/site-packages/openapi_core/validation/validators.py", line 24, in _find_path
    return finder.find(request)
  File "/Users/alex/dev/recipe-book/backend/api/venv/lib/python3.10/site-packages/openapi_core/templating/paths/finders.py", line 25, in find
    if not paths_iter_peek:
  File "/Users/alex/dev/recipe-book/backend/api/venv/lib/python3.10/site-packages/more_itertools/more.py", line 316, in __bool__
    self.peek()
  File "/Users/alex/dev/recipe-book/backend/api/venv/lib/python3.10/site-packages/more_itertools/more.py", line 330, in peek
    self._cache.append(next(self._it))
  File "/Users/alex/dev/recipe-book/backend/api/venv/lib/python3.10/site-packages/openapi_core/templating/paths/finders.py", line 45, in _get_paths_iter
    paths = self.spec / 'paths'
TypeError: unsupported operand type(s) for /: 'dict' and 'str'

Interestingly, I have a large app I am working on where it's working fine (I was trying to repo a different issue), but there's too much code to provide a snippet as it is. I'll try to figure out what's different between them.

alexferl avatar Jan 18 '22 19:01 alexferl