Decorators

The primary mechanism for adding content to your schema is by decorating your endpoints. If you have used sanic-openapi in the past, this should be familiar to you. The decorators and their arguments match closely the OAS v3.0 specification.

All of the examples show will wrap around a route definition. When you are creating these, you should make sure that your Sanic route decorator (@app.route, @app.get, etc) is the outermost decorator. That is to say that you should put that first and then one or more of the below decorators after.

from sanic_ext import openapi

@app.get("/path/to/<something>")
@openapi.summary("This is a summary")
@openapi.description("This is a description")
async def handler(request, something: str):
    ...

You will also see a lot of the below examples reference a model object. For the sake of simplicity, the examples will use UserProfile that will look like this. The point is that it can be any well-typed class. You could easily imagine this being a dataclass or some other kind of model object.

class UserProfile:
    name: str
    age: int
    email: str

Definition decorator#

@openapi.definition#

The @openapi.definition decorator allows you to define all parts of an operations on a path at once. It is an omnibums decorator in that it has the same capabilities to create operation definitions as the rest of the decorators. Using multiple field-specific decorators or a single decorator is a style choice for you the developer.

The fields are purposely permissive in accepting multiple types to make it easiest for you to define your operation.

Arguments

Field Type
body **dict, RequestBody, *YourModel***
deprecated bool
description str
document str, ExternalDocumentation
exclude bool
operation str
parameter str, dict, Parameter, [str], [dict], [Parameter]
response dict, Response, YourModel, [dict], [Response]
summary str
tag str, Tag, [str], [Tag]
secured Dict[str, Any]

Examples

@openapi.definition(
    body=RequestBody(UserProfile, required=True),
    summary="User profile update",
    tag="one",
    response=[Success, Response(Failure, status=400)],
)

See below examples for more examples. Any of the values for the below decorators can be used in the corresponding keyword argument.

Field-specific decorators#

All the following decorators are based on @openapi

body#

Arguments

Field Type
content ***YourModel*, dict, RequestBody**

Examples

@openapi.body(UserProfile)
@openapi.body({"application/json": UserProfile})
@openapi.body(RequestBody({"application/json": UserProfile}))
@openapi.body({"content": UserProfile})
@openapi.body(RequestBody(UserProfile))
@openapi.body({"application/json": {"description": ...}})

deprecated#

Arguments

None

Examples

@openapi.deprecated()
@openapi.deprecated

description#

Arguments

Field Type
text str

Examples

@openapi.description(
    """This is a **description**.

## You can use `markdown`

- And
- make
- lists.
"""
)

document#

Arguments

Field Type
url str
description str

Examples

@openapi.document("http://example.com/docs")
@openapi.document(ExternalDocumentation("http://example.com/more"))

exclude#

Can be used on route definitions like all of the other decorators, or can be called on a Blueprint

Arguments

Field Type Default
flag bool True
bp Blueprint

Examples

@openapi.exclude()
openapi.exclude(bp=some_blueprint)

operation#

Sets the operation ID.

Arguments

Field Type
name str

Examples

@openapi.operation("doNothing")

Arguments

Field Type Default
name str
schema type str
location "query", "header", "path" or "cookie" "query"

Examples

@openapi.parameter("thing")
@openapi.parameter(parameter=Parameter("foobar", deprecated=True))
@openapi.parameter("Authorization", str, "header")
@openapi.parameter("thing", required=True, allowEmptyValue=False)

response#

Arguments

If using a Response object, you should not pass any other arguments.

Field Type
status int
content ***type, *YourModel, dict**
description str
response Response

Examples

@openapi.response(200, str, "This is endpoint returns a string")
@openapi.response(200, {"text/plain": str}, "...")
@openapi.response(response=Response(UserProfile, description="..."))
@openapi.response(
    response=Response(
        {
            "application/json": UserProfile,
        },
        description="...",
        status=201,
    )
)
@openapi.response(200, UserProfile, "...")
@openapi.response(
    200,
    {
        "application/json": UserProfile,
    },
    "Description...",
)

summary#

Arguments

Field Type
text str

Examples

@openapi.summary("This is an endpoint")

tag#

Arguments

Field Type
*args str, Tag

Examples

@openapi.tag("foo")
@openapi.tag("foo", Tag("bar"))

secured#

Arguments

Field Type
*args, **kwargs str, Dict[str, Any]

Examples

@openapi.secured()
@openapi.secured("foo")
@openapi.secured("token1", "token2")
@openapi.secured({"my_api_key": []})
@openapi.secured(my_api_key=[])

Do not forget to use add_security_scheme. See security for more details. ``

Integration with Pydantic#

Pydantic models have the ability to generate OpenAPI schema.

To take advantage of Pydantic model schema generation, pass the output in place of the schema.

from sanic import Sanic, json
from sanic_ext import validate, openapi
from pydantic import BaseModel, Field

@openapi.component
class Item(BaseModel):
    name: str
    description: str = None
    price: float
    tax: float = None

class ItemList(BaseModel):
    items: List[Item]

app = Sanic("test")

@app.get("/")
@openapi.definition(
    body={
        "application/json": ItemList.schema(
            ref_template="#/components/schemas/{model}"
        )
    },
)
async def get(request):
    return json({})

Note

It is important to set that ref_template. By default Pydantic will select a template that is not standard OAS. This will cause the schema to not be found when generating the final document.

Added in v22.9