OpenAPI#

uapi can generate and serve an OpenAPI schema for your API.

from uapi import App

app = App()

# Register your routes here

# Serve the schema at /openapi.json by default
app.serve_openapi()

# Generate the schema, if you want to access it directly or customize it
spec = app.make_openapi_spec()

Additionally, uapi also supports serving several OpenAPI documentation viewers:

app.serve_swaggerui()
app.serve_redoc()
app.serve_elements()

The documentation viewer will be available at its default URL.

See also

App.serve_swaggerui()

App.serve_redoc()

App.serve_elements()

What is referred to as routes in uapi, OpenAPI refers to as operations. This document uses the uapi nomenclature by default.

uapi comes with OpenAPI schema support for the following types:

  • strings

  • integers

  • booleans

  • floats (type: number, format: double)

  • bytes (type: string, format: binary)

  • dates (type: string, format: date)

  • datetimes (type: string, format: date-time)

  • lists (type: array)

  • dictionaries (type: object, with additionalProperties)

  • attrs classes (type: object)

  • typing.Any (empty schema)

Operation Summaries and Descriptions#

OpenAPI allows operations to have summaries and descriptions; summaries are usually used as operation labels in OpenAPI tooling.

By default, uapi generates summaries from route names. This can be customized by using your own summary transformer, which is a function taking the actual handler function or coroutine and the route name, and returning the summary string.

app = App()

def summary_transformer(handler: Callable, name: str) -> str:
    """Use the name of the handler function as the summary."""
    return handler.__name__

app.serve_openapi(summary_transformer=summary_transformer)

Operation descriptions are generated from handler docstrings by default. This can again be customized by supplying your own description transformer, with the same signature as the summary transformer.

app = App()

def desc_transformer(handler: Callable, name: str) -> str:
    """Use the first line of the docstring as the description."""
    doc = getattr(handler, "__doc__", None)
    if doc is not None:
        return doc.split("\n")[0]
    return None

app.serve_openapi(description_transformer=desc_transformer)

OpenAPI allows Markdown to be used for descriptions.

Endpoint Tags#

OpenAPI supports grouping endpoints by tags. You can specify tags for each route when registering it:

@app.get("/{article_id}", tags=["articles"])
async def get_article(article_id: str) -> str:
    return "Getting the article"

Depending on the OpenAPI visualization framework used, operations with tags are usually displayed grouped under the tag.