How do i properly set up nextjs external pages/api/* routes using trpc?

I have a working application, now for testing I want to create a few pages/api/* routes to see the raw data i get before pushing into a component. I created pages/api/lessons with this content:
import { trpc } from "@acme/app/utils/trpc";
import { NextApiRequest, NextApiResponse } from "next";

export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const { method } = req;
const { data } = trpc.lesson.all.useQuery();
console.log("data", data);

switch (method) {
case "GET":
try {
res.status(200).json({ success: true, data: data });
} catch (error) {
res.status(400).json({ success: false, error: error });
}
}
}
import { trpc } from "@acme/app/utils/trpc";
import { NextApiRequest, NextApiResponse } from "next";

export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const { method } = req;
const { data } = trpc.lesson.all.useQuery();
console.log("data", data);

switch (method) {
case "GET":
try {
res.status(200).json({ success: true, data: data });
} catch (error) {
res.status(400).json({ success: false, error: error });
}
}
}
and I am getting an error:
TypeError: Cannot read properties of null (reading 'useContext')
TypeError: Cannot read properties of null (reading 'useContext')
I have trpc working on the index page (basic t3 app) but when i try to place it inside an nextjs route it never renders. If i remove trpc logic from the api route and just put some dummy data, it works fine. Where is my issue?
13 Replies
whatplan
whatplan2y ago
Server Side Calls | tRPC
You may need to call your procedure(s) directly from the same server they're hosted in, router.createCaller() can be used to achieve this.
whatplan
whatplan2y ago
Christopher Ehrlich
YouTube
Advanced tRPC - Callers, functions, and gSSP
🚨 createSSGHelpers has been renamed to createServerSideHelpers 🚨 Repo for this video: https://github.com/c-ehrlich/you-dont-need-callers If you want to use schema in the frontend, they cannot be imported from the same file as things that run specifically in the backend. One solution would be to put them into a procedureName.schema.ts or simi...
whatplan
whatplan2y ago
you really dont want to be calling your own backend from your backend just extract what you need into a function and call it where needed
Trader Launchpad
Trader LaunchpadOP2y ago
i am struggling to grasp this. That video didnt show how to use it in an api route. Could you elaborate a little more? I also want the api route to be protected by clerk auth so that you can only get a response if you are authed, but I can work on that after maybe. I am using t3 turbo with clerk so I may have to account for this to make this work. I am currently getting a type error with a reference to clerk auth (see errors below) here is my current file
import { trpc } from "@acme/app/utils/trpc";
import { NextApiRequest, NextApiResponse } from "next";
import { appRouter } from "@acme/api/index";
import { getHTTPStatusCodeFromError } from "@trpc/server/http";
import { TRPCError } from "@trpc/server";

type ResponseData = {
success?: boolean;
data?: {
post_title: string;
post_content: string;
};
error?: {
message?: string;
};
};

export default async function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>,
) {
const caller = appRouter.lesson.createCaller({});
const { method } = req;

switch (method) {
case "GET":
try {
const data = await caller.all();
res.status(200).json({
success: true,
data: {
post_title: data.post_title,
post_content: data.post_content,
},
});
} catch (cause) {
// If this a tRPC error, we can extract additional information.
if (cause instanceof TRPCError) {
// We can get the specific HTTP status code coming from tRPC (e.g. 404 for `NOT_FOUND`).
const httpStatusCode = getHTTPStatusCodeFromError(cause);

res
.status(httpStatusCode)
.json({ error: { message: cause.message } });
return;
}

// This is not a tRPC error, so we don't have specific information.
res.status(500).json({
error: { message: `Error while accessing post with ID ${postId}` },
});
}
}
}
import { trpc } from "@acme/app/utils/trpc";
import { NextApiRequest, NextApiResponse } from "next";
import { appRouter } from "@acme/api/index";
import { getHTTPStatusCodeFromError } from "@trpc/server/http";
import { TRPCError } from "@trpc/server";

type ResponseData = {
success?: boolean;
data?: {
post_title: string;
post_content: string;
};
error?: {
message?: string;
};
};

export default async function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>,
) {
const caller = appRouter.lesson.createCaller({});
const { method } = req;

switch (method) {
case "GET":
try {
const data = await caller.all();
res.status(200).json({
success: true,
data: {
post_title: data.post_title,
post_content: data.post_content,
},
});
} catch (cause) {
// If this a tRPC error, we can extract additional information.
if (cause instanceof TRPCError) {
// We can get the specific HTTP status code coming from tRPC (e.g. 404 for `NOT_FOUND`).
const httpStatusCode = getHTTPStatusCodeFromError(cause);

res
.status(httpStatusCode)
.json({ error: { message: cause.message } });
return;
}

// This is not a tRPC error, so we don't have specific information.
res.status(500).json({
error: { message: `Error while accessing post with ID ${postId}` },
});
}
}
}
I am getting type errors: const caller = ***
Argument of type '{}' is not assignable to parameter of type '{ auth: SignedInAuthObject | SignedOutAuthObject; prisma: PrismaClient<Prisma.PrismaClientOptions, never, Prisma.RejectOnNotFound | Prisma.RejectPerOperation | undefined>; }'.
Argument of type '{}' is not assignable to parameter of type '{ auth: SignedInAuthObject | SignedOutAuthObject; prisma: PrismaClient<Prisma.PrismaClientOptions, never, Prisma.RejectOnNotFound | Prisma.RejectPerOperation | undefined>; }'.
post_title: data.post_title
Property 'post_title' does not exist on type 'wp_posts[]'.
Property 'post_title' does not exist on type 'wp_posts[]'.
I know post_title does exist on that type because its working on pages/index @whatplan could you take a look? I have tried about 10 different ways today and i still cant figure it out
whatplan
whatplan2y ago
Just got off work I will tonight
Trader Launchpad
Trader LaunchpadOP2y ago
Thank you!
whatplan
whatplan2y ago
ok so last night I didnt really read your question too deeply (sorry) so first: if you want to check the output of your api just use it in a component and JSON.stringify or console.log it second, as I mentioned earlier and one of the main points of the video is almost always createCaller is not needed what you want is to extract your backend logic into a function you can call in different places (image is from the trpc docs link) so in this case you have a function that does all the database calling logic and then you can call that from different places in your case you could call it from within a trpc procedure, or from a nextjs api route but tbh I dont understand exactly what your looking to do if you could explain more I can help further
ejoo
ejoo2y ago
Create T3 App
tRPC 🚀 Create T3 App
The best way to start a full-stack, typesafe Next.js app.
Trader Launchpad
Trader LaunchpadOP2y ago
"almost always createCaller is not needed what you want is to extract your backend logic into a function you can call in different places" how would i handle protected routes in cases like this? Wouldnt i have to duplicate the code unnecessarily to check for clerk auth within the api route? I got it mostly working using createCaller, data is atleast printing to console, just having an issue displaying the json thank you for all your help! This helped alot, thank you!
whatplan
whatplan2y ago
Didn’t know this was a page on the docs site would’ve sent earlier sorry
ejoo
ejoo2y ago
And i think external api doesn’t work on protected routes. i have clerk user event webhook set up and it only works on public procedure
cje
cje2y ago
Yea if you make a request to a procedure that needs a session cookie, and you’re not providing a session cookie, it’s not gonna work
ejoo
ejoo2y ago
lucky for the webhook secret key
Want results from more Discord servers?
Add your server