Skip to content

Feature request: Support Field annotation for event_handler parameter validation #8304

Description

@rtandy

Use case

Hi, this is a follow-up to #5953.

@dap0am kindly implemented the example use case I showed there (thanks!). However, it looks like they actually only special-cased the specific example (discriminated union in the body). General support for Field annotations with different parameter types (path/query/header/body) is still missing.

This issue is to express more explicitly the originally intended request: I wish to be able to use any Field annotation in parameter validation, same as if the field were used in a model, with any kind of parameter.

Thank you for maintaining Powertools!

Solution/User Experience

from http import HTTPStatus
from typing import Annotated

from aws_lambda_powertools.event_handler import APIGatewayHttpResolver
from aws_lambda_powertools.event_handler.openapi.params import Body, Header, Path, Query

from pydantic.fields import Field

# may be defined elsewhere; used in models as well as parameters; etc
StrField = Annotated[str, Field()]

app = APIGatewayHttpResolver(enable_validation=True)

@app.get('/header')
def get_header(h: Annotated[StrField, Header]) -> None:
    ...

@app.get('/path/<p>')
def get_path(p: Annotated[StrField, Path]) -> None:
    ...

@app.get('/query')
def get_query(q: Annotated[StrField, Query]) -> None:
    ...

@app.post('/body')
def post_body(b: Annotated[StrField, Body]) -> None:
    ...

def lambda_handler(event, context):
    return app.resolve(event, context)

def test_get_header():
    event = {
        'headers': {'h': 'test'},
        'rawPath': '/header',
        'requestContext': {
            'http': { 'method': 'GET' },
            'stage': '$default'
        }
    }

    response = lambda_handler(event, None)
    assert HTTPStatus.OK == response['statusCode']

def test_get_path():
    event = {
        'rawPath': '/path/test',
        'requestContext': {
            'http': { 'method': 'GET' },
            'stage': '$default'
        }
    }

    response = lambda_handler(event, None)
    assert HTTPStatus.OK == response['statusCode']

def test_get_query():
    event = {
        'rawPath': '/query',
        'requestContext': {
            'http': { 'method': 'GET' },
            'stage': '$default'
        },
        'queryStringParameters': {'q': 'test'}
    }

    response = lambda_handler(event, None)
    assert HTTPStatus.OK == response['statusCode']

def test_post_body():
    event = {
        'body': '"test"',
        'rawPath': '/body',
        'requestContext': {
            'http': { 'method': 'POST' },
            'stage': '$default'
        },
    }

    response = lambda_handler(event, None)
    assert HTTPStatus.OK == response['statusCode']

Alternative solutions

Manual validation using TypeAdapter inside each route.

Acknowledgment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status
    Coming soon

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions