Azure Functions Validation
Part of the Azure Functions Python DX Toolkit — dogfood-tested by azure-functions-cookbook-python.
Read this in: 한국어 | 日本語 | 简体中文
Validation and serialization for the Azure Functions Python v2 programming model.
Part of the Azure Functions Python DX Toolkit → Bring FastAPI-like developer experience to Azure Functions
Why this exists
Azure Functions Python v2 handlers often drift into the same repeated problems:
- Repeated manual parsing — every handler calls
req.get_json(),req.params.get(), handlesValueErrorindividually - Inconsistent error responses — some handlers return 400, others 422, formats vary across the project
- Missing response contracts — response payloads silently diverge from the intended schema
- No type safety — request data flows through as untyped dicts, bugs surface only at runtime
What it does
- Typed validation — body, query, path, and header parameters validated via Pydantic v2
- Automatic error responses — invalid requests get consistent
400/422JSON error bodies - Response model enforcement — mismatches raise
ResponseValidationError(HTTP 500) - Decorator-first API —
@validate_httpwraps your handler, no boilerplate needed - Custom error formatting — per-handler error shaping via
ErrorFormatter
How it works
@validate_http builds a validation pipeline once at import time, then runs it for every request:
flowchart LR
Client([HTTP Client]) --> AZ[Azure Functions wrapper]
AZ --> DEC["@validate_http"]
DEC --> PL[pipeline]
PL -->|parse / validate| AD[adapter]
AD --> H[your handler]
H --> PL2[pipeline]
PL2 -->|validate / serialize| AD2[adapter]
AD2 --> RESP([HttpResponse])
Before / After
Without this package — manual parsing, manual errors, no contracts
import json
import azure.functions as func
app = func.FunctionApp()
@app.route(route="users", methods=["POST"])
def create_user(req: func.HttpRequest) -> func.HttpResponse:
try:
body = req.get_json()
except ValueError:
return func.HttpResponse(
json.dumps({"error": "Invalid JSON"}),
status_code=400,
mimetype="application/json",
)
name = body.get("name")
email = body.get("email")
if not name or not isinstance(name, str):
return func.HttpResponse(
json.dumps({"error": "name is required"}),
status_code=400,
mimetype="application/json",
)
if not email or not isinstance(email, str):
return func.HttpResponse(
json.dumps({"error": "email is required"}),
status_code=400,
mimetype="application/json",
)
return func.HttpResponse(
json.dumps({"message": f"Hello {name}", "status": "success"}),
mimetype="application/json",
)
With @validate_http — typed, consistent, contract-enforced:
import azure.functions as func
from pydantic import BaseModel
from azure_functions_validation import validate_http
app = func.FunctionApp()
class CreateUserRequest(BaseModel):
name: str
email: str
class CreateUserResponse(BaseModel):
message: str
status: str = "success"
@app.route(route="users", methods=["POST"])
@validate_http(body=CreateUserRequest, response_model=CreateUserResponse)
def create_user(req: func.HttpRequest, body: CreateUserRequest) -> CreateUserResponse:
return CreateUserResponse(message=f"Hello {body.name}")
Manual parsing and validation disappear from the handler. Error formatting and response contracts — handled.
What you get
Valid request → typed response:
$ curl -s -X POST http://localhost:7071/api/users \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "email": "alice@example.com"}'
{"message": "Hello Alice", "status": "success"}
HTTP 200
Missing required field → automatic error response:
$ curl -s -X POST http://localhost:7071/api/users \
-H "Content-Type: application/json" \
-d '{"name": "Alice"}'
{
"detail": [
{
"loc": ["body", "email"],
"msg": "Field required",
"type": "missing"
}
]
}
HTTP 422 — standardized error response, automatic
Invalid JSON → clear error:
$ curl -s -X POST http://localhost:7071/api/users \
-H "Content-Type: application/json" \
-d 'not json'
{"detail": [{"loc": [], "msg": "Invalid JSON", "type": "value_error"}]}
HTTP 400
FastAPI comparison
| Feature | FastAPI | azure-functions-validation |
|---|---|---|
| Request body parsing | Built-in via type hints | @validate_http(body=Model) |
| Query/path/header validation | Query(), Path(), Header() |
@validate_http(query=Model, path=Model, headers=Model) |
| Response model | response_model= |
@validate_http(response_model=Model) |
| Validation errors | Automatic 422 | Automatic 422 with {"detail": [...]} |
| Error customization | Exception handlers | ErrorFormatter callback |
Scope
- Azure Functions Python v2 programming model
- HTTP-triggered functions registered on
func.FunctionApp() - Pydantic v2-based request and response validation
This package does not target the legacy function.json-based v1 programming model.
What this package does not do
API documentation (azure-functions-openapi), runtime/graph deployment (azure-functions-langgraph), and project scaffolding (azure-functions-scaffold) are handled by sibling packages.
Package names
Three names cover three different contexts:
| Context | Name |
|---|---|
| GitHub repo | azure-functions-validation-python |
| PyPI package | azure-functions-validation |
| Python import | azure_functions_validation |
The repository carries the -python suffix to mark it as the Python implementation. The PyPI package follows Python ecosystem conventions and is published without the suffix, so installation stays idiomatic: pip install azure-functions-validation. See the FAQ entry for the long version.
Installation
pip install azure-functions-validation
Your Azure Functions app should also include:
azure-functions
azure-functions-validation
For local development:
git clone https://github.com/yeongseon/azure-functions-validation-python.git
cd azure-functions-validation-python
pip install -e .[dev]
Quick Start
import azure.functions as func
from pydantic import BaseModel
from azure_functions_validation import validate_http
class CreateUserRequest(BaseModel):
name: str
email: str
class CreateUserResponse(BaseModel):
message: str
status: str = "success"
app = func.FunctionApp()
@app.route(route="users", methods=["POST"], auth_level=func.AuthLevel.ANONYMOUS)
@validate_http(body=CreateUserRequest, response_model=CreateUserResponse)
def create_user(req: func.HttpRequest, body: CreateUserRequest) -> CreateUserResponse:
return CreateUserResponse(message=f"Hello {body.name}")
Start the Functions host locally:
func start
Verify locally and on Azure
After deploying (see docs/deployment.md), the same request produces the same response in both environments.
Local
curl -s http://localhost:7071/api/users \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "email": "alice@example.com"}'
{"message": "Hello Alice", "status": "success"}
Azure
curl -s "https://<your-app>.azurewebsites.net/api/users" \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "email": "alice@example.com"}'
{"message": "Hello Alice", "status": "success"}
Invalid requests return the same 400 error in both environments:
Local
curl -s http://localhost:7071/api/users \
-H "Content-Type: application/json" \
-d 'not json'
{"detail": [{"loc": [], "msg": "Invalid JSON", "type": "value_error"}]}
HTTP 400
Azure
curl -s "https://<your-app>.azurewebsites.net/api/users" \
-H "Content-Type: application/json" \
-d 'not json'
{"detail": [{"loc": [], "msg": "Invalid JSON", "type": "value_error"}]}
HTTP 400
Manually verified by maintainers against a temporary Azure Functions deployment (koreacentral, Python 3.12, Consumption plan); response captured and URL anonymized. See docs/deployment.md for the verification status and context.
Status codes and controlled errors
Return 201 on creation and raise controlled HTTP errors (e.g. 404) without
bypassing validation. Set the success status with status_code= and raise
HttpError to render an error through the standard {"detail": [...]} envelope:
import azure.functions as func
from pydantic import BaseModel
from azure_functions_validation import HttpError, validate_http
app = func.FunctionApp()
_USERS: dict[int, "UserResponse"] = {}
class CreateUserRequest(BaseModel):
name: str
email: str
class UserResponse(BaseModel):
id: int
name: str
@app.route(route="users", methods=["POST"], auth_level=func.AuthLevel.ANONYMOUS)
@validate_http(body=CreateUserRequest, response_model=UserResponse, status_code=201)
def create_user(req: func.HttpRequest, body: CreateUserRequest) -> UserResponse:
user = UserResponse(id=len(_USERS) + 1, name=body.name)
_USERS[user.id] = user
return user # HTTP 201
@app.route(route="users/{user_id}", methods=["GET"], auth_level=func.AuthLevel.ANONYMOUS)
@validate_http(response_model=UserResponse)
def get_user(req: func.HttpRequest) -> UserResponse:
user = _USERS.get(int(req.route_params["user_id"]))
if user is None:
raise HttpError(404, "User not found") # standardized error envelope
return user
A missing user returns a consistent error body:
{"detail": [{"loc": [], "msg": "User not found", "type": "http_error"}]}
HTTP 404
HttpError also accepts a pre-built detail list for richer errors, and
server-side (>=500) errors are always sanitized so internal details never
leak to clients.
When to use
- You have HTTP-triggered Azure Functions that accept JSON request bodies
- You want Pydantic-based validation without writing manual parsing code
- You need consistent error response formats across handlers
- You want response schema enforcement to catch contract drift
Documentation
- Project docs live under
docs/ - Smoke-tested examples live under
examples/ - Product requirements:
PRD.md - Design principles:
DESIGN.md
Ecosystem
This package is part of the Azure Functions Python DX Toolkit.
Design principle: azure-functions-validation owns request/response validation and serialization. azure-functions-openapi owns API documentation and spec generation. azure-functions-langgraph owns LangGraph runtime exposure.
| Package | Role |
|---|---|
| azure-functions-openapi-python | OpenAPI spec generation and Swagger UI |
| azure-functions-validation-python | Request/response validation and serialization |
| azure-functions-db-python | SQLAlchemy-powered DB integration helpers (poll-based pseudo trigger, input/output/client injection) |
| azure-functions-langgraph-python | LangGraph deployment adapter for Azure Functions |
| azure-functions-scaffold-python | Project scaffolding CLI |
| azure-functions-logging-python | Structured logging and observability |
| azure-functions-doctor-python | Pre-deploy diagnostic CLI |
| azure-functions-durable-graph-python | Manifest-first graph runtime with Durable Functions (experimental) |
| azure-functions-knowledge-python | Knowledge retrieval (RAG) decorators |
| azure-functions-cookbook-python | Dogfood examples — runnable recipes that exercise the full toolkit |
For AI Coding Assistants
When integrating with LLM-powered coding assistants, provide these files for context:
llms.txt— Concise index with quick start and API overviewllms-full.txt— Expanded reference with full signatures and patterns
Reference the files at repository root:
- https://github.com/yeongseon/azure-functions-validation-python/blob/main/llms.txt
- https://github.com/yeongseon/azure-functions-validation-python/blob/main/llms-full.txt
Disclaimer
This project is an independent community project and is not affiliated with, endorsed by, or maintained by Microsoft.
Azure and Azure Functions are trademarks of Microsoft Corporation.
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file azure_functions_validation-0.9.1.tar.gz.
File metadata
- Download URL: azure_functions_validation-0.9.1.tar.gz
- Upload date:
- Size: 145.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
511f8a960081f2a4050866317aac09d444b6c3efc4b014651a41a67bc1823b65
|
|
| MD5 |
be75e61abd3914c7d9e0d904773aae7e
|
|
| BLAKE2b-256 |
2bf4f2fb5b0ee9de34c3bc74b19f15e568560dd8d0af85bef093c152b21e6f58
|
Provenance
The following attestation bundles were made for azure_functions_validation-0.9.1.tar.gz:
Publisher:
publish-pypi.yml on yeongseon/azure-functions-validation-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
azure_functions_validation-0.9.1.tar.gz -
Subject digest:
511f8a960081f2a4050866317aac09d444b6c3efc4b014651a41a67bc1823b65 - Sigstore transparency entry: 2389455723
- Sigstore integration time:
-
Permalink:
yeongseon/azure-functions-validation-python@a815055800baa9444e8cb01d9cb613eaf5613227 -
Branch / Tag:
refs/tags/v0.9.1 - Owner: https://github.com/yeongseon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@a815055800baa9444e8cb01d9cb613eaf5613227 -
Trigger Event:
push
-
Statement type:
File details
Details for the file azure_functions_validation-0.9.1-py3-none-any.whl.
File metadata
- Download URL: azure_functions_validation-0.9.1-py3-none-any.whl
- Upload date:
- Size: 31.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2e599d913f677681f92345d77ca411a7d1e80602481c2f71bcb51f6b617341e2
|
|
| MD5 |
380d06fbddc55cbb6103c2c43d8fc717
|
|
| BLAKE2b-256 |
81f3cc2b82fa88f0df6da17983bfc93d0df60fa108452a61498e24c20656fbdd
|
Provenance
The following attestation bundles were made for azure_functions_validation-0.9.1-py3-none-any.whl:
Publisher:
publish-pypi.yml on yeongseon/azure-functions-validation-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
azure_functions_validation-0.9.1-py3-none-any.whl -
Subject digest:
2e599d913f677681f92345d77ca411a7d1e80602481c2f71bcb51f6b617341e2 - Sigstore transparency entry: 2389455783
- Sigstore integration time:
-
Permalink:
yeongseon/azure-functions-validation-python@a815055800baa9444e8cb01d9cb613eaf5613227 -
Branch / Tag:
refs/tags/v0.9.1 - Owner: https://github.com/yeongseon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@a815055800baa9444e8cb01d9cb613eaf5613227 -
Trigger Event:
push
-
Statement type: