v2.28.0
Summary
This release adds support for Data Validation and automatic OpenAPI generation in Event Handler.
Even better, it works with your existing resolver (API Gateway REST/HTTP, ALB, Lambda Function URL, VPC Lattice)!
Did you read that correctly? Yes, you did! Look at this:
Data validation
Docs: Data validation
By adding enable_validation=True
to your resolver constructor, you’ll change the way the resolver works. We will:
- inspect your route handlers to gather input and output types (including Pydantic models and dataclasses)
- validate and coerce the input data for you automatically before invoking your route handlers
- validate and coerce the output data for you automatically after invoking your route handlers
- enable a cool feature (see the next section!)
This moves data validation responsibilities to Event Handler resolvers, reducing a ton of boilerplate code. You can now focus on just writing your business logic, and leave the validation to us!
from typing import List, Optional
import requests
from pydantic import BaseModel, Field
from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext
tracer = Tracer()
logger = Logger()
app = APIGatewayRestResolver(enable_validation=True)
class Todo(BaseModel):
userId: int
id_: Optional[int] = Field(alias="id", default=None)
title: str
completed: bool
@app.post("/todos")
def create_todo(todo: Todo) -> str:
response = requests.post("https://jsonplaceholder.typicode.com/todos", json=todo.dict(by_alias=True))
response.raise_for_status()
return response.json()["id"]
@app.get("/todos")
@tracer.capture_method
def get_todos() -> List[Todo]:
todo = requests.get("https://jsonplaceholder.typicode.com/todos")
todo.raise_for_status()
return todo.json()
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_HTTP)
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict:
return app.resolve(event, context)
OpenAPI generation
Docs: OpenAPI generation
When you enable data validation, we automatically inspect your API in a way that makes it possible to generate OpenAPI specifications automatically!
You can export the OpenAPI spec for customization, manipulation, merging micro-functions, etc., in two ways:
- Pydantic model using
app.get_openapi_schema()
- JSON Schema using
app.get_openapi_json_schema()
Here’s one way to print the schema if you were to run your Python Lambda handler locally:
import requests
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.event_handler.openapi.models import Contact, Server
from aws_lambda_powertools.utilities.typing import LambdaContext
app = APIGatewayRestResolver(enable_validation=True)
@app.get("/todos/<todo_id>")
def get_todo_title(todo_id: int) -> str:
todo = requests.get(f"https://jsonplaceholder.typicode.com/todos/{todo_id}")
todo.raise_for_status()
return todo.json()["title"]
def lambda_handler(event: dict, context: LambdaContext) -> dict:
return app.resolve(event, context)
if __name__ == "__main__":
print(
app.get_openapi_json_schema(
title="TODO's API",
version="1.21.3",
summary="API to manage TODOs",
description="This API implements all the CRUD operations for the TODO app",
tags=["todos"],
servers=[Server(url="https://stg.example.org/orders", description="Staging server")],
contact=Contact(name="John Smith", email="[email protected]"),
),
)
Can you see where this is going? Keep reading :)
Swagger UI
Docs: Swagger UI
Last but not least... you can now enable an embedded Swagger UI to visualize and interact with your newly auto-documented API!
from typing import List, Optional
import requests
from pydantic import BaseModel, Field
from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext
app = APIGatewayRestResolver(enable_validation=True)
app.enable_swagger() # by default, path="/swagger"
@app.get("/todos")
@tracer.capture_method
def get_todos() -> List[Todo]:
todo = requests.get("https://jsonplaceholder.typicode.com/todos")
todo.raise_for_status()
return todo.json()
def lambda_handler(event: dict, context: LambdaContext) -> dict:
return app.resolve(event, context)
The Swagger UI appears by default at the /swagger
path, but you can customize this to serve the documentation from another path, and specify the source for Swagger UI assets.
We can’t wait for you try this new features!
Changes
- fix(event_handler): fix format for OpenAPI path templating (#3399) by @rubenfonseca
- fix(event_handler): allow fine grained Response with data validation (#3394) by @rubenfonseca
- fix(event_handler): apply serialization as the last operation for middlewares (#3392) by @rubenfonseca
🌟New features and non-breaking changes
- feat(event_handler): allow customers to catch request validation errors (#3396) by @rubenfonseca
📜 Documentation updates
- docs(event_handlers): new data validation and OpenAPI feature (#3386) by @rubenfonseca
🐛 Bug and hot fixes
- fix(event_handler): hide error details by default (#3406) by @rubenfonseca
- fix(event_handler): lazy load Pydantic to improve cold start (#3397) by @rubenfonseca
🔧 Maintenance
- chore(deps-dev): bump the boto-typing group with 1 update (#3400) by @dependabot
- chore(deps-dev): bump aws-cdk-lib from 2.110.0 to 2.110.1 (#3402) by @dependabot
- chore(deps): bump datadog-lambda from 4.82.0 to 5.83.0 (#3401) by @dependabot
- chore(deps-dev): bump aws-cdk from 2.110.0 to 2.110.1 (#3403) by @dependabot
- chore(deps-dev): bump pytest-xdist from 3.4.0 to 3.5.0 (#3387) by @dependabot
- chore(deps-dev): bump sentry-sdk from 1.35.0 to 1.36.0 (#3388) by @dependabot
- chore(deps): bump the layer-balancer group in /layer/scripts/layer-balancer with 3 updates (#3389) by @dependabot
This release was made possible by the following contributors:
@dependabot, @dependabot[bot], @github-actions, @github-actions[bot], @heitorlessa, and @rubenfonseca