Next.js: TypeError: Failed to parse URL from ... when targeting API route relatively
Asked Answered
R

4

37

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.

Rescue answered 22/5, 2023 at 18:55 Comment(0)
S
60

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.

Salvo answered 23/5, 2023 at 6:31 Comment(0)
S
5

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`);
Scouring answered 4/12, 2023 at 1:10 Comment(0)
D
1

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}`);
  }
Dannadannel answered 26/7, 2023 at 12:37 Comment(1)
Something to note is if you use Vercel's built-in env variable VERCEL_URL your build might fail if you have a "custom" vercel.app subdomain. VERCEL_URL is the deployment-specific subdomain, not the vercel.app subdomain you picked out. For me it was causingfetch() to fail with a "Unexpected token < in JSON at position 0" error. I just had to hardcode my vercel custom domain.Unmoor
B
-1

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.

Bello answered 19/3, 2024 at 7:32 Comment(3)
I wanted my api calls to be testable from Postman and also available to the front end if needed.Rescue
In that case, please follow solutions in above answers, they pretty much solve the issue at hand with env variables.Bello
Not sure why you think I didn't, considering how long the question has been on the site.Rescue

© 2022 - 2025 — McMap. All rights reserved.