HTTP API Example¶
This walkthrough builds an HTTP-focused Azure Functions project, customizes the generated code, adds a second endpoint, and runs everything locally.
What You Will Build¶
By the end, you will have:
- a scaffolded HTTP project
- optional OpenAPI and validation support
- two HTTP function modules (
healthandwebhooks) - local run and curl verification flow
1) Generate the Project¶
Create a strict project with OpenAPI and validation enabled:
afs advanced new \
--template http \
--preset strict \
--with-openapi \
--with-validation \
my-http-api
Move into the project and install dependencies:
Run baseline checks:
2) Understand Generated HTTP Behavior¶
The http template generates two endpoints:
GET /api/health— anonymous auth, returns{"status": "ok"}.POST /api/webhooks/inbound— FUNCTION auth, verifies an HMAC-SHA256 signature from theX-Signatureheader against theWEBHOOK_SECRETenvironment variable. Returns 503 when the secret is not configured, 401 on signature mismatch, and 202 on success.
Default route mode
The health endpoint uses anonymous auth so it can be polled by infrastructure without credentials. The webhook endpoint uses FUNCTION auth and signature verification to authenticate external callers.
The function_app.py entrypoint also includes OpenAPI routes when
--with-openapi is enabled:
GET /api/docsGET /api/openapi.jsonGET /api/openapi.yaml
3) Run the Function App Locally¶
In a second terminal, test the health endpoint:
Expected response:
Open Swagger UI:
4) Add a New HTTP Endpoint Module¶
Use afs api add to add a second endpoint scaffold:
This command:
- Creates
app/functions/users.py. - Creates
tests/test_users.py(iftests/exists). - Updates
function_app.pyimport and registration markers.
Preview before writing if needed:
5) Customize the New Endpoint¶
Edit app/functions/users.py so the route returns user list data:
from __future__ import annotations
import json
import azure.functions as func
users_blueprint = func.Blueprint() # type: ignore[no-untyped-call]
@users_blueprint.route(
route="users",
methods=["GET"],
auth_level=func.AuthLevel.FUNCTION,
)
def users(req: func.HttpRequest) -> func.HttpResponse:
payload = {
"items": [
{"id": 1, "name": "Ada"},
{"id": 2, "name": "Grace"},
]
}
return func.HttpResponse(
body=json.dumps(payload),
status_code=200,
mimetype="application/json",
)
Keep business logic separated
For larger endpoints, move data access and business rules into
app/services/ and keep trigger modules thin.
6) Test the New Endpoint¶
Run checks and tests:
Run locally again:
Call the new route:
Example response:
7) Common HTTP Customization Patterns¶
- Add request/response models in
app/schemas/. - Add OpenAPI annotations for each route when docs are enabled.
- Keep trigger code in
app/functions/, service logic inapp/services/. - Use pytest tests in
tests/for endpoint behavior.
Troubleshooting Notes¶
OpenAPI routes missing
Regenerate with --with-openapi, or verify your project was created with
that flag. OpenAPI routes are generated at creation time.
Webhook secret not set
With WEBHOOK_SECRET unset, POST /api/webhooks/inbound returns 503. Set it in local.settings.json before testing the webhook endpoint locally.
Next Steps¶
- Follow Full Stack Example for a complete strict setup.
- See Configuration for option combinations.
- Use Troubleshooting for runtime issues.