ferdy
ferdy2y ago

trpc + AWS Lambda (through cdk)

Hi all, has anyone successfully integrated tRPC with AWS Lambda? My current stack is API Gateway + Lambda, all created through cdk. I am trying to figure out how to hook up the tRPC router and client to the lambda code. This is my first time using tRPC 😅
36 Replies
Nick
Nick2y ago
Have you looked at the Lambda Adapter and its docs?
ferdy
ferdy2y ago
yeah, I have been trying to figure out how to make that sample code work. But it doesn't show me how to fit that code into the surrounding cdk infrastructure. I see that they export a handler:
export const handler = awsLambdaRequestHandler(...)
export const handler = awsLambdaRequestHandler(...)
but when I try to reference that handler from cdk it's not quite working:
const testLambda = new aws_lambda.Function(this, "testLambda", {
handler:("/path/to/ApiEntryPoint.handler"),
...
const testLambda = new aws_lambda.Function(this, "testLambda", {
handler:("/path/to/ApiEntryPoint.handler"),
...
Lois
Lois2y ago
remember to add AWS extension in your VSCode the prompt + autocomplete is good
Nick
Nick2y ago
So exporting a handler is a standard lambda thing, that’s the boundary of your application At that point you’re looking at CDK docs to integrate, though honestly I haven’t used CDK. For my own local dev I just use a standalone trpc adapter, and the lambda adapter is just for AWS deployments
ferdy
ferdy2y ago
ok I got it mostly figured out -- for any other wayward souls with this issue, check out this github repo that really helped me out: https://github.com/jacksonludwig/trpc-repro
GitHub
GitHub - jacksonludwig/trpc-repro
Contribute to jacksonludwig/trpc-repro development by creating an account on GitHub.
ferdy
ferdy2y ago
@Nick Lucas thanks for the help. I have one more question: when creating my client typescript keeps complaining to me that I am not providing a transformer, and I don't really know what I am supposed to pass in for that. The sample code I linked above doesn't seem to have to do that, I guess because they are not using createTRPCProxyClient. Do you know why that is or what I can use as a transformer?
Nick
Nick2y ago
That's a tRPC thing, check the docs for transformers 🙂 It's easy!
ferdy
ferdy2y ago
I will, though I am still curious why every example I've seen of the proxy client doesnt include having to specify a transformer
Nick
Nick2y ago
You don't have to, but you also can't go half in, which is what you might have inadvertently done if it's moaning at you
ferdy
ferdy2y ago
const client = createTRPCProxyClient<AppRouter>({
links: [
httpBatchLink({
url: "https://xxxxxxxx.execute-api.us-west-2.amazonaws.com/prod/"
})
],
});
const client = createTRPCProxyClient<AppRouter>({
links: [
httpBatchLink({
url: "https://xxxxxxxx.execute-api.us-west-2.amazonaws.com/prod/"
})
],
});
^^^ this doesnt compile
Nick
Nick2y ago
Can you share your appRouter too?
ferdy
ferdy2y ago
yeah
export const createContext = (_: CreateAWSLambdaContextOptions<APIGatewayProxyEventV2>) => ({});
type Context = inferAsyncReturnType<typeof createContext>;

const t = initTRPC.context<Context>().create();

export const middleware = t.middleware;
export const router = t.router;
export const procedure = t.procedure;
export const mergeRouters = t.mergeRouters;

const appRouter = router({
testRoute: procedure.query(async () => {
// mock fast db lookup
await new Promise((res) => setTimeout(res, 100));

return {
value: 5,
};
}),
testRoute2: procedure.query(async () => {
await new Promise((res) => setTimeout(res, 100));

return {
obj: {
value: 10,
},
};
}),
});

export const handler = awsLambdaRequestHandler({
router: appRouter,
createContext,
});

export type AppRouter = typeof appRouter;
export const createContext = (_: CreateAWSLambdaContextOptions<APIGatewayProxyEventV2>) => ({});
type Context = inferAsyncReturnType<typeof createContext>;

const t = initTRPC.context<Context>().create();

export const middleware = t.middleware;
export const router = t.router;
export const procedure = t.procedure;
export const mergeRouters = t.mergeRouters;

const appRouter = router({
testRoute: procedure.query(async () => {
// mock fast db lookup
await new Promise((res) => setTimeout(res, 100));

return {
value: 5,
};
}),
testRoute2: procedure.query(async () => {
await new Promise((res) => setTimeout(res, 100));

return {
obj: {
value: 10,
},
};
}),
});

export const handler = awsLambdaRequestHandler({
router: appRouter,
createContext,
});

export type AppRouter = typeof appRouter;
Nick
Nick2y ago
What's the compile error for your example? This does look fine so it's weird you're having an issue
ferdy
ferdy2y ago
TS2345: Argument of type '{ links: TRPCLink<CreateRouterInner<RootConfig<{ ctx: {}; meta: object; errorShape: never; transformer: DataTransformerOptions; }>, { testRoute: BuildProcedure<"query", { _config: RootConfig<{ ctx: {}; meta: object; errorShape: never; transformer: DataTransformerOptions; }>; ... 5 more ...; _meta: object; }, { ...; ...' is not assignable to parameter of type 'CreateTRPCClientOptions<CreateRouterInner<RootConfig<{ ctx: {}; meta: object; errorShape: never; transformer: DataTransformerOptions; }>, { testRoute: BuildProcedure<"query", { _config: RootConfig<{ ctx: {}; meta: object; errorShape: never; transformer: DataTransformerOptions; }>; ... 5 more ...; _meta: object; }, {...'.   Property 'transformer' is missing in type '{ links: TRPCLink<CreateRouterInner<RootConfig<{ ctx: {}; meta: object; errorShape: never; transformer: DataTransformerOptions; }>, { testRoute: BuildProcedure<"query", { _config: RootConfig<{ ctx: {}; meta: object; errorShape: never; transformer: DataTransformerOptions; }>; ... 5 more ...; _meta: object; }, { ...; ...' but required in type '{ transformer: DataTransformerOptions; }'.
TS2345: Argument of type '{ links: TRPCLink<CreateRouterInner<RootConfig<{ ctx: {}; meta: object; errorShape: never; transformer: DataTransformerOptions; }>, { testRoute: BuildProcedure<"query", { _config: RootConfig<{ ctx: {}; meta: object; errorShape: never; transformer: DataTransformerOptions; }>; ... 5 more ...; _meta: object; }, { ...; ...' is not assignable to parameter of type 'CreateTRPCClientOptions<CreateRouterInner<RootConfig<{ ctx: {}; meta: object; errorShape: never; transformer: DataTransformerOptions; }>, { testRoute: BuildProcedure<"query", { _config: RootConfig<{ ctx: {}; meta: object; errorShape: never; transformer: DataTransformerOptions; }>; ... 5 more ...; _meta: object; }, {...'.   Property 'transformer' is missing in type '{ links: TRPCLink<CreateRouterInner<RootConfig<{ ctx: {}; meta: object; errorShape: never; transformer: DataTransformerOptions; }>, { testRoute: BuildProcedure<"query", { _config: RootConfig<{ ctx: {}; meta: object; errorShape: never; transformer: DataTransformerOptions; }>; ... 5 more ...; _meta: object; }, { ...; ...' but required in type '{ transformer: DataTransformerOptions; }'.
Nick
Nick2y ago
Hm, what's your @trpc/* version? Are they all identical?