Skip to content

Feature request: Support types annotated with Field for event_handler validation #5953

Description

@rtandy

Use case

Hi, thank you for working on Powertools.

My Pydantic models are shared between multiple applications. For example, a client application builds an instance of a model and submits it to the API, which validates the request against the same model.

A few types I want to accept as API payloads or parameters are annotated with Field, mainly tagged unions.

I am aware of the Powertools OpenAPI Param annotations, but they have downsides:

  • having to import Powertools into non-Lambda projects;
  • being stuck with a single Param type (i.e. Body, Path, etc) per annotated type, or having to duplicate the arguments for different types

With Powertools 3.5.0, the example code below fails:

  • with def create_action(action: Action): AssertionError: Param: action can only be a request body, use Body()
  • with def create_action(action: Annotated[Action, Body()]): AssertionError: Only one FieldInfo can be used per parameter

It would be nice if event_handler would allow nested Field annotations, so that I can apply Annotated[some_type, Body()] to an existing annotated type such as a tagged union.

Thank you for considering.

Solution/User Experience

class FooAction(BaseModel):
    action: Literal['foo']
    foo: int 

class BarAction(BaseModel):
    action: Literal['bar']
    bar: int 

Action = Annotated[FooAction | BarAction, Field(discriminator='action')]

app = APIGatewayHttpResolver(enable_validation=True)

@app.post('/actions')
def create_action(action: Action): # or Annotated[Action, Body()]
    ...

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

Alternative solutions

  1. use event_handler OpenAPI Param annotations exclusively
Action = Annotated[FooAction | BarAction, Body(discriminator='action')]
  1. use TypeAdapter manually
Action = Annotated[FooAction | BarAction, Field(discriminator='action')]
action_adapter = TypeAdapter(Action)

@app.post('/actions')
def create_action():
    try:
        action = action_adapter.validate_json(app.current_event.body)
    except ValidationError as e:
        raise RequestValidationError(e.errors())

Acknowledgment

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions