From d7fccdceacb80bcf2ea41026d0b7c4cfdad77c1f Mon Sep 17 00:00:00 2001
From: Kiro Agent <244629292+kiro-agent@users.noreply.github.com>
Date: Tue, 20 Oct 2026 07:30:10 +0000
Subject: [PATCH 1/4] feat: add createAppSyncBatchHandler for AppSync
BatchInvoke
Add the batched counterpart to createAppSyncHandler. It takes an array of
resolver events, authenticates once per batch off the first event, and returns
R[] in source order. The context carries both ctx.event (events[0]) and the
full ctx.events array.
Factor the typed-error normalisation and envelope construction out of
createAppSyncHandler into shared toTypedError/buildErrorEnvelope helpers so both
handlers use the identical error model. createAppSyncHandler behavior is
unchanged. With APPSYNC_TYPED_ERRORS=true the batch handler returns one error
envelope per event; otherwise it rethrows.
---
llm.md | 10 +++
src/lambda/handler.ts | 169 +++++++++++++++++++++++++++++++++---------
2 files changed, 144 insertions(+), 35 deletions(-)
diff --git a/llm.md b/llm.md
index e8fce70..43414dc 100644
--- a/llm.md
+++ b/llm.md
@@ -182,6 +182,16 @@ export const handler = createAppSyncHandler(async
});
```
+For AppSync BatchInvoke, use `createAppSyncBatchHandler`. It takes an array of resolver events and returns an array of results in the same order (array in, array out, order preserved). It uses the same context as `createAppSyncHandler`, with the logger and the Cognito authorizer resolved once per batch off the first event. The context exposes both the first event as `ctx.event` (so handler code that reads `ctx.event.arguments` / `ctx.event.identity` keeps working) and the full batch as `ctx.events`. The typed-error model is identical to `createAppSyncHandler`: with `APPSYNC_TYPED_ERRORS === 'true'` a thrown `errors.appsync.*` or `errors.HttpError` returns an array of error envelopes aligned to the batch length, and otherwise rethrows. A plain `Error` always fails the invocation.
+
+```typescript
+import { createAppSyncBatchHandler } from 'cdk-serverless/lambda';
+
+export const handler = createAppSyncBatchHandler(async (ctx) => {
+ return Promise.all(ctx.events.map((event) => getItem(event.arguments.id)));
+});
+```
+
AppSync resolvers can throw typed errors from the `errors.appsync` namespace. `createAppSyncHandler` catches them and logs at `warn`. Whether it returns a `{ data, errorType, errorMessage, errorInfo }` envelope or rethrows is gated on the `APPSYNC_TYPED_ERRORS` environment variable. When `APPSYNC_TYPED_ERRORS === 'true'` the handler returns the envelope so the invocation stays off the Lambda Errors metric. Otherwise it rethrows the typed error, logging at `error`, so the invocation fails. A plain `Error` always fails the invocation regardless of the flag.
```typescript
diff --git a/src/lambda/handler.ts b/src/lambda/handler.ts
index d640bf5..bc2aba6 100644
--- a/src/lambda/handler.ts
+++ b/src/lambda/handler.ts
@@ -283,6 +283,58 @@ function httpStatusToErrorType(statusCode: number): string {
}
}
+/**
+ * The typed-error shape shared by createAppSyncHandler and createAppSyncBatchHandler.
+ */
+interface TypedAppSyncError {
+ errorType: string;
+ message: string;
+ errorInfo?: Record;
+}
+
+/**
+ * Normalises the two recognised typed-error shapes to a common
+ * { errorType, message, errorInfo } so the gate, envelope and rethrow are a
+ * single code path across the single and batch handlers. Returns undefined for
+ * anything that is neither (plain Error, Boom), which the callers rethrow.
+ *
+ * - appsyncErrors.AppSyncError carries its own GraphQL errorType and an optional
+ * errorInfo, which flow through unchanged.
+ * - errors.HttpError (the HTTP base thrown by the shared JwtAuthorizer via
+ * assertAuthenticated/assertGroup/assertAdmin, and by resolver code directly)
+ * has no GraphQL errorType, so map its statusCode with httpStatusToErrorType.
+ * HttpError carries no errorInfo, so errorInfo is undefined.
+ *
+ * The two instanceof checks are disjoint: HttpError and AppSyncError share no
+ * ancestry, so an appsync.ForbiddenError takes the AppSyncError branch and an
+ * errors.ForbiddenError the HttpError branch.
+ */
+function toTypedError(error: any): TypedAppSyncError | undefined {
+ if (error instanceof appsyncErrors.AppSyncError) {
+ return { errorType: error.errorType, message: error.message, errorInfo: error.errorInfo };
+ } else if (error instanceof errors.HttpError) {
+ return { errorType: httpStatusToErrorType(error.statusCode), message: error.message, errorInfo: undefined };
+ }
+ return undefined;
+}
+
+/**
+ * Builds the direct-Lambda error envelope AppSync surfaces as a typed GraphQL
+ * error. __appSyncError is a reserved sentinel key the resolver response handler
+ * keys on to recognise this envelope. Branching on the sentinel (rather than on
+ * a bare errorMessage) means a legitimate resolver result that merely contains
+ * an errorMessage field is not misclassified as a typed error.
+ */
+function buildErrorEnvelope(typed: TypedAppSyncError): R {
+ return {
+ __appSyncError: true,
+ data: null,
+ errorType: typed.errorType,
+ errorMessage: typed.message,
+ errorInfo: typed.errorInfo,
+ } as unknown as R;
+}
+
/**
* Creates an AppSync resolver handler from the given AppSyncHandler.
* Returns a function that can be used as an AppSync resolver.
@@ -313,28 +365,7 @@ export const createAppSyncHandler =
// invoke the handler function with the context
return await handler(ctx);
} catch (error: any) {
- // Normalise the two recognised typed-error shapes to a common
- // { errorType, message, errorInfo } so the gate, envelope and rethrow
- // below are a single code path.
- //
- // - appsyncErrors.AppSyncError carries its own GraphQL errorType and an
- // optional errorInfo, which flow through unchanged.
- // - errors.HttpError (the HTTP base thrown by the shared JwtAuthorizer
- // via assertAuthenticated/assertGroup/assertAdmin, and by resolver
- // code directly) has no GraphQL errorType, so map its statusCode with
- // httpStatusToErrorType. HttpError carries no errorInfo, so errorInfo
- // is undefined.
- //
- // The two instanceof checks are disjoint: HttpError and AppSyncError
- // share no ancestry, so an appsync.ForbiddenError takes the AppSyncError
- // branch and an errors.ForbiddenError the HttpError branch. Anything that
- // is neither (plain Error, Boom) leaves typed undefined and rethrows.
- let typed: { errorType: string; message: string; errorInfo?: Record } | undefined;
- if (error instanceof appsyncErrors.AppSyncError) {
- typed = { errorType: error.errorType, message: error.message, errorInfo: error.errorInfo };
- } else if (error instanceof errors.HttpError) {
- typed = { errorType: httpStatusToErrorType(error.statusCode), message: error.message, errorInfo: undefined };
- }
+ const typed = toTypedError(error);
if (typed && process.env.APPSYNC_TYPED_ERRORS === 'true') {
// The envelope-return is gated on APPSYNC_TYPED_ERRORS === 'true'.
@@ -352,20 +383,88 @@ export const createAppSyncHandler =
// exact string 'true' means rethrow. This is why a default UNIT
// resolver whose handler hits an auth assertion (an HttpError) still
// fails loudly unless typedErrors is active.
- //
- // __appSyncError is a reserved sentinel key the resolver response
- // handler keys on to recognise this envelope. Branching on the sentinel
- // (rather than on a bare errorMessage) means a legitimate resolver result
- // that merely contains an errorMessage field is not misclassified as a
- // typed error.
ctx.logger.warn(typed.message, { errorType: typed.errorType, errorInfo: typed.errorInfo });
- return {
- __appSyncError: true,
- data: null,
- errorType: typed.errorType,
- errorMessage: typed.message,
- errorInfo: typed.errorInfo,
- } as unknown as R;
+ return buildErrorEnvelope(typed);
+ }
+ // log the error and throw it again
+ ctx.logger.error(error);
+ throw error;
+ }
+ };
+ };
+
+/**
+ * The context for a batched AppSync resolver function.
+ * Extends AppSyncHandlerContext so handler code that reads ctx.event.arguments /
+ * ctx.event.identity keeps working against the first event, and additionally
+ * exposes the full batch of events so the handler can map over it.
+ */
+export interface AppSyncBatchHandlerContext | null = Record | null> extends AppSyncHandlerContext {
+ event: AWSLambda.AppSyncResolverEvent;
+ events: AWSLambda.AppSyncResolverEvent[];
+}
+
+/**
+ * A function that handles an AppSync BatchInvoke event.
+ * Receives the batch context and returns the responses in source order.
+ */
+export type AppSyncBatchHandler | null = Record | null> = (
+ context: AppSyncBatchHandlerContext,
+) => Promise;
+
+/**
+ * Creates a batched AppSync resolver handler from the given AppSyncBatchHandler.
+ * Returns a function that can be used as an AppSync BatchInvoke resolver: array
+ * in, array out, order preserved.
+ *
+ * It mirrors createAppSyncHandler's context and auth plumbing but operates on an
+ * array of events. Authentication runs once per batch off the first event, and
+ * the context carries both the first event (ctx.event = events[0]) and the full
+ * ctx.events array. The handler returns R[] in the same order as the input events.
+ *
+ * @param handler The AppSyncBatchHandler to use as the resolver.
+ */
+export const createAppSyncBatchHandler =
+ | null = Record | null>(
+ handler: AppSyncBatchHandler,
+ ): AWSLambda.AppSyncBatchResolverHandler => {
+ return async (events, context) => {
+ // BatchInvoke always delivers a non-empty array; authenticate and build
+ // the context off the first event, exactly like createAppSyncHandler.
+ const first = events[0];
+ const ctx: AppSyncBatchHandlerContext = {
+ event: first,
+ events,
+ lambdaContext: context,
+ logger: logger as unknown as logger.LambdaLog,
+ cognitoAuth: new AppSyncCognitoAuthorizer(first),
+ };
+
+ // set the meta information in logger
+ ctx.logger.options.meta.requestId = context.awsRequestId;
+ // set the debug flag for logger
+ ctx.logger.options.debug = process.env.DEBUG === 'true';
+
+ // log the received batch of events
+ ctx.logger.debug(JSON.stringify(events));
+
+ try {
+ // authenticate once per batch off the first event
+ await ctx.cognitoAuth.authenticate();
+ // invoke the handler function with the batch context; it returns R[] in source order
+ return await handler(ctx);
+ } catch (error: any) {
+ const typed = toTypedError(error);
+
+ if (typed && process.env.APPSYNC_TYPED_ERRORS === 'true') {
+ // Same gate and envelope as createAppSyncHandler. AppSync expects one
+ // result per event in a BatchInvoke response, so a batch-level typed
+ // error returns an array of envelopes aligned to the batch length;
+ // each item surfaces the same typed error. Returning (not throwing)
+ // keeps the invocation off the Lambda Errors metric. Without the flag
+ // the typed error falls through to the rethrow below.
+ ctx.logger.warn(typed.message, { errorType: typed.errorType, errorInfo: typed.errorInfo });
+ return events.map(() => buildErrorEnvelope(typed));
}
// log the error and throw it again
ctx.logger.error(error);
From 0b0a9a4779389d3bb16e1131a4b74ceabba3d8b6 Mon Sep 17 00:00:00 2001
From: Kiro Agent <244629292+kiro-agent@users.noreply.github.com>
Date: Tue, 20 Oct 2026 07:32:34 +0000
Subject: [PATCH 2/4] feat: add maxBatchSize option to
GraphQlApi.addLambdaResolver for AppSync BatchInvoke
---
src/constructs/graphql.ts | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/src/constructs/graphql.ts b/src/constructs/graphql.ts
index a08e0c2..fd4204b 100644
--- a/src/constructs/graphql.ts
+++ b/src/constructs/graphql.ts
@@ -50,6 +50,25 @@ export interface GraphQlApiProps extends BaseApiProps {
typedErrors?: boolean;
}
+export interface LambdaResolverOptions {
+ /**
+ * If set, addLambdaResolver wires an AppSync BatchInvoke resolver instead of a
+ * single invoke. The generated UNIT resolver gets MaxBatchSize set to this
+ * value, a BatchInvoke request template
+ * (MappingTemplate.lambdaRequest('$utils.toJson($context)', 'BatchInvoke')) and
+ * a MappingTemplate.lambdaResult() response template, so AppSync groups up to
+ * this many field invocations into one Lambda call. Pair this with
+ * createAppSyncBatchHandler, whose handler receives the batched events.
+ *
+ * This option applies only to the default direct-Lambda UNIT path. It is not
+ * compatible with `typedErrors` (the APPSYNC_JS pipeline resolver), which does
+ * not use these BatchInvoke mapping templates.
+ *
+ * @default - undefined (single invoke, the pre-batch behaviour; no MaxBatchSize and no mapping templates)
+ */
+ readonly maxBatchSize?: number;
+}
+
export interface VtlResolverOptions {
/**
* The datasource the VTL resolver targets
@@ -307,7 +326,15 @@ export class GraphQlApi extends BaseApi {
public addLambdaResolver>(
typeName: TYPE,
fieldName: keyof FIELDTYPE,
+ options?: LambdaResolverOptions,
): LambdaFunction {
+ // BatchInvoke mapping templates belong to the direct-Lambda UNIT resolver and
+ // have no equivalent on the APPSYNC_JS pipeline resolver built for typedErrors,
+ // so the two cannot be combined. Fail fast rather than silently ignore one.
+ if (options?.maxBatchSize !== undefined && this.props.typedErrors) {
+ throw new Error('maxBatchSize is not supported together with typedErrors');
+ }
+
const operationId = `${typeName as string}.${fieldName as String}`;
const description = `Type ${typeName as string} Field ${fieldName as String} Resolver`;
@@ -359,11 +386,23 @@ export class GraphQlApi extends BaseApi {
// source set directly. No response handler, so the error envelope from
// createAppSyncHandler would be surfaced as field data rather than a
// GraphQL error. Opt in via `typedErrors: true` to get the pipeline below.
+ //
+ // When maxBatchSize is set, this stays a UNIT resolver but gets the
+ // BatchInvoke mapping templates and MaxBatchSize, so AppSync batches field
+ // invocations into a single Lambda call handled by createAppSyncBatchHandler.
+ // The L2 BaseResolverProps.maxBatchSize sets MaxBatchSize directly, so no
+ // escape hatch is needed. Leaving the option unset keeps the exact prior
+ // single-invoke shape (no MaxBatchSize, no mapping templates).
new aws_appsync.Resolver(scope, `Resolver${operationId}`, {
api: this.api,
typeName: typeName as string,
fieldName: fieldName as string,
dataSource,
+ ...options?.maxBatchSize !== undefined && {
+ maxBatchSize: options.maxBatchSize,
+ requestMappingTemplate: aws_appsync.MappingTemplate.lambdaRequest('$utils.toJson($context)', 'BatchInvoke'),
+ responseMappingTemplate: aws_appsync.MappingTemplate.lambdaResult(),
+ },
});
return fn;
}
From ce3a6c4be219b46f4d1056d28eb00a4e2ce011dc Mon Sep 17 00:00:00 2001
From: Kiro Agent <244629292+kiro-agent@users.noreply.github.com>
Date: Tue, 20 Oct 2026 07:36:48 +0000
Subject: [PATCH 3/4] test: cover createAppSyncBatchHandler and maxBatchSize
resolver wiring
---
docs/constructs/assets/hierarchy.js | 2 +-
docs/constructs/assets/navigation.js | 2 +-
docs/constructs/assets/search.js | 2 +-
docs/constructs/classes/GraphQlApi.html | 7 +-
docs/constructs/classes/McpAuth.html | 2 +-
docs/constructs/classes/McpCognitoAuth.html | 2 +-
docs/constructs/classes/RestApi.html | 2 +-
.../classes/SingleTableDatastore.html | 2 +-
docs/constructs/classes/Workflow.html | 2 +-
docs/constructs/hierarchy.html | 10 +-
.../interfaces/LambdaResolverOptions.html | 68 ++++++
docs/constructs/interfaces/RestApiProps.html | 2 +-
docs/constructs/modules.html | 4 +-
docs/lambda/assets/hierarchy.js | 2 +-
docs/lambda/assets/navigation.js | 2 +-
docs/lambda/assets/search.js | 2 +-
.../classes/errors.BadRequestError.html | 2 +-
.../lambda/classes/errors.ForbiddenError.html | 2 +-
docs/lambda/classes/errors.HttpError.html | 2 +-
docs/lambda/classes/errors.NotFoundError.html | 2 +-
.../classes/errors.UnauthenticatedError.html | 2 +-
.../classes/errors.appsync.AppSyncError.html | 2 +-
.../classes/errors.appsync.ConflictError.html | 2 +-
.../errors.appsync.ForbiddenError.html | 2 +-
.../classes/errors.appsync.NotFoundError.html | 2 +-
.../errors.appsync.ValidationError.html | 2 +-
.../api.createAppSyncBatchHandler.html | 57 +++++
docs/lambda/hierarchy.html | 24 ++-
.../api.AppSyncBatchHandlerContext.html | 89 ++++++++
.../interfaces/api.AppSyncHandlerContext.html | 6 +
docs/lambda/modules/api.html | 12 +-
.../lambda/types/api.AppSyncBatchHandler.html | 53 +++++
test/constructs/graphql.test.ts | 69 ++++++
test/lambda/appsync-batch-handler.test.ts | 196 ++++++++++++++++++
34 files changed, 591 insertions(+), 48 deletions(-)
create mode 100644 docs/constructs/interfaces/LambdaResolverOptions.html
create mode 100644 docs/lambda/functions/api.createAppSyncBatchHandler.html
create mode 100644 docs/lambda/interfaces/api.AppSyncBatchHandlerContext.html
create mode 100644 docs/lambda/types/api.AppSyncBatchHandler.html
create mode 100644 test/lambda/appsync-batch-handler.test.ts
diff --git a/docs/constructs/assets/hierarchy.js b/docs/constructs/assets/hierarchy.js
index 6bb347a..6691c6e 100644
--- a/docs/constructs/assets/hierarchy.js
+++ b/docs/constructs/assets/hierarchy.js
@@ -1 +1 @@
-window.hierarchyData = "eJyVkztvwyAUhf/LnUnjQrANW9JKVbe+tigDtUmMSiACMkX+7xVp2tLG8mNhgHPvOR9cTuCsDR74umSoIAhjVJByg8DJrZZVUNZ44CfAOK5G7CVweLyzO6OCXR5DI01QlYg6QPChTA0c0xzB0WngoEyQbisq6efdRTdN2GtAUGnhPXAIvp7FLrOfynjYKF07aYCvF2zTIliwJE1/mFtcfoc5e0g/nxbka6NFUJDEdCW8XB7Uk7MHPwCeSqfiEspQntHIXLJr+z7Ki2SA668by1BOcHQjNLV7cOLQPOuRwP/UI5ijIcs6DfsQf1XDr5dnNOn/In0YSZNKx6HkBF9b9XFcJGNGsEy/4asyOy3fxLuW9yIIH6yTQ7+wq2bqVBb0PCMFTTl7w3RATwpyuYG2/QTETYzO"
\ No newline at end of file
+window.hierarchyData = "eJyVkztvwyAUhf/LnUmTYGMbtrSVqm59bVEGapMYlYAFZIr83ytSt6WN5cfCAOfecz64nMEa4x2wbUFRniCMUZ6udwis2CtRemm0A3YGjMOq+VEAg8c7c9DSm83J10J7WfKgAwQfUlfAMMkQnKwCBlJ7Yfe8FG7ZX3RT+6MCBKXizgED76pF6LL4qQyHtVSVFRrYNqW7FkFKozTDYda4+A5z8RBuOS/I10aLIE8i01vuxKaRT9Y0bgQ8ls7FTQhF2aoIzAW9th+i7CQjXH/dKEZZQoJbQmK7B8ub+llNBP6nnsAcDCnuNRxC/FWNv162KqL+L8L5iTSxdBpKlpBrqyGOTjJhBNN1/A1fpT4o8cbflbjnnjtvrBj7hX01c6cyJ5cZyUnMORimB3pWkO4G2vYTyU+M2A=="
\ No newline at end of file
diff --git a/docs/constructs/assets/navigation.js b/docs/constructs/assets/navigation.js
index 5233b22..0f9b791 100644
--- a/docs/constructs/assets/navigation.js
+++ b/docs/constructs/assets/navigation.js
@@ -1 +1 @@
-window.navigationData = "eJyNlU1PAjEQQP9Lz0SFBD+4IUYi0ahI9GA8lKXsNpR20w6iMfx3o9mFLp3O9jxvXqftTPv+w0B8ARuwoXMCRgvNOqzkULAByxR3TrjTOnJSwFqxDltJvWCDbu9y19lnX3MnhqUMk6sAlTsyuZZghhsohAaZcZAGKQPFKO/Y8rJ4VmhZhxhluOfr+YLfbnSGl9SMU6aHrPwrPFRUgZZcb++owotTpqlwgB5HFaByX6TOlZjxuRI3HLgDY0UowijK+mbsaqnMNjTVESq77swna0p3UEgNwi555vXuP9FU9frnYQPHTT5AidA2jWvjOLXIoX3j5iOG0t21jKBnxVFSPtlCijjASCndjr63vSWb6ombCmfUp7CP5V8Z+OkGFKVsvhPxK0O4du3M8kzqnCoWAylx9ShVV02ZUTJBXe+RtO6hBOFYaGFlllBrk0xQJzjTZfHL94EWkTeDpO+Yo7TVFxD3+QAlwuYtbo3SqUsIJ3P8RQkoSvkKKmXsQ4yS1n9YfPsNon3Wg9Lgu9zPN17Q2dVFt9/bffwCDG1v9A=="
\ No newline at end of file
+window.navigationData = "eJyNld9PwjAQx/+XPhMVEvzBG2IkEo2KRB+MD2WUrWG0S3uIxvC/G80GHb1e+3yf++y77q57/2EgvoAN2NBaAaOFYh1WcSjYgGUlt1bY06ZyUsC6ZB22kmrBBt3e5a6z777mVgwr6TfXBap3pHMlQQ83UAgFMuMgNRIDxSjv2PCqeC7RWIcaZbjn6/mC325Uhkdq1ynTQ1b9BfcVdSHS67w7qnDqlGkqLKDHUReo3hep8lLM+LwUNxy4BW2EL8IoyvqmzWpZ6q1vaipUdzOZT0ZX9qCQCoRZ8syZ3X+irer1z/0BDptcgBKhYxrWhnHqIYfxDZuPGEp3F1lBx4qjpHyyhRSxh5FSehxdb3wk2+qJnQqry09hHqu/GPjpehSlbN8T4U+GcHFtSlqUjKtnhmdS5XFzG6TE9X1XTxFlRskEdXN8pHUPJQjHQgkjs4SsbTJBneBMl4XnygUiIme9Sd8xR2nrv0vY5wKUCFvlsDVIpz5CWJnjl5VHUcpXKFN21McoafN7DL9+i4jvuhcNvqv9fuOBzq4uuv3e7uMXTxiQWw=="
\ No newline at end of file
diff --git a/docs/constructs/assets/search.js b/docs/constructs/assets/search.js
index 0c1556c..2f7d02e 100644
--- a/docs/constructs/assets/search.js
+++ b/docs/constructs/assets/search.js
@@ -1 +1 @@
-window.searchData = "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";
\ No newline at end of file
+window.searchData = "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";
\ No newline at end of file
diff --git a/docs/constructs/classes/GraphQlApi.html b/docs/constructs/classes/GraphQlApi.html
index 045dcb9..a5121cb 100644
--- a/docs/constructs/classes/GraphQlApi.html
+++ b/docs/constructs/classes/GraphQlApi.html
@@ -27,7 +27,7 @@
If set, addLambdaResolver wires an AppSync BatchInvoke resolver instead of a
+single invoke. The generated UNIT resolver gets MaxBatchSize set to this
+value, a BatchInvoke request template
+(MappingTemplate.lambdaRequest('$utils.toJson($context)', 'BatchInvoke')) and
+a MappingTemplate.lambdaResult() response template, so AppSync groups up to
+this many field invocations into one Lambda call. Pair this with
+createAppSyncBatchHandler, whose handler receives the batched events.
+
This option applies only to the default direct-Lambda UNIT path. It is not
+compatible with typedErrors (the APPSYNC_JS pipeline resolver), which does
+not use these BatchInvoke mapping templates.
diff --git a/docs/lambda/assets/hierarchy.js b/docs/lambda/assets/hierarchy.js
index 520fc01..60c556b 100644
--- a/docs/lambda/assets/hierarchy.js
+++ b/docs/lambda/assets/hierarchy.js
@@ -1 +1 @@
-window.hierarchyData = "eJytls1ymzAUhd9Fa8VBSOJvl3SadrpIO+20WXSyUEGuNcUSkUQzbsbv3hE2jLBNADsbFnDPPZ8uR4IXoJWyBmQ/CU4gpgiGMEyTRwg0X5Y8t0JJA7IXELqLZGsOMvDp2d7UdqW0+Mc1gOCPkAXIUJhAUOsSZCAvmTHcXLParha96sXKrksAdxUgA9YUV05+tbsBQb4SZaG5dEQhjBOIUPq4hYD4AO/UbymsmgFxpJgDEuIGIU48hJtKfGCWP7PNXzRvHoPKOUiINkgIpaeZwrOZwvOZ0h0THWBC81/bq+oRNoeSDo3nIpRj9ThKiPso1beNzM+hOC2cAJD68f1ccc3c5u4cQxq1jkJarpcsd6aVWHS1gyadoB8IHBAXCByQU84Pwq6+8qeaG3uris0ckAPpBC6HQQMPg2uttOlMSWu5VkVdcnO9ez7Y2XUxVdcZeZ0/Wlu9d+rXXua+fVc7Z5/hKIU4iSAJMCRh0Iw48tN1y4r9dKZyHCjG04STyDP8Ll04ubQiZ5YXU11PycatSYA96zulf4mi4HKqaV8wOvdaiqea37M1/8I0l82nEtNg90nyA3Wv7J2q5eTF9+ovwsCxh8GqymxkPhrsfd20gBOcHB9eUxfaOvmyWb8BNIEkjiFJI0gRbZZMk0si0BK9TRQgwXEDFccXxKFlepNYdEipv0t/sFIUzfk5F+pAOb5HKaK93zW5LEU++TRqbXu6MdPt9j+W+qIN"
\ No newline at end of file
+window.hierarchyData = "eJytls1ymzAUhd9Fa8VBfwZ5F2eaZrpIO+20XXSyUEEummKJCNHUzfjdO2DDgI2DsLPxAt+j8+lyrtALsMa4Aix+UMYhIQSSEEMMMY8eIbBylcnYKaMLsHgBuPrRYi3BAnx4djelS41V/6QFEPxWOgELhCMISpuBBYgzURSyuBalS2e96lnq1hmAuwqwAK5Irir51e4BBHGqssRKXVFhGEYQIf64hYB2AW7NL62cmQBxpJgCgkmNEEYdhJtcvRdOPovNHzStHyeVU5AQq5EQ4sNM+GwmfD4T3zGxE0xo+mt7VT3CVqHwU+25COVYPY6CSR8l/7LR8TkUw0IPAN6N78dcWlENd+uI2bxxVNpJuxJxZZqrWVt70qQV9ANBAloFggR0yPm7culn+VTKwi1NspkCciD14KowCDl+A/dCJ5m0t0Y7+dd5MAzqJjeGBXVjWHBMtBQuTs/FGhB7NidEHRRprbFFa0sb07VJykwW17v/T65crVLk7crdk/veufxdpX4t6fvl29ophxDhAaRBCCmmkFJUt5l327wUyT46vhwHivFRo0HYMfyqq8mV2qlYOJn4ug7JPKxxd9bujP2pkkRqX9O+YLTvpVZPpXwQa/lJWKnruwQJ66ZT2g3Ug3F3ptTem+/VX4TBuqeeyPNio+PRYO/r/AJO2cDJ7rvRxqkrm3RHCjmkPIIMhZCReb3lkF8SgYbobaIAKYtqqN7XZ2ocGqY3iUWDxFB3Sr+JTCX1x2Uq1IFyfEYZmffusnqVqdj7NGpse7ox0+32P99OBF0="
\ No newline at end of file
diff --git a/docs/lambda/assets/navigation.js b/docs/lambda/assets/navigation.js
index 93b66ee..3bdc0d2 100644
--- a/docs/lambda/assets/navigation.js
+++ b/docs/lambda/assets/navigation.js
@@ -1 +1 @@
-window.navigationData = "eJytlk1z0zAQhv+LzhloPP2A3NIOpe2hZcoAh04PqrTBGtyVkNcUw/DfmaSJY9myvKZcrXef/ZZ191sQ/CSxENIZMRNOUi4W4tHqqoDytXTmVU6PhZiJbwa1WBzOhMpNoT2gWNw1xkvnPtaoLiTqAvyZxc33BmeQwK+k2hKj6tBPdnT8Z9bgL4gck92XjoFvoXQWS+CQO9oU+saBl2QsDgIbBQvzxVB+C98rKOnU6nqc2jFIOVl+uHwvCZ5k/WO+Ld6eT7Xb9a0v61AP3p7Mj7I2OWh1FBooxnit9sZgreMxkvIgCYbiW1Wo1kV8xsa0If/4sIeOhhrjDgYdgd44wKUzLG6onYgeHLdxT8nBm+r42u527gUh7CG9YO5b4ciK8sgdWFHOvARNsx5n9isassuKcuvNr3arVCHLcsdN2oRe59mbYLH2hldPNMlRoGc6yf4ho74N19nEjLIJGW12mJ9MXJ5ywWVPgnIKMlKE9qSD99aX/Vl//s6adulcWaMaZGzPpzwf3q0t+8l1gG1xug+4KowiHjVQp7Dn1j8YrQF53FCeAl9bOrcVah43UKewn2Vh9OZBwAN39Ok5OpV6e82m4R3df6gvv67r32ua1She3h52Wz7hemcByShJMEKNiWONuf8Ld5QnIA=="
\ No newline at end of file
+window.navigationData = "eJytlk1T2zAQhv+LzpnSeIBCbglTSnuADp3CgeEgpA3W1EhCXhfcDv+dSUgcy5blVenVevd5vV+Wb/4yhGdkM8atYhNmOeZsxh6MrAoo97hVH3J8KNiE/VJastn+hIlcFdKBZrObJnhu7Y9aiwVHkZ9xLQtwJ0avDxum0ghuycUGOxziO2YHhy+TrlGaBx1/hmiJ7L50DHwJpTW6BAq5o42hLyw4jsroQWCjIGGuFeaX8FhBiQsj63FqJyDavu9fv3CEJ17/nm6Kt+Njbbd968s61I/Hn6YHWX8w2uMUJPdlRPI4lMhrDU4I1joeIwkHHCGa+bLSYtWjN/ZggO90uD9kksKnooP1CHEHKxOAXljQc6tIXF+biB7clnGn6N6kGp+b7SfjHa+wg/Re5rb1OrzCPHBXVJgTLwvVbPeJudcKzbzC3Dj1p90qUfCy3HKjMb7rNDvytncX+O0Jk4w8PdEk+4eM+jFUs8SMsoSM1jtMTyYsj1lQ2UlQSkFGitCedHDOuLI/62/PSdPOrS1rLQYZm/OU36zPq8h+ch1gWxzvg14WSiCN6qlj2FPj7pSUoGlcXx4Dnxs8NZWWNK6njmGveKHk+n+GBu7o43O04HLzmY3DO7r/UF96XVfXa5zVKN7fHnJbfurVzoJGJTjCCDUkDjXm9hXbo47Z"
\ No newline at end of file
diff --git a/docs/lambda/assets/search.js b/docs/lambda/assets/search.js
index 37beb96..88ac67d 100644
--- a/docs/lambda/assets/search.js
+++ b/docs/lambda/assets/search.js
@@ -1 +1 @@
-window.searchData = "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";
\ No newline at end of file
+window.searchData = "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";
\ No newline at end of file
diff --git a/docs/lambda/classes/errors.BadRequestError.html b/docs/lambda/classes/errors.BadRequestError.html
index 48db485..25a9354 100644
--- a/docs/lambda/classes/errors.BadRequestError.html
+++ b/docs/lambda/classes/errors.BadRequestError.html
@@ -14,7 +14,7 @@
Creates a batched AppSync resolver handler from the given AppSyncBatchHandler.
+Returns a function that can be used as an AppSync BatchInvoke resolver: array
+in, array out, order preserved.
+
It mirrors createAppSyncHandler's context and auth plumbing but operates on an
+array of events. Authentication runs once per batch off the first event, and
+the context carries both the first event (ctx.event = events[0]) and the full
+ctx.events array. The handler returns R[] in the same order as the input events.
The context for a batched AppSync resolver function.
+Extends AppSyncHandlerContext so handler code that reads ctx.event.arguments /
+ctx.event.identity keeps working against the first event, and additionally
+exposes the full batch of events so the handler can map over it.
diff --git a/llm.md b/llm.md
index 43414dc..3847b34 100644
--- a/llm.md
+++ b/llm.md
@@ -216,6 +216,8 @@ The response handler recognises the envelope by a reserved `__appSyncError` sent
Opting in with `typedErrors`: by default `addLambdaResolver` synthesizes a plain direct-Lambda UNIT resolver (the pre-#385 shape), so upgrading consumers who do not opt in see no resolver topology change and no `cdk diff` surprise. Set `typedErrors: true` on the `GraphQlApi` to get the typed `errors.appsync.*` behavior. With the flag enabled, each Lambda-backed field gains a new `AWS::AppSync::FunctionConfiguration` (`LambdaFn${type}.${field}`), and the resolver flips from a `dataSource` UNIT resolver to a `pipelineConfig` + `code` PIPELINE resolver with the response handler described above. The data source and resolver logical IDs are unchanged, so the resolver updates in place rather than being replaced, while the new per-field function resource is additive. The flag applies to all Lambda resolvers on the API, so run `cdk diff` after enabling it to review the topology change.
+`maxBatchSize` wins over `typedErrors` per field. When a field passes `maxBatchSize` to `addLambdaResolver`, that field always gets the UNIT BatchInvoke resolver (MaxBatchSize plus the BatchInvoke request template and the `lambdaResult` response template), even when the API has `typedErrors: true`. The batch field gets no APPSYNC_JS pipeline, no `AWS::AppSync::FunctionConfiguration`, and no `APPSYNC_TYPED_ERRORS` env var on its Lambda, so it synthesizes identically whether or not the API enables `typedErrors`. The trade-off is that typed errors thrown by a batch handler are not converted to GraphQL errors. They rethrow and fail the invocation, so do not rely on the typed-error-to-GraphQL-error conversion in a batch handler. Non-batch fields on the same API keep the `typedErrors` pipeline behavior described above.
+
`APPSYNC_TYPED_ERRORS` is the coupling mechanism between the handler and the pipeline. `createAppSyncHandler` returns the `{ __appSyncError: true, ... }` sentinel envelope only when `APPSYNC_TYPED_ERRORS === 'true'` is set in the Lambda environment, and rethrows the `errors.appsync.*` error otherwise. `GraphQlApi.addLambdaResolver` injects `APPSYNC_TYPED_ERRORS=true` automatically on the `typedErrors: true` path, the same path that carries the response handler to translate the envelope. On the default UNIT path the flag is left unset, so a handler that throws an `errors.appsync.*` error fails the invocation loudly (rethrow) instead of returning a broken envelope as field data. If you wire `createAppSyncHandler` yourself without `GraphQlApi`, set `APPSYNC_TYPED_ERRORS=true` on the Lambda yourself to get envelope behavior and replicate the response handler. Without it, typed errors rethrow.
Two classes share the short names `ForbiddenError` and `NotFoundError`, so pick the namespace deliberately:
diff --git a/src/constructs/graphql.ts b/src/constructs/graphql.ts
index fd4204b..df9dd5c 100644
--- a/src/constructs/graphql.ts
+++ b/src/constructs/graphql.ts
@@ -60,9 +60,13 @@ export interface LambdaResolverOptions {
* this many field invocations into one Lambda call. Pair this with
* createAppSyncBatchHandler, whose handler receives the batched events.
*
- * This option applies only to the default direct-Lambda UNIT path. It is not
- * compatible with `typedErrors` (the APPSYNC_JS pipeline resolver), which does
- * not use these BatchInvoke mapping templates.
+ * When both maxBatchSize and `typedErrors` are set, maxBatchSize wins for this
+ * field. The field gets the UNIT BatchInvoke resolver rather than the
+ * typedErrors APPSYNC_JS pipeline, because the BatchInvoke mapping templates
+ * have no equivalent on that pipeline. Typed errors thrown by a batch handler
+ * are not converted to GraphQL errors. They rethrow and fail the invocation,
+ * so a batch handler should not rely on the typed-error-to-GraphQL-error
+ * conversion.
*
* @default - undefined (single invoke, the pre-batch behaviour; no MaxBatchSize and no mapping templates)
*/
@@ -328,12 +332,7 @@ export class GraphQlApi extends BaseApi {
fieldName: keyof FIELDTYPE,
options?: LambdaResolverOptions,
): LambdaFunction {
- // BatchInvoke mapping templates belong to the direct-Lambda UNIT resolver and
- // have no equivalent on the APPSYNC_JS pipeline resolver built for typedErrors,
- // so the two cannot be combined. Fail fast rather than silently ignore one.
- if (options?.maxBatchSize !== undefined && this.props.typedErrors) {
- throw new Error('maxBatchSize is not supported together with typedErrors');
- }
+ const isBatch = options?.maxBatchSize !== undefined;
const operationId = `${typeName as string}.${fieldName as String}`;
const description = `Type ${typeName as string} Field ${fieldName as String} Resolver`;
@@ -381,28 +380,40 @@ export class GraphQlApi extends BaseApi {
lambdaFunction: fn,
});
+ if (isBatch) {
+ // A batch field always takes the UNIT BatchInvoke path, even when the API
+ // has typedErrors enabled. maxBatchSize wins over typedErrors for this
+ // field because the BatchInvoke mapping templates have no equivalent on
+ // the APPSYNC_JS pipeline resolver. AppSync batches up to maxBatchSize
+ // field invocations into a single Lambda call handled by
+ // createAppSyncBatchHandler. The L2 BaseResolverProps.maxBatchSize sets
+ // MaxBatchSize directly, so no escape hatch is needed.
+ //
+ // APPSYNC_TYPED_ERRORS is intentionally not set here. A batch handler that
+ // throws a typed error rethrows and fails the invocation loudly instead of
+ // having the error envelope returned as field data.
+ new aws_appsync.Resolver(scope, `Resolver${operationId}`, {
+ api: this.api,
+ typeName: typeName as string,
+ fieldName: fieldName as string,
+ dataSource,
+ maxBatchSize: options!.maxBatchSize,
+ requestMappingTemplate: aws_appsync.MappingTemplate.lambdaRequest('$utils.toJson($context)', 'BatchInvoke'),
+ responseMappingTemplate: aws_appsync.MappingTemplate.lambdaResult(),
+ });
+ return fn;
+ }
+
if (!this.props.typedErrors) {
// Default (pre-#385) shape: a plain UNIT resolver with the Lambda data
// source set directly. No response handler, so the error envelope from
// createAppSyncHandler would be surfaced as field data rather than a
// GraphQL error. Opt in via `typedErrors: true` to get the pipeline below.
- //
- // When maxBatchSize is set, this stays a UNIT resolver but gets the
- // BatchInvoke mapping templates and MaxBatchSize, so AppSync batches field
- // invocations into a single Lambda call handled by createAppSyncBatchHandler.
- // The L2 BaseResolverProps.maxBatchSize sets MaxBatchSize directly, so no
- // escape hatch is needed. Leaving the option unset keeps the exact prior
- // single-invoke shape (no MaxBatchSize, no mapping templates).
new aws_appsync.Resolver(scope, `Resolver${operationId}`, {
api: this.api,
typeName: typeName as string,
fieldName: fieldName as string,
dataSource,
- ...options?.maxBatchSize !== undefined && {
- maxBatchSize: options.maxBatchSize,
- requestMappingTemplate: aws_appsync.MappingTemplate.lambdaRequest('$utils.toJson($context)', 'BatchInvoke'),
- responseMappingTemplate: aws_appsync.MappingTemplate.lambdaResult(),
- },
});
return fn;
}
diff --git a/test/constructs/graphql.test.ts b/test/constructs/graphql.test.ts
index 68845c9..bd746f9 100644
--- a/test/constructs/graphql.test.ts
+++ b/test/constructs/graphql.test.ts
@@ -484,7 +484,7 @@ type Post {
});
});
- test('maxBatchSize together with typedErrors throws', () => {
+ test('maxBatchSize wins over typedErrors: UNIT BatchInvoke resolver, no pipeline, no env var', () => {
const api = new GraphQlApi(stack, 'TestApi', {
apiName: 'TestAPI',
stageName: 'test',
@@ -493,8 +493,35 @@ type Post {
typedErrors: true,
});
- expect(() => api.addLambdaResolver('Query', 'getUser', { maxBatchSize: 10 }))
- .toThrow('maxBatchSize is not supported together with typedErrors');
+ api.addLambdaResolver('Query', 'getUser', { maxBatchSize: 10 });
+
+ const template = Template.fromStack(stack);
+
+ // A batch field takes the UNIT BatchInvoke path even when the API enables
+ // typedErrors, so it synthesizes identically to a batch field on a
+ // non-typedErrors API: a direct-Lambda UNIT resolver with MaxBatchSize and
+ // the BatchInvoke mapping templates, no inline Code and no PipelineConfig.
+ template.hasResourceProperties('AWS::AppSync::Resolver', {
+ TypeName: 'Query',
+ FieldName: 'getUser',
+ Kind: 'UNIT',
+ MaxBatchSize: 10,
+ RequestMappingTemplate: Match.stringLikeRegexp('BatchInvoke'),
+ ResponseMappingTemplate: '$util.toJson($ctx.result)',
+ Code: Match.absent(),
+ PipelineConfig: Match.absent(),
+ });
+
+ // No APPSYNC_JS pipeline function on the batch path.
+ template.resourceCountIs('AWS::AppSync::FunctionConfiguration', 0);
+
+ // The batch Lambda carries no APPSYNC_TYPED_ERRORS env var, so a batch
+ // handler that throws a typed error rethrows and fails the invocation
+ // instead of returning the envelope as field data.
+ template.hasResourceProperties('AWS::Lambda::Function', {
+ Description: '[test] Type Query Field getUser Resolver',
+ Environment: Match.absent(),
+ });
});
});
The type definition for the GraphQL resolvers.