Amy Blankenship
Amy Blankenship

Reputation: 6961

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

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

Answers (4)

dbanswan
dbanswan

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

Michael Lynch
Michael Lynch

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

Dave Lee
Dave Lee

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

Youssouf Oumar
Youssouf Oumar

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

Related Questions