Skip to content

Latest commit

 

History

History
227 lines (165 loc) · 6.56 KB

getting-started.md

File metadata and controls

227 lines (165 loc) · 6.56 KB

Getting Started

This quickstart takes you from zero to a working Azure Functions API with:

  • a documented HTTP endpoint (@openapi)
  • generated OpenAPI JSON and YAML routes
  • Swagger UI route

Prerequisites

Before you begin, make sure you have:

  • Python 3.11+
  • Azure Functions Core Tools v4
  • An Azure Functions Python v2 app (func.FunctionApp)

!!! warning azure-functions-openapi targets the Azure Functions Python v2 decorator model. It does not support the legacy function.json model.

Install dependencies

pip install azure-functions azure-functions-openapi

If you use Pydantic models in your function contracts:

pip install pydantic

Create your first documented endpoint

Add a file like function_app.py:

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()


class HelloResponse(BaseModel):
    message: str


@app.function_name(name="http_trigger")
@openapi(
    summary="Greet user",
    description="Returns a greeting using the `name` query parameter.",
    tags=["Hello"],
    operation_id="greetUser",
    route="/api/http_trigger",
    method="get",
    parameters=[
        {
            "name": "name",
            "in": "query",
            "required": True,
            "schema": {"type": "string"},
            "description": "Name to greet",
        }
    ],
    responses={
        200: {
            "description": "Successful greeting",
            "content": {"application/json": {"schema": HelloResponse}},
        },
        400: {"description": "Missing name"},
    },
    )
@app.route(route="http_trigger", methods=["GET"], auth_level=func.AuthLevel.ANONYMOUS)
def http_trigger(req: func.HttpRequest) -> func.HttpResponse:
    name = req.params.get("name")
    if not name:
        return func.HttpResponse("Missing name", status_code=400)

    return func.HttpResponse(
        json.dumps({"message": f"Hello, {name}!"}),
        mimetype="application/json",
        status_code=200,
    )

!!! note "Response parameters here" This example pairs a model-derived 200 schema with a manual 400 response, expressed with a single unified responses= map: the 200 entry carries the model in content.schema while 400 is a plain Response Object. See Usage.

Add spec endpoints

The opt-in helper registers the JSON, YAML, and Swagger UI routes on your existing FunctionApp:

from azure_functions_openapi import register_openapi_routes

register_openapi_routes(app, title="Hello API", version="1.0.0")

Pass the same route_prefix configured in host.json when it differs from the default /api. Use enabled=False to register nothing in environments where runtime documentation must stay unavailable.

Manual alternative

You can instead add JSON and YAML routes directly:

!!! warning "Choose documentation-route access deliberately" The AuthLevel.ANONYMOUS routes below expose the OpenAPI JSON/YAML and Swagger UI publicly after deployment. The spec discloses endpoint shapes, schemas, and security scheme names. Anonymous access is convenient for local development, but production exposure should be a deliberate decision; see Protecting documentation routes.

@app.function_name(name="openapi_json")
@app.route(route="openapi.json", methods=["GET"], auth_level=func.AuthLevel.ANONYMOUS)
def openapi_json(req: func.HttpRequest) -> func.HttpResponse:
    return func.HttpResponse(
        get_openapi_json(
            title="Hello API",
            version="1.0.0",
            description="OpenAPI spec for Hello API",
        ),
        mimetype="application/json",
    )


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

!!! note get_openapi_json() and get_openapi_yaml() return strings. Wrap them in func.HttpResponse as shown above.

Add Swagger UI endpoint

When using the manual alternative, add the UI route too:

@app.function_name(name="swagger_ui")
@app.route(route="docs", methods=["GET"], auth_level=func.AuthLevel.ANONYMOUS)
def swagger_ui(req: func.HttpRequest) -> func.HttpResponse:
    return render_swagger_ui(
        title="Hello API Docs",
        openapi_url="/api/openapi.json",
    )

Run locally

func start

When startup succeeds, test all routes.

Test with curl

Call your endpoint:

curl "http://localhost:7071/api/http_trigger?name=Azure"

Expected response:

{"message":"Hello, Azure!"}

Fetch JSON spec:

curl "http://localhost:7071/api/openapi.json"

Fetch YAML spec:

curl "http://localhost:7071/api/openapi.yaml"

The generated spec is served as a JSON document — the same format a client generator reads to produce SDKs. The preview below is captured from the representative webhook_receiver example, which documents a richer API than this walkthrough:

OpenAPI spec preview generated from the representative webhook_receiver example

View Swagger UI

Open:

http://localhost:7071/api/docs

You should see your operation with its summary, description, parameters, and response schema. The Swagger UI preview below is captured from the representative webhook_receiver example:

Swagger UI preview generated from the representative webhook_receiver example

Next steps

  1. Add request validation and richer models (Usage)
  2. Configure security schemes and OpenAPI versions (Configuration)
  3. Explore complete examples (Webhook Receiver, Report Jobs, Notification Request, Partner Import Bridge)

Troubleshooting quick checks

If docs are blank:

  • confirm endpoint functions are imported during app startup
  • confirm target handlers are decorated with @openapi
  • confirm openapi_url in render_swagger_ui() points to a valid route

For deeper issues, see Troubleshooting.