adapter-aws-lambda
Deploy tRPC on AWS Lambda with awsLambdaRequestHandler() from @trpc/server/adapters/aws-lambda for API Gateway v1 (REST, APIGatewayProxyEvent) and v2 (HTTP, APIGatewayProxyEventV2), and Lambda Function URLs. Enable response streaming with awsLambdaStreamingRequestHandler() wrapped in awslambda.streamifyResponse(). CreateAWSLambdaContextOptions provides event and context for context creation. Use one {proxy+} resource for httpBatchLink, or httpLink for a resource per procedure.
AWS Lambda + API Gateway Adapter
From https://trpc.io/docs/server/adapters/aws-lambda
AWS Lambda adapter
The AWS Lambda adapter is supported for API Gateway REST API(v1) and HTTP API(v2), and Lambda Function URL use cases.
httpBatchLink requires the router to work on a single API Gateway Resource (as shown in the example). If you'd like to have a Resource per procedure, you can use the httpLink instead (more info).
Example apps
| Description | Links |
|---|---|
| API Gateway with NodeJS client. | |
| API Gateway REST API with response streaming. |
How to add tRPC
1. Install deps
yarn add @trpc/server2. Create a tRPC router
Implement your tRPC router. A sample router is given below:
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
export const t = initTRPC.create();
const appRouter = t.router({
getUser: t.procedure.input(z.string()).query((opts) => {
opts.input; // string
return { id: opts.input, name: 'Bilbo' };
}),
});
// export type definition of API
export type AppRouter = typeof appRouter;3. Use the Amazon API Gateway adapter
tRPC includes an adapter for API Gateway out of the box. This adapter lets you run your routes through the API Gateway handler.
import type { APIGatewayProxyEventV2 } from 'aws-lambda';
import type { CreateAWSLambdaContextOptions } from '@trpc/server/adapters/aws-lambda';
import { awsLambdaRequestHandler } from '@trpc/server/adapters/aws-lambda';
import { appRouter } from './router';
// created for each request
const createContext = ({
event,
context,
}: CreateAWSLambdaContextOptions<APIGatewayProxyEventV2>) => ({}); // no context
type Context = Awaited<ReturnType<typeof createContext>>;
export const handler = awsLambdaRequestHandler({
router: appRouter,
createContext,
})awsLambdaRequestHandler accepts the options every adapter takes, like onError and maxBatchSize.
Build & deploy your code, now use your API Gateway URL to call your function.
| Endpoint | HTTP URI |
|---|---|
| getUser | GET https://<execution-api-link>/getUser?input=INPUT where INPUT is a URI-encoded JSON string. |
A word about payload format version
API Gateway has two different event data formats when it invokes a Lambda. For REST APIs they should be version "1.0"(APIGatewayProxyEvent), but you can choose which for HTTP APIs by stating either version "1.0" or "2.0".
- Version 1.0: APIGatewayProxyEvent
- Version 2.0: APIGatewayProxyEventV2
To infer what version you might have, supply the context as following:
function createContext({
event,
context,
}: CreateAWSLambdaContextOptions<APIGatewayProxyEvent>) {
// ...
}
// CreateAWSLambdaContextOptions<APIGatewayProxyEvent> or CreateAWSLambdaContextOptions<APIGatewayProxyEventV2>Read more here about payload format version
AWS Lambda Response Streaming Adapter
AWS Lambda supports streaming responses to clients with both Lambda Function URLs and API Gateway REST APIs.
Response streaming is supported for Lambda Function URLs and API Gateway REST APIs. For API Gateway REST APIs, you need to configure the integration with responseTransferMode: STREAM. Read more about Lambda response streaming and API Gateway response streaming.
Response Streaming
The signature of a streaming handler is different from the default handler. The streaming handler additionally receives a writable stream parameter, responseStream, besides the default node handler parameters, event and context. To indicate that Lambda should stream your responses, you must wrap your function handler with the awslambda.streamifyResponse() decorator.
Note that the awslambda namespace is automatically provided by the Lambda execution environment. You can import the types from @types/aws-lambda to augment the global namespace with the awslambda namespace.
With streaming, a procedure that returns an async generator, like iterable below, sends each value as it's yielded to clients using httpBatchStreamLink.
/// <reference types="aws-lambda" />
import type { APIGatewayProxyEventV2 } from 'aws-lambda';
import type { CreateAWSLambdaContextOptions } from '@trpc/server/adapters/aws-lambda';
import { awsLambdaStreamingRequestHandler } from '@trpc/server/adapters/aws-lambda';
import { appRouter } from './router';
// created for each request
const createContext = ({
event,
context,
}: CreateAWSLambdaContextOptions<APIGatewayProxyEventV2>) => ({
// your context
});
type Context = Awaited<ReturnType<typeof createContext>>;
export const handler = awslambda.streamifyResponse(
awsLambdaStreamingRequestHandler({
router: appRouter,
createContext,
}),
);Common mistakes
- Using httpBatchLink with a resource per procedure. A batch request puts several procedures in one path, like /getUser,createUser, which none of those resources match. Use one greedy resource like /trpc/{proxy+}, which tRPC reads the procedure path from, or switch to httpLink.
- Forgetting awslambda.streamifyResponse(). Without it, Lambda calls awsLambdaStreamingRequestHandler as a regular handler, which has no response stream to write to.
- Expecting the default handler to stream. awsLambdaRequestHandler buffers the whole response before returning it, so httpBatchStreamLink responses arrive all at once. Use the streaming handler instead.
Common options
Every HTTP adapter accepts these options, next to its own (like endpoint for Fetch, or basePath for Standalone):
| Option | Description |
|---|---|
| router | Your app router. Required. |
| createContext | Creates the context for each request. It receives the adapter's own objects (e.g. req and res) plus info. |
| onError | Called with { error, type, path, input, ctx, req } for every error, e.g. to report it. See Error handling. |
| responseMeta | Returns { status, headers } for the response, e.g. for caching. |
| allowBatching | Set to false to reject batch requests. Defaults to true. |
| maxBatchSize | Rejects batch requests with more calls than this with a 400 Bad Request. Set maxItems on your batch link to the same or a lower value. |
| allowMethodOverride | Accepts queries sent as POST, for clients that set methodOverride: 'POST' on their link. Defaults to false. |
The Node.js adapters (Standalone, Express and Next.js) also accept:
- maxBodySize: the largest request body in bytes; larger ones are rejected with 413 PAYLOAD_TOO_LARGE.
- middleware: a connect-style (req, res, next) function that runs before tRPC, e.g. cors().
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { appRouter } from './router';
createHTTPServer({
router: appRouter,
createContext: () => ({}),
onError({ error, path }) {
console.error(`tRPC error on '${path}':`, error);
},
maxBatchSize: 10,
maxBodySize: 1_000_000, // 1 MB
}).listen(3000);From https://trpc.io/docs/server/adapters#common-options
Related skills
- server-setup (https://trpc.io/docs/server/overview): npx @tanstack/intent@latest load @trpc/server#server-setup