Reputation: 6961
I have this code in my app/page
(Server Component):
const getUsers = async () => {
const result = await fetch('/api/users', {method: 'GET'});
if (result.ok) {
return result.json();
}
return [];
}
export default async function IndexPage() {
const users = await getUsers();
return (<h1>Users: {users.length}</h1>);
}
This gives me the following error:
TypeError: Failed to parse URL from api/users
How do I refer to the "left side" of the URL from within a Server Side Component? All the Next.js 13
examples I can find show pointing to some third-party server. The Postgres example project, which uses the old router and client-side fetching, uses the same syntax I used.
Upvotes: 44
Views: 63273
Reputation: 49
If it helps, I had the same error in the server component next.js 13. All i did to fix the error was to shift the code from api call to a util file which returns the same data. Since we are in the server component we can directly call that function without needing to fetch data from a api.
Upvotes: 0
Reputation: 3149
Create .env
variables:
LOCAL
URL=http://localhost:3000
DEVELOPMENT
URL=https://site-name.vercel.app
PREVIEW
URL=${VERCEL_URL}
PRODUCTION
URL=https://site-name.com
Note that Vercel defines a VERCEL_URL
system variable that you need to reference for their preview server, as the URL is generated.
https://vercel.com/docs/projects/environment-variables/system-environment-variables
Then reference the variable in your code:
fetch(`${process.env.URL}/api/users`);
Upvotes: 10
Reputation: 524
You would need to use absolute URLs, and it can be called from env file. For those who are curious about my case, my similar issue came from Vercel's environment variables. I did not configure Vercel environment variables, so the service failed to parse the URL. Here's my code snippet.
try {
// request APIs
const response = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}${param}`, { // You need to add an env variable "NEXT_PUBLIC_BASE_URL" in Vercel's settings.
method: "POST",
headers: {
Authorization: `Bearer ${process.env.NEXT_PUBLIC_API_TOKEN}`,
},
body: JSON.stringify({
{YOUR_BODY}
}),
});
const textResponse = await response.text();
return new Response(textResponse, { status: 200 });
} catch (error) {
console.log(`error: ${error}`);
}
Upvotes: 1
Reputation: 46161
When you call fetch(/api/users)
with a relative path on the browser, it works because it is using the origin of the document to have fetch(https://your-domain.com/api/users)
.
However, in Node.js, where your server-side fetch is happening, there is no similar behaviour. It expects a fully defined URL. It's not related to Server Components, in fact, you get the same error in functions like getServerSideProps
in the pages
directory.
You can read more about it if you want on this GitHub Issue.
I would suggest you use an environment variable to smoothly go to production, where you may have a different URL.
app/page.js:
const getUsers = async () => {
const result = await fetch(process.env.URL + '/api/users', {method: 'GET'});
if (result.ok) {
return result.json();
}
return [];
}
export default async function IndexPage() {
const users = await getUsers();
return (<h1>Users: {users.length}</h1>);
}
.env:
URL="http://localhost:3001"
You just change the URL variable later on in your hosting service admin.
That has been said, you may still get another error at build time if you are calling an internal API route from a server component. Because at that time, there might be no application running (the application being build and not deployed yet).
Tim Neutkens from Next.js points that out in this GitHub issue:
This is because you're trying to fetch from an internal api route during build, which is not supported.
Instead of calling the internal API route from a server component, which then calls your DB or CMS, reach them directly from the component. It helps avoid the error, and also an additional useless API call.
Upvotes: 77