T
tRPC

trpc + AWS Lambda (through cdk)

trpc + AWS Lambda (through cdk)

Fferdy3/6/2023
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 😅
Nnlucas3/6/2023
Have you looked at the Lambda Adapter and its docs?
Fferdy3/6/2023
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"),
...
LLois3/7/2023
remember to add AWS extension in your VSCode the prompt + autocomplete is good
Nnlucas3/7/2023
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
Fferdy3/7/2023
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 @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?
Nnlucas3/7/2023
That's a tRPC thing, check the docs for transformers 🙂 It's easy!
Fferdy3/7/2023
I will, though I am still curious why every example I've seen of the proxy client doesnt include having to specify a transformer
Nnlucas3/7/2023
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
Fferdy3/7/2023
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
Nnlucas3/7/2023
Can you share your appRouter too?
Fferdy3/7/2023
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;
Nnlucas3/7/2023
What's the compile error for your example? This does look fine so it's weird you're having an issue
Fferdy3/7/2023
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; }'.
Nnlucas3/7/2023
Hm, what's your @trpc/* version? Are they all identical?
Fferdy3/7/2023
"@trpc/server": "^10.14.0",
"@trpc/client": "^10.14.0",
"@trpc/server": "^10.14.0",
"@trpc/client": "^10.14.0",
Nnlucas3/7/2023
I've definitely seen someone else asking about this, and I think they resolved it, just can't find it now
Fferdy3/7/2023
ok ill search around as well
Nnlucas3/7/2023
Reload your editor / TS language server and restart your build if you haven't
Fferdy3/7/2023
no luck with that
Nnlucas3/7/2023
bah, this is a weird one This is an error that appears when you have set a transformer on the API but not on the frontend It's intentional and I can reproduce that in my own codebase But transformers are optional I suspect it might be something weird related to your repo setup. If you install superjson and get that set up, do any new errors appear?
Fferdy3/7/2023
I was able to pass in superjson and get around the error, but then the response from my lambda was coming back undefined -- I was wondering if the default transformer would've just handled the response correctly
Nnlucas3/7/2023
At runtime?
Fferdy3/7/2023
yep. and I tested out calling the api directly in my aws console, confirmed its working. Also confirmed that the lambda is getting invoked when I call it from the client by double checking logs it's just the return value isn't getting processed correctly
Nnlucas3/7/2023
That might be something more related to API Gateway if you're using that honestly AWS is a weird balancing act in my experience There's talk to adding some more in-depth docs but we're not there yet
Fferdy3/7/2023
it definitely could be an apig oddity, though I can see it in the console returning the json response correctly. Maybe I need to find somewhere in between that I can inspect to see where that response is getting lost... Like a debug log from the trpc client or something
Nnlucas3/7/2023
Yep I put console logs at several stages, exported my own handler and called the lambda adapter's handler within it so I could log before and after. It's a pain but that's AWS 😄 Did also have some similar teething troubles like you
Fferdy3/7/2023
ok I got it working -- truly dont understand this yet but adding Context to the type parameter of create did the trick:
export const createContext = ({event, context}: CreateAWSLambdaContextOptions<APIGatewayProxyEventV2>) => ({});
type Context = inferAsyncReturnType<typeof createContext>;

const t = initTRPC.context<Context>().create<Context>();
export const createContext = ({event, context}: CreateAWSLambdaContextOptions<APIGatewayProxyEventV2>) => ({});
type Context = inferAsyncReturnType<typeof createContext>;

const t = initTRPC.context<Context>().create<Context>();
also fixed having to supply a transformer
Nnlucas3/7/2023
Huh, that’s very weird Typescript issue maybe? Is strict mode enabled?
Fferdy3/7/2023
ohh no it wasnt. I didn't do the initial setup of this codebase, didn't even notice strict wasnt on. Enabling strict mode and removing the extra <Context> works, compile-wise -- not sure yet about runtime
Nnlucas3/7/2023
That’s good, strict mode fixes a lot of stuff in these well-typed frameworks
UUUnknown User3/7/2023
Message Not Public
Sign In & Join Server To View
FFalo4/24/2023
Ferdy, i'm wondering how to push the code on aws, did you compile your code with tsc and send the dist folder to aws lambda ? Because i have a tons of problem with tsc and running the js file

Looking for more? Join the community!

T
tRPC

trpc + AWS Lambda (through cdk)

Join Server
Recommended Posts
Is it possible to narrow an output schema if the query optionally doesn't return all fields?I have a router procedure that has an input schema that has an optional `filter` that changes the shFetching different server url than defined in configIs it possible to access the reactQuery instance and fetch different server url? I would like to useinput using z.or not working properlyi have an input like this let input = z.object({ name: z.string().optional() }).or(z.object({ How can I disable batching with fastify adapter?I cant seem to find a way to disable batching for my server, and this link doesnt help me much httpsIssue with monorepo architecture ant tRPCHi, we had an issue with batched requests that if we batch some requests they produce a TRPCClientErUsing tRPC in CRON jobsHey everyone, this might be a very stupid question, but is it possible to use tRPC inside a CRON joasync createContext for Express AdapterBeen debugging an odd behavior for the past hour, it seems like that an async function does not workIs it possible to split the router definition with the imlementation?I want to define the server router(input\output\meta) in a separate package from the server package Cache not working for `useQuery`I have a query like this: ```js const { data: article, isFetching } = api.public.getArticle.useQueryZod File Upload Validation with Open-Api Support?Hi guys, anyone know how to validate file upload with zod and get also open-api support?Zod validation and open-api support for File on the server?Hi guys, anyone know how to validate a File upload using zod? and also have open-api support?is context cached?If I put an object on the context that represents the User record from my database... ``` export asyJSON inferred router output not matchingHello. I have a procedure query which is returning Json from a postgresql db using Prisma. The type Best way to implement input based validation on a router procedureHi guys, bit of a noob. I have already created a 'protectedProcedure', ensuring the user is logged [Help] Turbo shared typesI have a turborepo with two apps (web and embed). web is a t3 stack and embed is a create-react-app.Cache SSG helper responseI'm using `createProxySSGHelpers` in GSSP with `ssr: false` in the global config. I trying to cacheInput is too big for a single dispatchI decided to try tRPC for my Crypto analytics dashboard. However, I'm having a hard time passing thetypesafe permissionsHi, So I wanted to infer all the procedures from my router recursively & assign a permission (stringawaiting for procedure & logging the response.Hi, I was wondering if there is a way to handle the return object via the post-middleware's? I know createCaller Dependency Injection in Middleware ctx ?`createCaller` makes it really easy to inject dependencies via anything that's created during the `c