Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Configuration

Validation injects configured models by parameter name: `body`, `query`, `path`
and `headers` (`req_model` for the deprecated shorthand). A required handler
parameter annotated with a configured model but named differently, such as
`payload: Input` for `body=Input`, raises a decoration-time configuration error.
Rename it to `body`; there is no implicit injection by type. Independent Azure
binding parameters and handlers that validate without consuming a model remain
supported.

This page documents every parameter of `validate_http` and how to combine them
in production handlers.

Expand Down
20 changes: 20 additions & 0 deletions src/azure_functions_validation/decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,26 @@ def _validate_no_conflicts(
f"conflicts with a @validate_http injected parameter of the same name. "
f"Rename it (e.g. to 'req' or 'http_request')."
)
parameters = inspect.signature(func).parameters
try:
annotations = get_type_hints(func)
except (NameError, TypeError):
annotations = getattr(func, "__annotations__", {})
for name, parameter in parameters.items():
if name == request_param_name or name in _injected:
continue
if parameter.default is not inspect.Parameter.empty:
continue
annotation = annotations.get(name)
expected = [
key for key, model in _injected.items() if model is not None and annotation is model
]
if expected:
raise ValueError(
f"Function {func.__name__}: parameter '{name}' matches a configured model; "
f"expected injected parameter name(s): {', '.join(expected)}. "
"Validation injects by name, not by type."
)


_MISSING: Any = object() # sentinel for absent req argument
Expand Down
25 changes: 25 additions & 0 deletions tests/test_injected_parameter_diagnostic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from azure.functions import HttpRequest
from pydantic import BaseModel
import pytest

from azure_functions_validation import validate_http


class Input(BaseModel):
name: str


def test_mismatched_body_model_parameter_fails_during_decoration() -> None:
with pytest.raises(ValueError, match="payload.*expected.*body"):

@validate_http(body=Input)
def handler(req: HttpRequest, payload: Input) -> Input:
return payload


def test_correctly_named_model_and_independent_bindings_remain_supported() -> None:
@validate_http(body=Input)
def handler(req: HttpRequest, body: Input, context: str) -> Input:
return body

assert callable(handler)
Loading