Next13: calling a route handler from Server Component?
Answered
Chinese Egret posted this in #help-forum
Chinese EgretOP
Hi all,
I have a route handler (
I have a Server Component that wants to make a request to this route handler (
I have not been able to find any examples of hitting route handlers from Server Components. I don't want to convert this Server Component into a Client Component unless I have to...
Can anyone help?
I have a route handler (
app/api/user/route.ts
) that handles adding a header via httpOnly cookies and sending off a request to an external API. I have a Server Component that wants to make a request to this route handler (
const res = await fetch('api/user');
). However, since this request is happening in the server environment, the relative URL results in an error on the server: Failed to parse URL from api/user
. I have not been able to find any examples of hitting route handlers from Server Components. I don't want to convert this Server Component into a Client Component unless I have to...
Can anyone help?
Answered by European sprat
You should be calling the function directly rather than hitting your own route handler from server components
20 Replies
Broad-snouted Caiman
Use
const res = await fetch('/api/user');
(absolute url)European sprat
You should be calling the function directly rather than hitting your own route handler from server components
Answer
Chinese EgretOP
Thanks @Broad-snouted Caiman . Can you say more about that @European sprat ?
European sprat
show your route handler code and the server component code
Chinese EgretOP
// Route handler:
import 'server-only';
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';
const authFetch = async (
path: string,
config?: {
method?: string;
body?: object;
}
) => {
const cookieStore = cookies();
const accessToken = cookieStore.get('accessToken');
const refreshToken = cookieStore.get('refreshToken');
if (!accessToken && !refreshToken) {
redirect('/');
}
const method = config?.method || 'GET';
const body = config?.body ? JSON.stringify(config.body) : undefined;
const headers = new Headers();
headers.append('Authorization', `Bearer ${accessToken}`);
if (['POST', 'PATCH', 'PUT'].includes(method)) {
headers.append('Content-Type', `application/json`);
}
return await fetch(`${process.env.API_URL}${path}`, {
method,
body,
headers: {
Authorization: `Bearer ${accessToken}`,
...headers,
},
});
};
export async function GET() {
return authFetch(`item-inventory/api/instances`); // this is the external API
}
// Server component helper:
export const preload = (type: string) => void getInventoryInstances(type);
export const getInventoryInstances = async (type: string) => {
const res = await fetch(`api/inventory/instances`);
if (!res.ok) {
console.error('Failed to fetch data');
}
const { instances } = await res.json();
return instances;
};
// Server component:
import { getInventoryInstances } from '@/utils/api/inventory/getInstances';
export default async function AppProvider({
children,
}: React.PropsWithChildren) {
const inventoryInstances = await getInventoryInstances('Track');
return (
<TracksProvider {...{ inventoryInstances }}>{children}</TracksProvider>
);
}
European sprat
ok so can't your RSC just call the external api directly?
Chinese EgretOP
Could it do the same cookie handling that the route handler does?
There is also another situation – I also have Client Components that will need to call the external API, with the same cookie header handling
European sprat
client components would use your route handler endpoint (or server action which calls the external api)
Chinese EgretOP
but i think the same issue would arise, of the endpoint being relative versus absolute
let me give it a shot
thanks @European sprat for your help!
European sprat
i'm not sure exactly how to structure what you're doing but my main point was to say that you shouldn't call an internal nextjs router handler from a server component. i don't know the exact reasoning but i know it's a "no no"
Chinese EgretOP
i feel that
yea im realizing its not very different from api routes in pre-13
same paradigm applies
i just didnt think that the Server Components' server environment would be the same as the route handler's server environment
yea...doesnt look like they are able to find the httpOnly cookies set in each other's environments
I have it structured as so for now:
- login button callback (on client) -> api/login/route.ts to set httpOnly token cookies
- page (on server) -> api/needs-auth/route.ts to check and inject httpOnly token cookies to external API request
- login button callback (on client) -> api/login/route.ts to set httpOnly token cookies
- page (on server) -> api/needs-auth/route.ts to check and inject httpOnly token cookies to external API request