Next.js Discord

Discord Forum

route handlers

Unanswered
Asiatic Lion posted this in #help-forum
Open in Discord
Asiatic LionOP
How do I consume an app router route handler in a next page? I can access it in the browser via localhost:3000/api/myroute but if I put a fetch on my actual page I can’t get it. I’ve tried api/myroute and http://localhost:3000/api/myroute but neither get my data. I don’t see anything on consuming the api on the site but I assumed api/myroute would have been the way

32 Replies

how is your route set up in the folder structure?
Giant panda
You need a prefixed slash: fetch('/api/myroute')
@aardani how is your route set up in the folder structure?
Asiatic LionOP
My actual api route is src/app/myroute/route.tsx and my page is src/app/test/page.tsx
if your route.ts is at /app/myroute then then your route will be accessible at /myroute not /api/myroute
Asiatic LionOP
I missed api so my route.ts is at /src/app/api/myroute/route.tsx but i get console error of failed to parse url from /api/myroute and on the page i get a next error saying body is disturbed or locked. However when navigating strait to api/myroute in the browser I do get my db query data
I don't think i can help you with the given information, perhaps you can help us by providing more info such as by showing code on how you access your routes
@Giant panda You need a prefixed slash: `fetch('/api/myroute')`
Asiatic LionOP
That’s what I would have expected but it doesn’t work. I’ll post some code
Asiatic LionOP
I have a ts file to get data from an api import
"server-only"; const headers = { method: "GET", headers: { Authorization: process.env.API_KEY ? process.env.API_KEY : "", }, next: { revalidate: 15, cache: "no-store" }, }; export async function getData(id: number) { const res = await fetch(https://internalsite.com/api/example/${id}`,
headers
);

return res.json();
}
`
Then I have a route handler using it and it works in postman and browser so does pull data
import { NextResponse } from "next/server"; import { getData } from "@/lib/data/example"; export async function GET() { const data = await getData(1); return NextResponse.json({ data }); }
And my ui is trying to use it this way
"use client"; export async function getData() { const res = await fetch(/api/myroute); console.log(res.json()); return res.json(); } export default function Page({ params }: { params: { id: string } }) { const id = params.id; const data = getData(); return ( <div> <h1>ID page for {id}</h1> <pre>{JSON.stringify(data, null, 2)}</pre> </div> ); }
Can you format your code?
Asiatic LionOP
Errors are
error unhandledRejection: Error [TypeError]: Failed to parse URL from /api/myroute

and
input: '/api/myroute', code: 'ERR_INVALID_URL'
Try putting quotation mark in the url
Asiatic LionOP
same thing 😦
Ok make a minimal reproducible repository then
Recreate your problem in a new repository or project
@aardani Ok make a minimal reproducible repository then
Asiatic LionOP
done
European sprat
you need to make the page function async and await getData
but you also shouldn't be consuming a route handler in a server component
you can use lib/getData.ts directly in the server component
if you really want to consume the route handler in the server component then it works if you make the changes i said and fix the URL, like
fetch("http://localhost:3000/api/randomjoke")
where you want to use the route handler in this example would be a button, which is a client component, that hits the route handler endpoint when clicked
but the initial page (server component) would interact with the getData directly
@European sprat you can use lib/getData.ts directly in the server component
Asiatic LionOP
I just used server components for simplicity, I actually need a client component to consume the route handler and refresh the data every x seconds. So going with localhost:3000 does work but that would break in a production scenario once you deploy.
European sprat
well then update your repro to use client components like you want lol
and show where it doesn't work for your scenario
my client side fetches are able to use /api/whatever just fine
Asiatic LionOP
I guess that answers my question. Basically route handlers are not capable of working in server components in both a dev and production environment without hard coding a domain name or maybe env variables. Instead use the function directly or a client component. Seems like a bit of an oversight IMO for server components not to be able to use the relative URL like a client component.
and the only time (i think?) you'd be using relative URLs in a fetch would be to interact with your own endpoint
personally, i've had to create an env var for a few places where i do need the full URL and it being different in dev/prod
Asiatic LionOP
I wonder why, technically, the behaviour wouldn't be similar though just for shared code. Obviously you can hoist shared code out of the handler and the handler just be basic like here but still . Just glancing, but I can't find anywhere on their route handler docs that says not to use on a server component. Either way it is what it is and I appreciate your help!

Yeah, I've done that too several times just not in a full-stack framework.