sanic-org / sanic-ext

Extended Sanic functionality
https://sanic.dev/en/plugins/sanic-ext/getting-started.html
MIT License
50 stars 36 forks source link

[Bug] OpenAPI using Schema constructor in blueprints gives error #199

Open m-aliansari opened 1 year ago

m-aliansari commented 1 year ago

Description I want to show the minimum value of a query parameter in the docs, so I am using Schema constructor with @openapi.parameter decorator. It works great when using in app route directly. However, it starts giving error when I use the same method in blueprints. I am attaching sample code and screenshots below.

What's working here is the sample code that works correct

from sanic import Request, Sanic
from sanic_ext import Config, openapi
from sanic_ext.extensions.openapi.types import Schema

app = Sanic(name="sample")
app.extend(
    config=Config(
        swagger_ui_configuration={
            "showCommonExtensions": True,
            "apisSorter": "alpha", 
            "operationsSorter": "alpha"
        }
    )
)

@app.get("/")
@openapi.parameter(name='other', schema=Schema(type="int", minimum=1))
async def hello(request: Request):
    return "hello world"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

Notice the Schema constructor being used. It gives the docs also as expected. image

What does not work (Steps to reproduce) Here is the sample code that doesn't work. It involves two files.

# example_blueprint.py
from sanic import Blueprint, Request, Sanic
from sanic_ext import openapi
from sanic_ext.extensions.openapi.types import Schema

app = Sanic.get_app()

example_blueprint = Blueprint("example_blueprint", "/example")

@example_blueprint.get("/")
@openapi.parameter(name="page", schema=Schema(type=int, minimum=1))
async def movie(request: Request):
    return "some"
# server.py
from sanic import Request, Sanic
from sanic_ext import Config, openapi
from sanic_ext.extensions.openapi.types import Schema

app = Sanic(name="sample")
app.extend(
    config=Config(
        swagger_ui_configuration={
            "showCommonExtensions": True,
            "apisSorter": "alpha", 
            "operationsSorter": "alpha"
        }
    )
)

from example_blueprint import example_blueprint
app.blueprint(blueprint=example_blueprint)

@app.get("/")
@openapi.parameter(name='other', schema=Schema(type="int", minimum=1))
async def hello(request: Request):
    return "hello world"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

This code initializes perfect but when I navigate to /docs it gives the following error in console:

[12240] [ERROR] Exception occurred while handling uri: 'http://localhost:8000/docs/openapi.json'
Traceback (most recent call last):
  File "E:\workplace\sanic-openapi-problem\venv\Lib\site-packages\sanic\app.py", line 974, in handle_request
    response = await response
               ^^^^^^^^^^^^^^
  File "E:\workplace\sanic-openapi-problem\venv\Lib\site-packages\sanic_ext\extensions\openapi\blueprint.py", line 109, in spec
    return json(SpecificationBuilder().build(request.app).serialize())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "E:\workplace\sanic-openapi-problem\venv\Lib\site-packages\sanic\response\convenience.py", line 50, in json
    return JSONResponse(
           ^^^^^^^^^^^^^
  File "E:\workplace\sanic-openapi-problem\venv\Lib\site-packages\sanic\response\types.py", line 361, in __init__
    self._encode_body(self._use_dumps(body, **self._use_dumps_kwargs)),
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Ansari\AppData\Local\Programs\Python\Python311\Lib\json\__init__.py", line 238, in dumps
    **kw).encode(obj)
          ^^^^^^^^^^^
  File "C:\Users\Ansari\AppData\Local\Programs\Python\Python311\Lib\json\encoder.py", line 200, in encode
    chunks = self.iterencode(o, _one_shot=True)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Ansari\AppData\Local\Programs\Python\Python311\Lib\json\encoder.py", line 258, in iterencode
    return _iterencode(o, 0)
           ^^^^^^^^^^^^^^^^^
  File "C:\Users\Ansari\AppData\Local\Programs\Python\Python311\Lib\json\encoder.py", line 180, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type type is not JSON serializable

And on the web it gives this error. image

Environment:

Additional context It works fine when I use docstrings as documentation, but I can't use docstrings because some of my query params are complex and will require a lot of writing everytime something changes. So, I want to make it work with @openapi.parameter decorator.