Next.js Discord

Discord Forum

Next13: calling a route handler from Server Component?

Answered
Chinese Egret posted this in #help-forum
Open in Discord
Avatar
Chinese EgretOP
Hi all,

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
View full answer

20 Replies

Avatar
Broad-snouted Caiman
Use const res = await fetch('/api/user'); (absolute url)
Avatar
European sprat
You should be calling the function directly rather than hitting your own route handler from server components
Answer
Avatar
Chinese EgretOP
Thanks @Broad-snouted Caiman . Can you say more about that @European sprat ?
Avatar
European sprat
show your route handler code and the server component code
Avatar
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>
  );
}
Avatar
European sprat
ok so can't your RSC just call the external api directly?
Avatar
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
Avatar
European sprat
client components would use your route handler endpoint (or server action which calls the external api)
Avatar
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!
Avatar
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"
Avatar
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