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)