API Reference¶
This page documents the public API exported from azure_functions_validation.
from azure_functions_validation import (
ErrorFormatter,
ResponseValidationError,
SerializationError,
validate_http,
)
Public surface
The package exports: validate_http, ResponseValidationError,
ErrorFormatter, and SerializationError. Pipeline and adapter internals
are not public contracts.
validate_http¶
Decorator for validating HTTP request inputs and response outputs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
body
|
Any
|
Pydantic model for request body validation. |
None
|
query
|
Any
|
Pydantic model for query parameter validation. |
None
|
path
|
Any
|
Pydantic model for path parameter validation. |
None
|
headers
|
Any
|
Pydantic model for header validation. |
None
|
request_model
|
Any
|
Deprecated shorthand alias for body. Use |
None
|
response_model
|
Any
|
Pydantic model for response validation. |
None
|
adapter
|
ValidationAdapter | None
|
Custom validation adapter (defaults to |
None
|
error_formatter
|
ErrorFormatter | None
|
Per-handler custom error formatter. |
None
|
status_code
|
int
|
HTTP status code for successful responses (default 200).
Use e.g. |
200
|
legacy_loc
|
bool
|
When |
False
|
Returns:
| Type | Description |
|---|---|
Callable[..., Any]
|
A decorator that wraps the handler with validation logic. |
Source code in src/azure_functions_validation/decorator.py
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | |
Usage example: body + response validation¶
import azure.functions as func
from pydantic import BaseModel
from azure_functions_validation import validate_http
class CreateInvoiceBody(BaseModel):
customer_id: str
amount: float
class CreateInvoiceResponse(BaseModel):
invoice_id: str
status: str
app = func.FunctionApp()
@app.function_name(name="create_invoice")
@app.route(route="invoices", methods=["POST"], auth_level=func.AuthLevel.ANONYMOUS)
@validate_http(body=CreateInvoiceBody, response_model=CreateInvoiceResponse)
def create_invoice(req: func.HttpRequest, body: CreateInvoiceBody) -> CreateInvoiceResponse:
return CreateInvoiceResponse(invoice_id="inv_1001", status="created")
Usage example: status codes and controlled errors¶
Use status_code= to set the success status (e.g. 201 for creation), and
raise HttpError to return a controlled error through the standard
{"detail": [...]} envelope without bypassing validation.
import azure.functions as func
from pydantic import BaseModel
from azure_functions_validation import HttpError, validate_http
class CreateUserBody(BaseModel):
name: str
class UserResponse(BaseModel):
id: int
name: str
app = func.FunctionApp()
_USERS: dict[int, UserResponse] = {}
@app.function_name(name="create_user")
@app.route(route="users", methods=["POST"], auth_level=func.AuthLevel.ANONYMOUS)
@validate_http(body=CreateUserBody, response_model=UserResponse, status_code=201)
def create_user(req: func.HttpRequest, body: CreateUserBody) -> UserResponse:
user = UserResponse(id=len(_USERS) + 1, name=body.name)
_USERS[user.id] = user
return user # HTTP 201
@app.function_name(name="get_user")
@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")
return user
Usage example: query + path + headers¶
import azure.functions as func
from pydantic import BaseModel, ConfigDict, Field
from azure_functions_validation import validate_http
class UserQuery(BaseModel):
include_deleted: bool = False
class UserPath(BaseModel):
user_id: int = Field(ge=1)
class UserHeaders(BaseModel):
model_config = ConfigDict(populate_by_name=True)
x_request_id: str = Field(alias="x-request-id")
app = func.FunctionApp()
@app.function_name(name="get_user")
@app.route(route="users/{user_id}", methods=["GET"], auth_level=func.AuthLevel.ANONYMOUS)
@validate_http(query=UserQuery, path=UserPath, headers=UserHeaders)
def get_user(
req: func.HttpRequest,
query: UserQuery,
path: UserPath,
headers: UserHeaders,
) -> dict[str, object]:
return {
"user_id": path.user_id,
"include_deleted": query.include_deleted,
"request_id": headers.x_request_id,
}
Usage example: custom request_model shorthand¶
import azure.functions as func
from pydantic import BaseModel
from azure_functions_validation import validate_http
class CreateTaskRequest(BaseModel):
title: str
app = func.FunctionApp()
@app.function_name(name="create_task")
@app.route(route="tasks", methods=["POST"], auth_level=func.AuthLevel.ANONYMOUS)
@validate_http(request_model=CreateTaskRequest)
def create_task(req: func.HttpRequest, req_model: CreateTaskRequest) -> dict[str, str]:
return {"title": req_model.title}
Conflict rule
request_model cannot be combined with body, query, path, or headers.
The decorator raises ValueError at import time if combined.
ResponseValidationError¶
Bases: Exception
Raised when response validation fails.
Initialize ResponseValidationError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
Error message |
'Response validation error'
|
Source code in src/azure_functions_validation/errors.py
Usage example: handling response contract failures¶
import azure.functions as func
from pydantic import BaseModel
from azure_functions_validation import validate_http
class HealthResponse(BaseModel):
status: str
app = func.FunctionApp()
@app.function_name(name="health")
@app.route(route="health", methods=["GET"], auth_level=func.AuthLevel.ANONYMOUS)
@validate_http(response_model=HealthResponse)
def health(req: func.HttpRequest) -> dict[str, str]:
# Returning an invalid shape to show failure behavior
return {"state": "ok"}
When response validation fails, the runtime returns HTTP 500 with this payload:
{
"detail": [
{
"loc": ["response"],
"msg": "Response validation failed",
"type": "response_validation_error"
}
]
}
HttpResponse bypass
Returning azure.functions.HttpResponse directly bypasses response model
validation by design.
ErrorFormatter¶
Usage example: custom validation error shape¶
import azure.functions as func
from pydantic import BaseModel
from azure_functions_validation import ErrorFormatter, validate_http
class InputModel(BaseModel):
value: int
def app_error_formatter(exc: Exception, status_code: int) -> dict[str, object]:
return {
"error": {
"code": f"VALIDATION_{status_code}",
"message": str(exc),
}
}
formatter: ErrorFormatter = app_error_formatter
app = func.FunctionApp()
@app.function_name(name="custom_error")
@app.route(route="custom_error", methods=["POST"], auth_level=func.AuthLevel.ANONYMOUS)
@validate_http(body=InputModel, error_formatter=formatter)
def custom_error(req: func.HttpRequest, body: InputModel) -> dict[str, int]:
return {"value": body.value}
Formatter signature
Keep the formatter signature exactly (exc: Exception, status_code: int) -> dict[str, Any].
HttpError¶
Bases: Exception
Raised by a handler to return a controlled HTTP error response.
Rendered through the standard error envelope ({"detail": [...]}) by the
validation pipeline, so controlled errors (e.g. 404, 409) share the same
shape as automatic validation errors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
status_code
|
int
|
HTTP status code for the response (e.g. |
required |
detail
|
Any
|
Either a human-readable message (wrapped into a single
|
'Error'
|
error_type
|
str
|
|
'http_error'
|
Source code in src/azure_functions_validation/errors.py
to_detail()
¶
Return the error-envelope detail list for this error.
Source code in src/azure_functions_validation/errors.py
Raise HttpError(status_code, detail) from a handler to return a controlled
HTTP error rendered through the standard {"detail": [...]} envelope. detail
may be a plain message (wrapped into a single entry) or a pre-built list of
{"loc", "msg", "type"} mappings. Errors with status_code >= 500 are
sanitized so internal details never leak to clients.
azure_functions_validation.testing.MockHttpRequest¶
A public test helper for unit-testing validated handlers. It subclasses the real
azure.functions.HttpRequest, so it drives the genuine @validate_http pipeline
end-to-end without a running Functions host.
from azure_functions_validation.testing import MockHttpRequest
request = MockHttpRequest(
method="POST",
json={"name": "Alice", "email": "alice@example.com"},
params={"debug": "true"},
)
response = create_user(request)
assert response.status_code == 200
See Testing for the full list of constructor options.
Error response shape reference¶
Default validation and parsing errors use this envelope:
{
"detail": [
{
"loc": ["body", "field_name"],
"msg": "Field required",
"type": "missing"
}
],
"error_format_version": 1
}
Stability contract¶
Every default error envelope carries a top-level error_format_version
integer. It lets downstream consumers (frontends, API gateways) pin against a
known schema and detect breaking changes explicitly instead of silently
misparsing new fields.
- The current version is
1. - The integer is bumped only when the default envelope changes in a backwards-incompatible way; additive, optional fields do not bump it.
- The marker is present on all built-in envelopes — validation errors (
4xx), sanitized server errors (5xx), and the internal-failure fallback. - A custom
ErrorFormatterowns its output shape entirely: the marker is never injected into a successful custom formatter's response. Emit your own version field there if you need one. { "detail": [ { "loc": ["body", "field_name"], "msg": "Field required", "type": "missing" } ] } ```
Common status codes:
400: invalid JSON parsing ("Invalid JSON").422: request validation failed.500: response validation failure or internal adapter failure.
Typical loc values
- body errors:
locstarts with"body" - query errors:
locstarts with"query" - path errors:
locstarts with"path" - header errors:
locstarts with"headers" - response errors:
locequals["response"]
Opting out of the source prefix
The leading source segment (body / query / path / headers) was
added to disambiguate same-named fields across inputs. To keep the previous
unprefixed loc for one migration cycle, pass legacy_loc=True to
validate_http. This escape hatch will be removed in a future release.
- response errors: loc equals ["response"]
Internal references¶
These modules are useful for advanced extension work but are internal APIs:
pipeline.py:PipelineConfig,run_pipeline,run_pipeline_asyncadapter.py:ValidationAdapter,PydanticAdapter
For full implementation patterns, see Usage and Architecture.