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
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.
Now in server component, call this function to fetch data.
No need to go via http(s) nor fetch.
Hope this helps others.
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)
https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations
Hope this will help