Skip to content

API Reference

This page documents the public API exported from azure_functions_validation.

from azure_functions_validation import (
    ErrorFormatter,
    ResponseValidationError,
    validate_http,
)

Public surface

The package intentionally keeps a small public API: validate_http, ResponseValidationError, and ErrorFormatter. 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

Shorthand alias for body.

None
response_model Any

Pydantic model for response validation.

None
adapter ValidationAdapter | None

Custom validation adapter (defaults to PydanticAdapter).

None
error_formatter ErrorFormatter | None

Per-handler custom error formatter.

None

Returns:

Type Description
Callable[..., Any]

A decorator that wraps the handler with validation logic.

Source code in src/azure_functions_validation/decorator.py
def validate_http(
    *,
    body: Any = None,
    query: Any = None,
    path: Any = None,
    headers: Any = None,
    request_model: Any = None,
    response_model: Any = None,
    adapter: ValidationAdapter | None = None,
    error_formatter: ErrorFormatter | None = None,
) -> Callable[..., Any]:
    """Decorator for validating HTTP request inputs and response outputs.

    Args:
        body: Pydantic model for request body validation.
        query: Pydantic model for query parameter validation.
        path: Pydantic model for path parameter validation.
        headers: Pydantic model for header validation.
        request_model: Shorthand alias for *body*.
        response_model: Pydantic model for response validation.
        adapter: Custom validation adapter (defaults to ``PydanticAdapter``).
        error_formatter: Per-handler custom error formatter.

    Returns:
        A decorator that wraps the handler with validation logic.
    """
    # Handle request_model shorthand
    if request_model is not None:
        if any([body, query, path, headers]):
            raise ValueError("Cannot use request_model together with body/query/path/headers")
        body = request_model

    # Use default adapter if none provided
    if adapter is None:
        adapter = PydanticAdapter()

    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        is_async = inspect.iscoroutinefunction(func)

        func_sig = inspect.signature(func)
        func_params = func_sig.parameters

        request_param_name = _find_request_param(func, func_params)
        _validate_no_conflicts(func, request_param_name, body, query, path, headers, request_model)

        config = PipelineConfig(
            body=body,
            query=query,
            path=path,
            headers=headers,
            request_model=request_model,
            response_model=response_model,
            adapter=adapter,
            error_formatter=error_formatter,
            func_params=func_params,
            request_param_name=request_param_name,
        )

        @wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> HttpResponse:
            return run_pipeline(func, args, kwargs, config)

        @wraps(func)
        async def async_wrapper(*args: Any, **kwargs: Any) -> HttpResponse:
            return await run_pipeline_async(func, args, kwargs, config)

        return async_wrapper if is_async else wrapper

    return decorator

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: 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
def __init__(self, message: str = "Response validation error"):
    """Initialize ResponseValidationError.

    Args:
        message: Error message
    """
    super().__init__(message)
    self.message = message

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].

Error response shape reference

Default validation and parsing errors use this envelope:

{
  "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: loc starts with "body"
  • query errors: loc starts with "query"
  • path errors: loc starts with "path"
  • header errors: loc starts with "headers"
  • 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_async
  • adapter.py: ValidationAdapter, PydanticAdapter

For full implementation patterns, see Usage and Architecture.