# azure-functions-validation — Full LLM Reference

> Pydantic-based request/response validation for Azure Functions Python v2.

## Package Info

- PyPI: `pip install azure-functions-validation`
- Version: 0.6.0
- Python: >=3.10, <3.15
- License: MIT
- Docs: https://yeongseon.github.io/azure-functions-validation/
- Repository: https://github.com/yeongseon/azure-functions-validation
- Azure Functions programming model: v2

## Installation

```bash
pip install azure-functions-validation
```

For local development:
```bash
git clone https://github.com/yeongseon/azure-functions-validation.git
cd azure-functions-validation
pip install -e .[dev]
```

## Public API

### Main Decorator

```python
from azure_functions_validation import validate_http
from pydantic import BaseModel

def validate_http(
    *,
    body: type[BaseModel] | None = None,
    query: type[BaseModel] | None = None,
    path: type[BaseModel] | None = None,
    headers: type[BaseModel] | None = None,
    request_model: type[BaseModel] | None = None,
    response_model: type[BaseModel] | None = None,
    adapter: ValidationAdapter | None = None,
    error_formatter: ErrorFormatter | None = None,
) -> Callable[[Callable], Callable]:
    """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 parameter.
        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.
    """
```

### Error Classes

```python
from azure_functions_validation import ResponseValidationError, SerializationError

class ResponseValidationError(Exception):
    """Raised when response validation fails.
    
    Attributes:
        message: Error message describing the validation failure.
    """
    def __init__(self, message: str = "Response validation error"):
        pass

class SerializationError(TypeError):
    """Raised when an unsupported type is encountered during serialization.
    
    Attributes:
        type_name: Name of the unsupported type.
    """
    def __init__(self, type_name: str) -> None:
        pass
```

### Error Formatting

```python
from azure_functions_validation import ErrorFormatter
from typing import Any

ErrorFormatter = Callable[[Exception, int], dict[str, Any]]
```

Type alias for custom error formatters. Called with:
- `exception`: The caught validation or serialization exception
- `status_code`: HTTP status code (400, 422, 500, etc.)

Must return a dict representing the error response body (will be JSON-serialized).

## Common Patterns

### Basic Request Body Validation

```python
import azure.functions as func
from pydantic import BaseModel
from azure_functions_validation import validate_http

class UserCreateRequest(BaseModel):
    name: str
    email: str

app = func.FunctionApp()

@app.route(route="users", methods=["POST"])
@validate_http(body=UserCreateRequest)
def create_user(req: func.HttpRequest, body: UserCreateRequest) -> func.HttpResponse:
    # body is already validated UserCreateRequest instance
    return func.HttpResponse(f"Created {body.name}", status_code=201)
```

### Query and Path Parameters

```python
from pydantic import BaseModel

class SearchParams(BaseModel):
    q: str
    limit: int = 10
    offset: int = 0

class UserPathParams(BaseModel):
    user_id: str

@app.route(route="users/<user_id>")
@validate_http(path=UserPathParams, query=SearchParams)
def get_user(req: func.HttpRequest, path: UserPathParams, query: SearchParams) -> func.HttpResponse:
    # path and query are validated instances
    return func.HttpResponse(f"User: {path.user_id}, limit: {query.limit}")
```

### Request + Response Validation

```python
class CreateUserResponse(BaseModel):
    id: str
    name: str
    created_at: str

@app.route(route="users", methods=["POST"])
@validate_http(body=UserCreateRequest, response_model=CreateUserResponse)
def create_user(req: func.HttpRequest, body: UserCreateRequest) -> CreateUserResponse:
    # Response must match CreateUserResponse schema, or ResponseValidationError is raised
    return CreateUserResponse(
        id="123",
        name=body.name,
        created_at="2024-01-01T00:00:00Z"
    )
```

### Custom Error Formatting

```python
from azure_functions_validation import ErrorFormatter

def my_error_formatter(exception: Exception, status_code: int) -> dict:
    return {
        "code": "VALIDATION_ERROR",
        "message": str(exception),
        "status": status_code,
    }

@app.route(route="users", methods=["POST"])
@validate_http(
    body=UserCreateRequest,
    error_formatter=my_error_formatter
)
def create_user_custom_errors(
    req: func.HttpRequest,
    body: UserCreateRequest
) -> func.HttpResponse:
    return func.HttpResponse(f"Created {body.name}")
```

### Header Validation

```python
from pydantic import BaseModel, Field

class HeaderParams(BaseModel):
    authorization: str = Field(alias="Authorization")
    x_user_id: str | None = Field(None, alias="X-User-ID")

@app.route(route="protected")
@validate_http(headers=HeaderParams)
def protected_endpoint(
    req: func.HttpRequest,
    headers: HeaderParams
) -> func.HttpResponse:
    # headers.authorization is validated
    return func.HttpResponse("OK")
```

## Design Principles

1. **Decorator-first**: Configuration happens at decoration time, validation at runtime.
2. **Explicit over implicit**: All parameters are explicit in decorator arguments.
3. **Pydantic v2 native**: Leverages Pydantic's validation power and error messages.
4. **Error consistency**: All validation errors return `400` or `422` with `{"detail": [...]}` format.
5. **Response enforcement**: Response models catch contract drift before deployment.
6. **Minimal overhead**: No request processing happens until handler is called.
7. **Azure Functions v2 aligned**: Follows Azure Functions Python v2 programming model conventions.

## Limitations

1. **Request type**: Only works with `azure.functions.HttpRequest`.
2. **Response types**: Supports anything JSON-serializable (BaseModel, dict, list, str, int, bool, None).
3. **Async support**: Both sync and async handlers are supported.
4. **No inheritance validation**: Inherited Pydantic fields work, but validation model itself cannot be inherited in decorator.
5. **File uploads**: Not designed for multipart/form-data or file uploads. Use raw request handling for that.

## Error Response Format

All validation errors return `{"detail": [{"loc": [...], "msg": "...", "type": "..."}]}` format
matching Pydantic ValidationError style. This is consistent across all handlers unless overridden
with a custom `ErrorFormatter`.

Example validation error:
```json
{
  "detail": [
    {
      "loc": ["body", "email"],
      "msg": "value is not a valid email address",
      "type": "value_error.email"
    }
  ]
}
```

## Type Hints

All public functions and classes are fully type-hinted for IDE support and static analysis.

```python
from typing import Any, Callable
from pydantic import BaseModel

ErrorFormatter: type = Callable[[Exception, int], dict[str, Any]]
```

Supported parameter types in decorator:
- `body`, `query`, `path`, `headers`: Any Pydantic `BaseModel` subclass
- `response_model`: Any Pydantic `BaseModel` subclass (or Union types for multiple response shapes)
- `error_formatter`: Callable matching `ErrorFormatter` signature
- `adapter`: Custom validation adapter implementing `ValidationAdapter` protocol
