Skip to content

v2.28.0

Compare
Choose a tag to compare
@github-actions github-actions released this 23 Nov 16:30
· 489 commits to refs/heads/develop since this release

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:

image (9)

Data validation

Docs: Data validation

By adding enable_validation=True to your resolver constructor, you’ll change the way the resolver works. We will:

  1. inspect your route handlers to gather input and output types (including Pydantic models and dataclasses)
  2. validate and coerce the input data for you automatically before invoking your route handlers
  3. validate and coerce the output data for you automatically after invoking your route handlers
  4. 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="john@smith.com"),
        ),
    )

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.

image (10)

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

🐛 Bug and hot fixes

🔧 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