Skip to main content

Azure Functions OpenAPI

Part of the Azure Functions Python DX Toolkit — dogfood-tested by azure-functions-cookbook-python.

PyPI Downloads Python Version CI Release Security Scans codecov pre-commit Docs License: MIT

Read this in: 한국어 | 日本語 | 简体中文

OpenAPI (Swagger) documentation and Swagger UI for the Azure Functions Python v2 programming model.

Python 3.10 is deprecated. Support ends in the next minor release — Python 3.10 reaches end of life in October 2026. Importing the package on Python 3.10 emits a FutureWarning; upgrade to Python 3.11 or newer.

Why this exists

Azure Functions Python v2 has no built-in API documentation story:

  • No auto-generated docs — you maintain OpenAPI specs by hand or not at all
  • No Swagger UI — no browser-based API explorer for testing endpoints
  • Hard to test — consumers rely on tribal knowledge or external tools to discover your API
  • Spec drift — hand-written docs diverge from actual handler behavior over time

Before / After

❌ Without azure-functions-openapi — maintain specs by hand

# openapi_spec.json — manually written, manually updated
{
    "paths": {
        "/api/users": {
            "post": {
                "summary": "Create user",
                "requestBody": { "...": "..." },
                "responses": { "200": { "...": "..." } }
            }
        }
    }
}

# function_app.py — no connection to the spec above
@app.route(route="users", methods=["POST"])
def create_user(req):
    ...

Spec drifts. Consumers guess. No Swagger UI.

✅ With azure-functions-openapi — spec lives next to the handler

from pydantic import BaseModel


class CreateUserRequest(BaseModel):
    name: str


class UserResponse(BaseModel):
    id: str
    name: str


@openapi(
    summary="Create user",
    requests=CreateUserRequest,
    responses=UserResponse,
)
@app.route(route="users", methods=["POST"])
def create_user(req):
    ...

# Auto-generated endpoints:
# GET /api/openapi.json  — always in sync
# GET /api/docs          — Swagger UI included

Spec matches code. Always. Swagger UI out of the box.

What it does

  • @openapi decorator — attach operation metadata directly to your handler
  • Auto-generated spec — /openapi.json and /openapi.yaml endpoints from decorated handlers
  • Swagger UI — built-in /docs endpoint with security defaults
  • CLI tooling — generate specs at build time for CI validation
  • Schema support — query, path, header, body, and response schemas
  • Metadata inference — infer the 200 response from a handler's return type (on by default, opt out with infer_return_types=False), and opt into summary/description inference from its docstring with infer_docstring=True; both are gap-fill-only and explicit-always-wins (see Usage Guide)
  • auth_level security inference — opt-in infer_auth_level=True derives OpenAPI security from a route's Azure Functions auth_level (see Usage Guide)

How it fits together

flowchart LR
    DEC["@openapi decorator"] --> REG["_openapi_registry"]
    REG --> GEN["spec.generate_openapi_spec()"]
    GEN --> EP["GET /api/openapi.json | .yaml"]
    UI["render_swagger_ui()<br/>GET /api/docs"] -.->|browser fetches spec| EP

FastAPI comparison

Feature FastAPI azure-functions-openapi
API docs generation Built-in from type hints @openapi decorator on handlers
Swagger UI /docs auto-served render_swagger_ui() endpoint
OpenAPI spec Auto-generated /openapi.json get_openapi_json() endpoint
CLI spec export N/A azure-functions-openapi generate
Pydantic integration Native requests= / responses=

Scope

  • Azure Functions Python v2 programming model
  • Decorator-based func.FunctionApp() applications
  • HTTP-triggered functions documented with @openapi
  • Pydantic schema generation (requires Pydantic v2)

This package does not support the legacy function.json-based v1 programming model.

What this package does not do

This package does not own:

CLI Quick Start

Generate an OpenAPI spec from your decorated function app:

# Install
pip install azure-functions-openapi

# Generate spec from a function app module (registers @openapi routes)
azure-functions-openapi generate --app function_app --title "My API" --format json

# Write to file with pretty-printing
azure-functions-openapi generate --app function_app --title "My API" --pretty --output openapi.json

# YAML output
azure-functions-openapi generate --app function_app --format yaml --output openapi.yaml

Pass module:variable to resolve the FunctionApp instance and also discover endpoint-metadata routes — those registered by producers like @validate_http or azure-functions-langgraph — merging them with your @openapi routes into a single spec. With module alone the CLI imports the module (firing @openapi decorators) but does not scan for endpoint metadata:

azure-functions-openapi generate --app function_app:app --title "My API"

See the CLI Guide for all options and CI integration examples.

Installation

pip install azure-functions-openapi

Your Function App dependencies should include:

azure-functions
azure-functions-openapi

SDK Compatibility

This package discovers routes, methods, and handlers from the azure-functions SDK through a single isolated adapter (azure_functions_openapi.adapters). Discovery is public-API-first: it enumerates via the public, idempotent FunctionBuilder.build() and reads everything else through public Function accessors (get_function_name / get_user_function / get_bindings / is_http_function). The adapter never calls the non-idempotent FunctionApp.get_functions(). The one unavoidable private token — app._function_builders, which has no public substitute for enumeration — lives exclusively in the adapter and is covered by a mandatory guard test. We validate the package against an explicit matrix in CI. See issue #258 and issue #327 for background.

azure-functions Python 3.10 Python 3.11 Python 3.12 Python 3.13 Python 3.14
1.21.0 (floor) ✅ tested
1.24.0 ✅ tested
latest 1.x ✅ tested ✅ tested ✅ tested
2.x (>=2,<3) ✅ tested ✅ tested

The version pin in pyproject.toml is interpreter-aware: azure-functions>=1.21.0,<2.0.0 on Python < 3.13, and azure-functions>=1.21.0,<3.0.0 on Python 3.13+. The <3.0.0 ceiling keeps an uncertified azure-functions 3.x out. The floor is 1.21.0 because earlier releases return None from FunctionBuilder.__call__ (breaking direct invocation of decorated handlers in tests and CLI extraction). The split exists because azure-functions 2.x drops support for Python < 3.13, so the 2.x line is only installable — and only offered — on Python 3.13+. The 2.x path is proven by a dedicated wheel-based compatibility matrix in CI (real Python 3.13 and 3.14 interpreters) and certified against real Azure — a Python 3.13 Function App deployed on a Flex Consumption plan in koreacentral. See issue #528 and issue #488 for the cap-lift work.

Quick Start

import json

import azure.functions as func
from pydantic import BaseModel

from azure_functions_openapi import (
    get_openapi_json,
    get_openapi_yaml,
    openapi,
    render_swagger_ui,
)

app = func.FunctionApp()


# Describe your API with plain Pydantic models.
class GreetRequest(BaseModel):
    name: str


class GreetResponse(BaseModel):
    message: str


# @openapi infers the route and method from the @app.route below —
# no need to repeat them here.
@openapi(
    summary="Greet user",
    tags=["Example"],
    requests=GreetRequest,
    responses=GreetResponse,
)
@app.route(route="http_trigger", auth_level=func.AuthLevel.ANONYMOUS, methods=["POST"])
def http_trigger(req: func.HttpRequest) -> func.HttpResponse:
    # @openapi documents the request/response contract — it does not validate.
    # For runtime validation, see azure-functions-validation.
    data = req.get_json()
    name = data.get("name", "world")
    return func.HttpResponse(
        json.dumps({"message": f"Hello, {name}!"}),
        mimetype="application/json",
    )

Pydantic v2 is a required dependency (pydantic>=2.0,<3.0) and is installed with this package. requests= / responses= accept Pydantic models (the recommended path) or raw JSON Schema dicts (see below) — so you can describe schemas without authoring Pydantic models, but Pydantic itself is always present.

Want runtime validation too? (optional) @openapi documents your Pydantic models — it does not parse or validate requests at runtime. If you also want automatic request parsing, consistent 400/422 error responses, and response-model enforcement, layer azure-functions-validation's @validate_http on the same Pydantic models. It is an optional companion, not a dependency — this package works fully on its own. See the validation README for details, or a full runnable example that pairs both on one resource: Full Stack CRUD API.

Want structured logging too? (optional) Pair your documented endpoints with azure-functions-logging for structured, correlation-aware logs and observability. It attaches request/response context to every log line without changing your @openapi contracts. Like validation, it is an optional companion, not a dependency — this package works fully on its own. See the logging README for details.

Wire up the spec + Swagger UI endpoints (openapi.json / openapi.yaml / docs)
# Serve the generated spec and Swagger UI as ordinary HTTP routes.
@app.route(route="openapi.json", auth_level=func.AuthLevel.ANONYMOUS, methods=["GET"])
def openapi_json(req: func.HttpRequest) -> func.HttpResponse:
    return func.HttpResponse(
        get_openapi_json(
            title="Sample API",
            description="OpenAPI document for the Sample API.",
        ),
        mimetype="application/json",
    )


@app.route(route="openapi.yaml", auth_level=func.AuthLevel.ANONYMOUS, methods=["GET"])
def openapi_yaml(req: func.HttpRequest) -> func.HttpResponse:
    return func.HttpResponse(
        get_openapi_yaml(
            title="Sample API",
            description="OpenAPI document for the Sample API.",
        ),
        mimetype="application/x-yaml",
    )


@app.route(route="docs", auth_level=func.AuthLevel.ANONYMOUS, methods=["GET"])
def swagger_ui(req: func.HttpRequest) -> func.HttpResponse:
    return render_swagger_ui()
Advanced: describe the schema with raw JSON Schema instead of Pydantic
@openapi(
    summary="Greet user",
    tags=["Example"],
    requests={
        "type": "object",
        "properties": {"name": {"type": "string"}},
        "required": ["name"],
    },
    responses={
        200: {
            "description": "Successful greeting",
            "content": {
                "application/json": {
                    "schema": {
                        "type": "object",
                        "properties": {"message": {"type": "string"}},
                    }
                }
            },
        }
    },
)
@app.route(route="http_trigger", auth_level=func.AuthLevel.ANONYMOUS, methods=["POST"])
def http_trigger(req: func.HttpRequest) -> func.HttpResponse:
    ...

Run locally with Azure Functions Core Tools:

func start

Verify locally and on Azure

After deploying (see docs/deployment.md), the same request produces the same response in both environments.

Local

curl -s http://localhost:7071/api/http_trigger \
  -H "Content-Type: application/json" \
  -d '{"name": "World"}'
{"message": "Hello, World!"}

Azure

curl -s "https://<your-app>.azurewebsites.net/api/http_trigger" \
  -H "Content-Type: application/json" \
  -d '{"name": "World"}'
{"message": "Hello, World!"}

The /api/openapi.json, /api/openapi.yaml, and /api/docs endpoints are also available in both environments.

Verified against a temporary Azure Functions deployment in koreacentral on a Flex Consumption plan (certified on Python 3.13). Response captured and URL anonymized.

Demo

The representative webhook_receiver example shows the full outcome of adopting this library:

  • You annotate an Azure Functions v2 HTTP handler with @openapi.
  • The package generates a real OpenAPI document for that route.
  • The same route is rendered in Swagger UI for browser-based inspection.

Generated Spec Result

The generated OpenAPI file is captured as a static preview from the same example run, so the README shows the actual document produced by the representative function.

OpenAPI spec preview

Swagger UI Result

The web preview below is generated from the same representative example and captured automatically from the rendered Swagger UI page produced by that example flow.

OpenAPI Swagger UI preview

When to use

  • You have HTTP-triggered Azure Functions and need API documentation
  • You want Swagger UI for browser-based API testing
  • You need OpenAPI specs for client code generation or CI validation
  • You want to keep docs in sync with handler code automatically

Documentation

Ecosystem

This package is part of the Azure Functions Python DX Toolkit.

Design principle: azure-functions-openapi owns API documentation and spec generation. azure-functions-validation owns request/response validation and serialization. azure-functions-langgraph owns LangGraph runtime exposure.

Package Role
azure-functions-openapi-python OpenAPI spec generation and Swagger UI
azure-functions-validation-python Request/response validation and serialization
azure-functions-db-python SQLAlchemy-powered DB integration helpers (poll-based pseudo trigger, input/output/client injection)
azure-functions-langgraph-python LangGraph deployment adapter for Azure Functions
azure-functions-scaffold-python Project scaffolding CLI
azure-functions-logging-python Structured logging and observability
azure-functions-doctor-python Pre-deploy diagnostic CLI
azure-functions-cookbook-python Dogfood examples — runnable recipes that exercise the full toolkit

For AI Coding Assistants

This repository includes llms.txt and llms-full.txt in the root directory. These files provide comprehensive package and API information optimized for LLM context windows.

  • llms.txt — Quick reference with core API, installation, and quick-start example
  • llms-full.txt — Complete reference with full signatures, patterns, design principles, and ecosystem context

Use these files to get better context when working with this package in AI-assisted coding environments.

Disclaimer

This project is an independent community project and is not affiliated with, endorsed by, or maintained by Microsoft.

Azure and Azure Functions are trademarks of Microsoft Corporation.

License

MIT

Metadata

Release files for azure-functions-openapi 0.27.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for azure-functions-openapi 0.27.1
File Size Uploaded
azure_functions_openapi-0.27.1.tar.gz 343.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for azure-functions-openapi 0.27.1
File Interpreter ABI Platform
azure_functions_openapi-0.27.1-py3-none-any.whl Python 3 none any Details

Total release size: 433.3 kB

Release files / azure_functions_openapi-0.27.1.tar.gz

Download URL azure_functions_openapi-0.27.1.tar.gz
Size 343.1 kB
Tags Source
SHA-256 checksum
How to use checksums
36a9ceb25ce3992579d8ddc559464d988793992e7b33227c5905e9296d146a43
BLAKE2b-256 checksum
How to use checksums
d54005f63228c6d656630628fce9dbb4d591d8ba0de3a9161e6afb9af89afac6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / azure_functions_openapi-0.27.1-py3-none-any.whl

Download URL azure_functions_openapi-0.27.1-py3-none-any.whl
Size 90.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1bcf1ed52481a6c211e625c016223bab0d2d314b5c749443d63316d661fa41e1
BLAKE2b-256 checksum
How to use checksums
0567b2691f79693d67c79f54f2f8fe6187c430818542fe545e799fb0eb38186b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page