# API Documentation

Generate OpenAPI 3.2 contracts and expose a deliberately protected Swagger UI.

Source: https://flasgo.dev/reference/api-documentation/

Flasgo generates OpenAPI 3.2.0 with an explicit JSON Schema 2020-12 dialect and can serve a built-in Swagger UI. Specification generation is always available; serving the two documentation endpoints is disabled by default.

## Generated contract

The generator uses registered routes and the same compiled endpoint plans used at runtime. It documents:

- Flask-style path converters and typed path parameters, with untyped `<name>` segments documented using the handler's annotated type (or `string` when unannotated);
- `Body()`, `Query()`, `Header()`, `Cookie()`, and `Form()` bindings;
- parameters supplied by `Depends()` providers;
- reusable dataclass request and response schemas;
- request media types and structured `422` validation responses;
- authorization security schemes, required scopes or roles, and `401`/`403` responses;
- applicable framework responses such as `413`, `415`, and `429`;
- route docstrings, return annotations, and root `API_SERVERS` entries.

The documented responses match runtime behavior. A handler annotated `-> None` is documented as `204 No Content` with no response body. `str` and `bytes` return annotations document `text/plain`, the content type Flasgo sends for both. `set[T]` schemas declare `uniqueItems`. The first docstring line becomes the operation summary; the remaining text becomes the description with its paragraph breaks and indentation preserved. Operation IDs contain only `[A-Za-z0-9_]`, with other characters replaced by underscores so client generators accept them.

Standard operations, including OpenAPI 3.2 `QUERY`, use normal Path Item fields. Other valid HTTP methods are emitted through `additionalOperations`.

```python
spec = app.openapi_spec()
assert spec["openapi"] == "3.2.0"
```

See [Request Data and Dependencies](/guides/request-data-and-dependencies/) for the runtime binding model that feeds the contract.

## Response and dependency contracts

The generator also documents inherited blueprint permissions, standalone route/group dependency inputs, and explicit `response_model=` schemas. Underscore-prefixed dataclass fields are excluded from schemas and output. Runtime enforcement requires `response_model=`; a return annotation alone remains descriptive. Tuple response models are rejected at registration because a returned tuple is read as `(body, status)`; use a list or dataclass instead. See [Response Contracts](/guides/response-contracts/).

A return annotation of `StreamingResponse`, `EventSourceResponse`, or `NDJSONResponse` advertises `application/octet-stream`, `text/event-stream`, or `application/x-ndjson`, respectively. An `item_model=` or custom media type chosen inside a handler is runtime configuration and cannot be inferred into the schema. See [Streaming Responses](/guides/streaming-responses/).

The generator unwraps `Annotated[T, ...]` return types before selecting the media type. For example, `Annotated[EventSourceResponse, "progress events"]` still documents `text/event-stream`, and `Annotated[str, "plain text"]` documents `text/plain`. This metadata does not enable runtime response validation.

Dependency overrides are local to execution and do not mutate the published OpenAPI contract.

## Built-in endpoints

When `ENABLE_DOCS=True`, Flasgo reserves two endpoints before normal route matching:

| Endpoint | Default path | Setting |
| --- | --- | --- |
| Swagger UI | `/docs` | `DOCS_PATH` |
| OpenAPI JSON | `/openapi.json` | `OPENAPI_PATH` |

They accept only `GET` and `HEAD`; other methods receive `405 Method Not Allowed`. When docs are disabled, the paths fall through to normal route matching. Both paths are relative to the application's mount point: under an ASGI `root_path` such as `/api`, Swagger UI requests the document from `/api/openapi.json`. The embedded spec URL escapes `<`, `>`, and `&`, so an unusual `OPENAPI_PATH` cannot close the page's inline script.

## Protecting the docs

Use `DOCS_AUTH_BACKEND` to apply an existing authentication backend to both the UI and the JSON document:

```python
import hmac
import os

from flasgo import Flasgo, User, bearer_token_backend

docs_token = os.environ["FLASGO_DOCS_TOKEN"]


def validate_docs_token(token: str) -> User | None:
    if hmac.compare_digest(token, docs_token):
        return User(id="docs", is_authenticated=True)
    return None


app = Flasgo(
    settings={
        "ENABLE_DOCS": True,
        "DOCS_AUTH_BACKEND": "docs",
        "DOCS_PATH": "/api-docs",
        "OPENAPI_PATH": "/api/openapi.json",
        "API_TITLE": "Example API",
        "API_VERSION": "1.0.0",
        "API_DESCRIPTION": "Internal service API.",
        "API_SERVERS": ["https://api.example.com"],
    }
)

app.register_auth_backend(
    "docs",
    bearer_token_backend(validate_docs_token),
)
```

The configured backend must be registered before the application is checked or serves the endpoints. Authentication failures are subject to the normal security-failure limiter.

## Authentication metadata

`bearer_token_backend()` and `jwt_backend()` provide accurate HTTP security metadata automatically. Application-owned backends may declare a local OpenAPI Security Scheme Object at registration:

```python
app.register_auth_backend(
    "deviceOAuth",
    backend,
    openapi_scheme={
        "type": "oauth2",
        "oauth2MetadataUrl": (
            "https://identity.example.com/"
            ".well-known/oauth-authorization-server"
        ),
        "flows": {
            "deviceAuthorization": {
                "deviceAuthorizationUrl": (
                    "https://identity.example.com/device"
                ),
                "tokenUrl": "https://identity.example.com/token",
                "scopes": {"read": "Read account data"},
            }
        },
    },
)
```

Flasgo validates and copies the metadata. OAuth and OpenID URLs must use HTTPS; supported extension keys begin with `x-`; and external `$ref` values are rejected. The metadata documents credentials accepted by your backend, but it does not implement an OAuth authorization server.

## Generate without serving

Print or atomically write a deterministic artifact:

```bash
uv run flasgo openapi app.py
uv run flasgo openapi app.py --output openapi.json
uv run flasgo check app.py
```

`--output` replaces an existing file atomically and keeps its permissions; a new file uses the process umask.

The check catches route conflicts, missing authentication backends, and internal endpoint conflicts without starting a server.

## Swagger UI security

The built-in UI uses an exact version of the Swagger distribution with subresource-integrity hashes. Query-driven configuration and remote validation are disabled. Inline script and style content runs with a rotating per-response CSP nonce rather than `unsafe-inline`.

Even with those controls, expose API metadata deliberately. Prefer a controlled development or staging environment, use `DOCS_AUTH_BACKEND` whenever the endpoints are reachable beyond a trusted local environment, and review generated schemas for information your application should not disclose.

Sources:

- [README.md](https://github.com/L1ghtn1ng/flasgo/blob/main/README.md)
- [flasgo/openapi.py](https://github.com/L1ghtn1ng/flasgo/blob/main/flasgo/openapi.py)
- [flasgo/auth.py](https://github.com/L1ghtn1ng/flasgo/blob/main/flasgo/auth.py)
