I've been building stuff with Azure Functions in Python recently, and I kept running into the same annoyance:
"Where's my Swagger UI?"
FastAPI gives you this beautiful auto-generated Swagger doc with just a few decorators and some pydantic models.
But Azure Functions? Nothing built-in. No docs. No OpenAPI JSON. Just function.json files and… sadness.
So I decided to do something about it.
💡 What I built
I started hacking on a decorator that could hook into the Azure Function's internals — and a few weekends later, I had this:
- A @openapidecorator that adds summary, description, tags, models, etc.
- Automatic method and route detection from function.json
- 
pydanticsupport for request and response schemas
- Swagger UI served at /api/docs
- JSON docs at /api/openapi.jsonand/api/openapi.yaml
All without needing to run a separate web server.
✍️ How it works (with an example)
Here's what it looks like in action:
# hello_openapi/function_app.py
import json
import azure.functions as func
from azure_functions_openapi.decorator import openapi
from azure_functions_openapi.openapi import get_openapi_json, get_openapi_yaml
from azure_functions_openapi.swagger_ui import render_swagger_ui
app = func.FunctionApp()
@openapi(
    summary="Greet user",
    route="/api/http_trigger",
    request_model={"name": "string"},
    response_model={"message": "string"},
    tags=["Example"]
)
@app.function_name(name="http_trigger")
@app.route(route="/api/http_trigger", auth_level=func.AuthLevel.ANONYMOUS, methods=["POST"])
def main(req: func.HttpRequest) -> func.HttpResponse:
    try:
        data = req.get_json()
        name = data.get("name", "world")
        return func.HttpResponse(
            json.dumps({"message": f"Hello, {name}!"}),
            mimetype="application/json"
        )
    except Exception as e:
        return func.HttpResponse(f"Error: {str(e)}", status_code=400)
@app.function_name(name="openapi_json")
@app.route(route="/api/openapi.json", auth_level=func.AuthLevel.ANONYMOUS, methods=["GET"])
def openapi_json(req: func.HttpRequest) -> func.HttpResponse:
    return get_openapi_json()
@app.function_name(name="openapi_yaml")
@app.route(route="/api/openapi.yaml", auth_level=func.AuthLevel.ANONYMOUS, methods=["GET"])
def openapi_yaml(req: func.HttpRequest) -> func.HttpResponse:
    return get_openapi_yaml()
@app.function_name(name="swagger_ui")
@app.route(route="/api/docs", auth_level=func.AuthLevel.ANONYMOUS, methods=["GET"])
def swagger_ui(req: func.HttpRequest) -> func.HttpResponse:
    return render_swagger_ui()
Once you register the Swagger UI route manually, deploying your function lets you access the full documentation at /api/docs.
🚀 Quick Start
pip install azure-functions-openapi
Then:
- Decorate your functions with @openapi(...)
- Define your request/response models with pydanticor dict
- Register /api/docs,/api/openapi.json, and/api/openapi.yamlroutes
- Deploy and visit /api/docs🎉
🔗 GitHub
All the code is open-source here:
👉 https://github.com/yeongseon/azure-functions-openapi
If you try it out, I'd love to hear how it works for you.
PRs, issues, suggestions — all welcome 🙌
Originally published on Medium.
 

 
    
Top comments (0)