This utility provides data validation and parsing for Standard Schema, together with a collection of built-in Zod schemas and envelopes to parse and unwrap popular AWS event sources payloads.
You can parse inbound events using parser decorator, Middy.js middleware, or manually using built-in envelopes and schemas.
When using the decorator or middleware, you can specify a schema to parse the event, this can be a built-in Zod schema or a custom schema you defined. Custom schemas can be defined using Zod or any other Standard Schema compatible library.
import{Logger}from'@aws-lambda-powertools/logger';import{parser}from'@aws-lambda-powertools/parser/middleware';importmiddyfrom'@middy/core';import{z}from'zod';constlogger=newLogger();constorderSchema=z.object({id:z.number().positive(),description:z.string(),items:z.array(z.object({id:z.number().positive(),quantity:z.number().positive(),description:z.string(),})),optionalField:z.string().optional(),});exportconsthandler=middy().use(parser({schema:orderSchema})).handler(async(event):Promise<void>=>{for(constitemofevent.items){// item is parsed as OrderItemlogger.info('Processing item',{item});}});
import{Logger}from'@aws-lambda-powertools/logger';import{parser}from'@aws-lambda-powertools/parser/middleware';importmiddyfrom'@middy/core';import{array,number,object,optional,pipe,string,toMinValue,}from'valibot';constlogger=newLogger();constorderSchema=object({id:pipe(number(),toMinValue(0)),description:string(),items:array(object({id:pipe(number(),toMinValue(0)),quantity:pipe(number(),toMinValue(1)),description:string(),})),optionalField:optional(string()),});exportconsthandler=middy().use(parser({schema:orderSchema})).handler(async(event):Promise<void>=>{for(constitemofevent.items){// item is parsed as OrderItemlogger.info('Processing item',{item});}});
Warning
The decorator and middleware will replace the event object with the parsed schema if successful.
Be cautious when using multiple decorators that expect an event to have a specific structure, the order of evaluation for decorators is from the inner to the outermost decorator.
importtype{LambdaInterface}from'@aws-lambda-powertools/commons/types';import{Logger}from'@aws-lambda-powertools/logger';import{parser}from'@aws-lambda-powertools/parser';importtype{Context}from'aws-lambda';import{z}from'zod';constlogger=newLogger();constorderSchema=z.object({id:z.number().positive(),description:z.string(),items:z.array(z.object({id:z.number().positive(),quantity:z.number(),description:z.string(),})),optionalField:z.string().optional(),});typeOrder=z.infer<typeoforderSchema>;classLambdaimplementsLambdaInterface{@parser({schema:orderSchema})publicasynchandler(event:Order,_context:Context):Promise<void>{// event is now typed as Orderfor(constitemofevent.items){logger.info('Processing item',{item});}}}constmyFunction=newLambda();exportconsthandler=myFunction.handler.bind(myFunction);
Parser comes with the following built-in Zod schemas:
Looking for other libraries?
The built-in schemas are defined using Zod, if you would like us to support other libraries like valibot please open an issue and we will consider it based on the community's feedback.
Model name
Description
AlbSchema
Lambda Event Source payload for Amazon Application Load Balancer
APIGatewayProxyEventSchema
Lambda Event Source payload for Amazon API Gateway
APIGatewayRequestAuthorizerEventSchema
Lambda Event Source payload for Amazon API Gateway Request Authorizer
APIGatewayTokenAuthorizerEventSchema
Lambda Event Source payload for Amazon API Gateway Token Authorizer
APIGatewayProxyEventV2Schema
Lambda Event Source payload for Amazon API Gateway v2 payload
APIGatewayProxyWebsocketEventSchema
Lambda Event Source payload for Amazon API Gateway WebSocket events
APIGatewayRequestAuthorizerEventV2Schema
Lambda Event Source payload for Amazon API Gateway v2 Authorizer
AppSyncResolverSchema
Lambda Event Source payload for AWS AppSync GraphQL API resolver
AppSyncBatchResolverSchema
Lambda Event Source payload for AWS AppSync GraphQL API batch resolver
AppSyncEventsPublishSchema
Lambda Event Source payload for AWS AppSync Events API PUBLISH operation
AppSyncEventsSubscribeSchema
Lambda Event Source payload for AWS AppSync Events API SUBSCRIBE operation
CloudFormationCustomResourceCreateSchema
Lambda Event Source payload for AWS CloudFormation CREATE operation
CloudFormationCustomResourceUpdateSchema
Lambda Event Source payload for AWS CloudFormation UPDATE operation
CloudFormationCustomResourceDeleteSchema
Lambda Event Source payload for AWS CloudFormation DELETE operation
CloudwatchLogsSchema
Lambda Event Source payload for Amazon CloudWatch Logs
PreSignupTriggerSchema
Lambda Event Source payload for Amazon Cognito Pre Sign-up trigger
PostConfirmationTriggerSchema
Lambda Event Source payload for Amazon Cognito Post Confirmation trigger
PreTokenGenerationTriggerSchema
Lambda Event Source payload for Amazon Cognito Pre Token Generation trigger
CustomMessageTriggerSchema
Lambda Event Source payload for Amazon Cognito Custom Message trigger
MigrateUserTriggerSchema
Lambda Event Source payload for Amazon Cognito User Migration trigger
CustomSMSTriggerSchema
Lambda Event Source payload for Amazon Cognito Custom SMS trigger
CustomEmailTriggerSchema
Lambda Event Source payload for Amazon Cognito Custom Email trigger
When trying to parse your payload you might encounter the following situations:
Your actual payload is wrapped around a known structure, for example Lambda Event Sources like EventBridge
You're only interested in a portion of the payload, for example parsing the detail of custom events in EventBridge, or body of SQS records
You can either solve these situations by creating a schema of these known structures, parsing them, then extracting and parsing a key where your payload is.
This can become difficult quite quickly. Parser simplifies the development through a feature named Envelope.
Envelopes can be used via envelope parameter available in middy and decorator.
Here's an example of parsing a custom schema in an event coming from EventBridge, where all you want is what's inside the detail key.
import{Logger}from'@aws-lambda-powertools/logger';import{EventBridgeEnvelope}from'@aws-lambda-powertools/parser/envelopes/eventbridge';import{parser}from'@aws-lambda-powertools/parser/middleware';importmiddyfrom'@middy/core';import{z}from'zod';constlogger=newLogger();constorderSchema=z.object({id:z.number().positive(),description:z.string(),items:z.array(z.object({id:z.number().positive(),quantity:z.number(),description:z.string(),})),optionalField:z.string().optional(),});exportconsthandler=middy().use(parser({schema:orderSchema,envelope:EventBridgeEnvelope})).handler(async(event):Promise<void>=>{for(constitemofevent.items){// item is parsed as OrderItemlogger.info('Processing item',{item});}});
importtype{LambdaInterface}from'@aws-lambda-powertools/commons/types';import{Logger}from'@aws-lambda-powertools/logger';import{parser}from'@aws-lambda-powertools/parser';import{EventBridgeEnvelope}from'@aws-lambda-powertools/parser/envelopes/eventbridge';importtype{Context}from'aws-lambda';import{z}from'zod';constlogger=newLogger();constorderSchema=z.object({id:z.number().positive(),description:z.string(),items:z.array(z.object({id:z.number().positive(),quantity:z.number(),description:z.string(),})),optionalField:z.string().optional(),});typeOrder=z.infer<typeoforderSchema>;classLambdaimplementsLambdaInterface{@parser({schema:orderSchema,envelope:EventBridgeEnvelope})// (1)!publicasynchandler(event:Order,_context:Context):Promise<void>{// event is now typed as Orderfor(constitemofevent.items){logger.info('Processing item',item);// (2)!}}}constmyFunction=newLambda();exportconsthandler=myFunction.handler.bind(myFunction);
Pass eventBridgeEnvelope to parser decorator
event is parsed and replaced as Order object
The envelopes are functions that take an event and the schema to parse, and return the result of the inner schema.
Depending on the envelope it can be something simple like extracting a key.
We have also complex envelopes that parse the payload from a string, decode base64, uncompress gzip, etc.
Envelopes vs schema extension
Use envelopes if you want to extract only the inner part of an event payload and don't use the information from the Lambda event.
Otherwise, extend built-in schema to parse the whole payload and use the metadata from the Lambda event.
Parser comes with the following built-in Zod envelopes:
Looking for other libraries?
The built-in schemas are defined using Zod, if you would like us to support other libraries like valibot please open an issue and we will consider it based on the community's feedback.
Envelope name
Behaviour
ApiGatewayEnvelope
1. Parses data using APIGatewayProxyEventSchema. 2. Parses body key using your schema and returns it.
ApiGatewayV2Envelope
1. Parses data using APIGatewayProxyEventV2Schema. 2. Parses body key using your schema and returns it.
CloudWatchEnvelope
1. Parses data using CloudwatchLogsSchema which will base64 decode and decompress it. 2. Parses records in message key using your schema and return them in a list.
DynamoDBStreamEnvelope
1. Parses data using DynamoDBStreamSchema. 2. Parses records in NewImage and OldImage keys using your schema. 3. Returns a list with a dictionary containing NewImage and OldImage keys
EventBridgeEnvelope
1. Parses data using EventBridgeSchema. 2. Parses detail key using your schema and returns it.
KafkaEnvelope
1. Parses data using KafkaRecordSchema. 2. Parses value key using your schema and returns it.
KinesisEnvelope
1. Parses data using KinesisDataStreamSchema which will base64 decode it. 2. Parses records in Records key using your schema and returns them in a list.
KinesisFirehoseEnvelope
1. Parses data using KinesisFirehoseSchema which will base64 decode it. 2. Parses records in Records key using your schema and returns them in a list.
LambdaFunctionUrlEnvelope
1. Parses data using LambdaFunctionUrlSchema. 2. Parses body key using your schema and returns it.
SnsEnvelope
1. Parses data using SnsSchema. 2. Parses records in body key using your schema and return them in a list.
SnsSqsEnvelope
1. Parses data using SqsSchema. 2. Parses SNS records in body key using SnsNotificationSchema. 3. Parses data in Message key using your schema and return them in a list.
SnsEnvelope
1. Parses data using SqsSchema. 2. Parses records in body key using your schema and return them in a list.
VpcLatticeEnvelope
1. Parses data using VpcLatticeSchema. 2. Parses value key using your schema and returns it.
VpcLatticeV2Envelope
1. Parses data using VpcLatticeSchema. 2. Parses value key using your schema and returns it.
If you want to parse the event without throwing an error, use the safeParse option.
The handler event object will be replaced with ParsedResult<Input?, Oputput?>, for example ParsedResult<SqsEvent, Order>, where SqsEvent is the original event and Order is the parsed schema.
The ParsedResult object will have success, data, or error and originalEvent fields, depending on the outcome.
If the parsing is successful, the data field will contain the parsed event, otherwise you can access the error field and the originalEvent to handle the error and recover the original event.
Because Parser uses Zod, you can use all the features of Zod to validate your data.
For example, you can use refine to validate a field or a combination of fields:
1 2 3 4 5 6 7 8 9101112131415161718192021
import{z}from'zod';constorderItemSchema=z.object({id:z.number().positive(),quantity:z.number(),description:z.string(),});exportconstorderSchema=z.object({id:z.number().positive(),description:z.string(),items:z.array(orderItemSchema).refine((items)=>items.length>0,{message:'Order must have at least one item',// (1)!}),optionalField:z.string().optional(),}).refine((order)=>order.id>100&&order.items.length>100,{message:'All orders with more than 100 items must have an id greater than 100',// (2)!});
validate a single field
validate an object with multiple fields
Zod provides a lot of other features and customization, see Zod documentation for more details.
import{Logger}from'@aws-lambda-powertools/logger';import{parser}from'@aws-lambda-powertools/parser/middleware';importmiddyfrom'@middy/core';importtype{Context}from'aws-lambda';import{z}from'zod';constlogger=newLogger();constorderSchema=z.object({id:z.number().positive(),description:z.string(),items:z.array(z.object({id:z.number().positive(),quantity:z.number(),description:z.string(),})),optionalField:z.string().optional(),});typeOrder=z.infer<typeoforderSchema>;// (1)!constlambdaHandler=async(event:Order,// (2)!_context:Context):Promise<void>=>{for(constitemofevent.items){// item is parsed as OrderItemlogger.info('Processing item',{item});// (3)!}};exportconsthandler=middy(lambdaHandler).use(parser({schema:orderSchema}));
Use z.infer to extract the type of the schema, also works for nested schemas
The package @types/aws-lambda is a popular project that contains type definitions for many AWS service event invocations, support for these types is provided on a best effort basis.
We recommend using the types provided by the Parser utility under @aws-powertools/parser/types when using the built-in schemas and envelopes, as they are inferred directly from the Zod schemas and are more accurate.
If you encounter any type compatibility issues with @types/aws-lambda, please submit an issue.
When testing your handler with parser decorator you need to use double assertion to bypass TypeScript type checking in your tests.
This is useful when you want to test the handler for invalid payloads or when you want to test the error handling.
If you are you use middy middleware, you don't need to do this.
importtype{Context}from'aws-lambda';import{describe,expect,it}from'vitest';import{handler}from'./decorator.js';importtype{Order}from'./schema.js';describe('Test handler',()=>{it('should parse event successfully',async()=>{consttestEvent={id:123,description:'test',items:[{id:1,quantity:1,description:'item1',},],};awaitexpect(handler(testEvent,{}asContext)).resolves.toEqual(123);});it('should throw error if event is invalid',async()=>{consttestEvent={foo:'bar'};awaitexpect(handler(testEventasunknownasOrder,// (1)!{}asContext)).rejects.toThrow();});});
Use double assertion as unknown as X to bypass TypeScript type checking in your tests
1 2 3 4 5 6 7 8 91011121314151617181920
importtype{LambdaInterface}from'@aws-lambda-powertools/commons/types';import{Logger}from'@aws-lambda-powertools/logger';import{parser}from'@aws-lambda-powertools/parser';importtype{Context}from'aws-lambda';import{typeOrder,orderSchema}from'./schema.js';constlogger=newLogger();classLambdaimplementsLambdaInterface{@parser({schema:orderSchema})publicasynchandler(event:Order,_context:Context):Promise<number>{logger.info('Processing event',{event});// ... business logicreturnevent.id;}}constmyFunction=newLambda();exportconsthandler=myFunction.handler.bind(myFunction);
importtype{LambdaInterface}from'@aws-lambda-powertools/commons/types';import{Logger}from'@aws-lambda-powertools/logger';import{parser}from'@aws-lambda-powertools/parser';import{EventBridgeEnvelope}from'@aws-lambda-powertools/parser/envelopes/eventbridge';importtype{EventBridgeEvent,ParsedResult,}from'@aws-lambda-powertools/parser/types';importtype{Context}from'aws-lambda';import{typeOrder,orderSchema}from'./schema.js';constlogger=newLogger();classLambdaimplementsLambdaInterface{@parser({schema:orderSchema,envelope:EventBridgeEnvelope,safeParse:true,})publicasynchandler(event:ParsedResult<EventBridgeEvent,Order>,_context:Context):Promise<number>{logger.info('Processing event',{event});if(event.success){// ... business logicreturnevent.data.id;}logger.error('Failed to parse event',{event});thrownewError('Failed to parse event');}}constmyFunction=newLambda();exportconsthandler=myFunction.handler.bind(myFunction);