diff --git a/docs/features/event-handler/appsync-events.md b/docs/features/event-handler/appsync-events.md index 207dbb0c0..8d220ce92 100644 --- a/docs/features/event-handler/appsync-events.md +++ b/docs/features/event-handler/appsync-events.md @@ -167,15 +167,24 @@ This is useful when you want to for example: You can enable this with the `aggregate` parameter: -!!! note "Aggregate Processing" - When enabling `aggregate`, your handler receives a list of all events, requiring you to manage the response format. Ensure your response includes results for each event in the expected [AppSync Request and Response Format](#appsync-request-and-response-format). - === "Aggregated processing" ```typescript hl_lines="17 32 34" --8<-- "examples/snippets/event-handler/appsync-events/aggregatedProcessing.ts" ``` +When enabling `aggregate`, your handler receives a list of all the events, requiring you to manage the response format. Ensure your response includes results for each event in the expected [AppSync Request and Response Format](#appsync-request-and-response-format). + +If you want to omit one or more events from the response, you can do so by excluding them from the returned array. Likewise, if you want to discard the entire batch and prevent subscribers from receiving it, you can return an empty array. + +=== "Aggregated processing with partial results" + + ```typescript hl_lines="17 19" + --8<-- "examples/snippets/event-handler/appsync-events/aggregatedProcessingWithPartialResults.ts" + ``` + + 1. You can also return an empty array `[]` to discard the entire batch and prevent subscribers from receiving it. + ### Handling errors You can filter or reject events by throwing exceptions in your resolvers or by formatting the payload according to the expected response structure. This instructs AppSync not to propagate that specific message, so subscribers will not receive it. @@ -237,7 +246,7 @@ You can also do content-based authorization for channel by throwing an `Unauthor === "UnauthorizedException" - ```typescript hl_lines="3 14 20" + ```typescript hl_lines="3 14 25-27" --8<-- "examples/snippets/event-handler/appsync-events/unauthorizedException.ts" ``` diff --git a/examples/snippets/event-handler/appsync-events/aggregatedProcessingWithPartialResults.ts b/examples/snippets/event-handler/appsync-events/aggregatedProcessingWithPartialResults.ts new file mode 100644 index 000000000..7178a3ef7 --- /dev/null +++ b/examples/snippets/event-handler/appsync-events/aggregatedProcessingWithPartialResults.ts @@ -0,0 +1,23 @@ +import { AppSyncEventsResolver } from '@aws-lambda-powertools/event-handler/appsync-events'; +import type { AppSyncEventsPublishEvent } from '@aws-lambda-powertools/event-handler/types'; +import type { Context } from 'aws-lambda'; + +const app = new AppSyncEventsResolver(); + +app.onPublish( + '/default/foo/*', + async (events) => { + const payloadsToReturn: AppSyncEventsPublishEvent['events'] = []; + + for (const event of events) { + if (event.payload.includes('foo')) continue; + payloadsToReturn.push(event); + } + + return payloadsToReturn; // (1)! + }, + { aggregate: true } +); + +export const handler = async (event: unknown, context: Context) => + app.resolve(event, context); diff --git a/examples/snippets/event-handler/appsync-events/unauthorizedException.ts b/examples/snippets/event-handler/appsync-events/unauthorizedException.ts index 7c1201299..96f621ad4 100644 --- a/examples/snippets/event-handler/appsync-events/unauthorizedException.ts +++ b/examples/snippets/event-handler/appsync-events/unauthorizedException.ts @@ -14,10 +14,18 @@ app.onPublish('/*', () => { throw new UnauthorizedException('You can only publish to /default/foo'); }); -app.onSubscribe('/default/foo', () => true); +app.onSubscribe('/private/*', async (info) => { + const userGroups = + info.identity?.groups && Array.isArray(info.identity?.groups) + ? info.identity?.groups + : []; + const channelGroup = 'premium-users'; -app.onSubscribe('/*', () => { - throw new UnauthorizedException('You can only subscribe to /default/foo'); + if (!userGroups.includes(channelGroup)) { + throw new UnauthorizedException( + `Subscription requires ${channelGroup} group membership` + ); + } }); export const handler = async (event: unknown, context: Context) => diff --git a/packages/event-handler/src/types/appsync-events.ts b/packages/event-handler/src/types/appsync-events.ts index 7953fbe3e..7c391f331 100644 --- a/packages/event-handler/src/types/appsync-events.ts +++ b/packages/event-handler/src/types/appsync-events.ts @@ -168,12 +168,12 @@ type RouteOptions = { */ type AppSyncEventsEvent = { /** - * The `identity` field is marked as `unknown` because it varies based on the authentication type used in AppSync. + * The `identity` field varies based on the authentication type used for the AppSync API. * When using an API key, it will be `null`. When using IAM, it will contain the AWS credentials of the user. When using Cognito, * it will contain the Cognito user pool information. When using a Lambda authorizer, it will contain the information returned * by the authorizer. */ - identity: unknown; + identity: null | Record; result: null; request: { headers: Record;