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
@openapi
decorator that adds summary, description, tags, models, etc. - Automatic method and route detection from
function.json
-
pydantic
support for request and response schemas - Swagger UI served at
/api/docs
- JSON docs at
/api/openapi.json
and/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
pydantic
or dict - Register
/api/docs
,/api/openapi.json
, and/api/openapi.yaml
routes - 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)