skip to Main Content

This is in a NextJS version 14.2.7 app.

I have setup up an api under the following path.

src/app/api/posts/route.ts

When I call it from a client component as follows, works fine.

  const loadMorePosts = async () => {
    const res = await fetch(`/api/posts?page=1&limit=20`);
    const data = await res.json();
  };

  useEffect(() => {
    if (inView) {
      loadMorePosts();
    }
  }, [inView]);

But if I call the same endpoint from a server component as follows:

import { notFound } from 'next/navigation';

const getPost = async (slug: string) => {
    const res = await fetch(`/api/posts?page=1&limit=20`); // this already breaks
    const data = await res.json();
    return data;
};

const PostDetails = async ({ slug }: { slug: string }) => {
  const post = await getPost(slug);

  // failing before even coming here.

  if (!post) {
    notFound();
  }

  return (
    <div className='container mx-auto p-4'>
        Hello
    </div>
  );
};

export default PostDetails;

I get this error:

GET /api/posts?page=1&limit=20 200 in 1069ms ✓ Compiled /post/[slug] in 153ms (1069 modules) ⨯ Internal error: TypeError: Failed to parse
URL from /api/posts?page=1&limit=20
at node:internal/deps/undici/undici:12500:13 digest: "1300981860" Cause: TypeError: Invalid URL
at new URL (node:internal/url:804:36)
at new Request (node:internal/deps/undici/undici:4839:25)
at fetch (node:internal/deps/undici/undici:9651:25)
at fetch (node:internal/deps/undici/undici:12498:10)
at fetch (node:internal/bootstrap/web/exposed-window-or-worker:79:16)
at doOriginalFetch (webpack-internal:///(rsc)/./node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]/node_modules/next/dist/server/lib/patch-fetch.js:440:24)
at eval (webpack-internal:///(rsc)/./node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]/node_modules/next/dist/server/lib/patch-fetch.js:589:24)
at async getPost (webpack-internal:///(rsc)/./src/components/PostDetails.tsx:12:17)
at async PostDetails (webpack-internal:///(rsc)/./src/components/PostDetails.tsx:39:18) {
code: ‘ERR_INVALID_URL’, input: ‘/api/posts?page=1&limit=20’

Why? I have also tried with localhost:3000/api/posts?page=1&limit=20. Same error.

2

Answers


  1. Chosen as BEST ANSWER

    Reason is cos when it comes to server components, you no longer need to call that logic as an api. Just call it as a function without need for going via fetch.

    Essentially extract the logic. Say example you need to contact DB and fetch some data.

    export const getPost = async (slug: string) => {
      const post = await db
        .select()
        .from(posts)
        .where(eq(posts.slug, slug))
        .limit(1)
        .then(rows => rows[0] ?? null);
      return post;
    };
    

    Now in server component, call this function to fetch data.

    No need to go via http(s) nor fetch.

    const PostDetails = async ({ slug }: { slug: string }) => {
      const post = await getPost(slug);
      if (!post) {
        notFound();
      }
    
      return (
        <div className='container mx-auto p-4'>
          Hello
        </div>
      );
    };
    

    Hope this helps others.


  2. If you need your api call only once in the server component, your solution is good. But, if you need the same data both on client and server component, there are 2 better solutions (in my opinion)

    1. Since the server doesn’t know what the public url is (there is no window.location.origin property on the server or something like that) when you call your api you should include the entire url (including schema and domain name too), so to call your api from a server component you should do something like
        const res = await fetch(`${process.env.ORIGIN}/api/posts?page=1&limit=20`);
    
    1. You can use the new server actions from Nextjs 14. In this way, you can create a simple function under action/action-name.ts, make sure you include a "use server" at the beginning of your file and then you can call that function as a simple function call both on client and server components
      https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations

    Hope this will help

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search