API Route not found from server component
Unanswered
Cape lion posted this in #help-forum
Cape lionOP
Hey, I am getting a error of 404 on an API route when I call it from a server component.
Here's the code:
1. Mail Page
2. fetchInbox action:
Here's the code:
1. Mail Page
import { cookies } from "next/headers";
import Image from "next/image";
import { Mail } from "./_components/mail";
import { accounts } from "./data";
import ActionBar from "@/app/(common)/_components/ActionBar";
import { fetchInbox } from "./_actions";
export default async function MailPage() {
const mails = await fetchInbox();
const layout = cookies().get("react-resizable-panels:layout");
const collapsed = cookies().get("react-resizable-panels:collapsed");
const defaultLayout = layout ? JSON.parse(layout.value) : undefined;
const defaultCollapsed = collapsed ? JSON.parse(collapsed.value) : undefined;
return (
<>
<ActionBar actionBarComponent={null} />
<div className="hidden flex-col md:flex">
<Mail
accounts={accounts}
mails={mails}
defaultLayout={defaultLayout}
defaultCollapsed={defaultCollapsed}
navCollapsedSize={4}
/>
</div>
</>
);
}2. fetchInbox action:
"use server";
export async function fetchInbox() {
try {
console.log("fetching inbox")
const res = await fetch(`http://localhost:3000/api/mailbox`);
console.log(res);
const data = await res.json();
if (!res.ok) {
console.error(data);
return [];
}
return data.data.messages;
} catch (error) {
console.error('Error fetching inbox:', error);
return [];
}
};42 Replies
Cape lionOP
3. /api/mailbox route:
4. middleware.ts
import getAuthenticatedUser from "@/utils/auth";
import { NextRequest, NextResponse } from "next/server";
import prisma from "@/lib/prisma";
import { gmail_v1 } from "googleapis";
import { createGoogleApiClient } from "@/utils/helpers";
export async function GET(req: NextRequest) {
try {
let authenticatedUser = await getAuthenticatedUser(req);
if (!authenticatedUser) {
return NextResponse.json({
status: false,
message: "User not authenticated",
data: null
});
}
...
return NextResponse.json({
status: true,
message: "Inbox fetched successfully",
data: {
messages: messages,
pageToken: response.data.nextPageToken,
maxResults: response.data.resultSizeEstimate,
email: authenticatedUser.email,
}
})
} catch (err: any) {
console.log('Error in get mailbox api', err);
return Response.json({
status: false,
message: "Internal server error",
data: null,
error: err.message,
});
}
}4. middleware.ts
import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";
const isPublicRoute = createRouteMatcher([
"/sign-in",
"/sign-up",
"/forgot-password",
"/api/webhooks/(.*)",
]);
export default clerkMiddleware((auth, request) => {
if (!isPublicRoute(request)) {
auth().protect();
}
});
export const config = {
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};1. Mail Page is a client or server component?
2. share your file structure
@B33fb0n3 1. Mail Page is a client or server component?
Cape lionOP
Server component. I've not declared use client for the mail page
@Cape lion Server component. I've not declared use client for the mail page
Alright. I will get to the point with your issue with the route in the next couple of messages. But first things first: why don't you fetch it directly inside your server component?
@B33fb0n3 2. share your file structure
Cape lionOP
Sure, for Mail Page it's
Mail box api is:
src/app/workspace/[workspaceId]/mails/page.tsxMail box api is:
src/app/api/mailbox/route.ts@B33fb0n3 Alright. I will get to the point with your issue with the route in the next couple of messages. But first things first: why don't you fetch it directly inside your server component?
Cape lionOP
I tried that, it's still giving the same error
@Cape lion I tried that, it's still giving the same error
can you execute this clientside:
And share the network request?
const res = await fetch(`http://localhost:3000/api/mailbox`);
console.log(res);
const data = await res.json();And share the network request?
Cape lionOP
This is the error btw:
GET /api/mailbox 404 in 842ms
Error fetching inbox: SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
at JSON.parse (<anonymous>)
at parseJSONFromBytes (node:internal/deps/undici/undici:5472:19)
at successSteps (node:internal/deps/undici/undici:5454:27)
at fullyReadBody (node:internal/deps/undici/undici:4381:9)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async consumeBody (node:internal/deps/undici/undici:5463:7)
at async fetchInbox (webpack-internal:///(rsc)/./src/app/workspace/[workspace_id]/mails/_actions.ts:16:22)perfect. After that, can you remove (or comment out) all the code inside your route, so that only this is left:
Also remove all the imports. When you call your route now, are you able to see the "hello world" message in the serverside log?
export async function GET(request: Request) {
console.log("hello world")
}Also remove all the imports. When you call your route now, are you able to see the "hello world" message in the serverside log?
@B33fb0n3 can you execute this clientside:
tsx
const res = await fetch(`http://localhost:3000/api/mailbox`);
console.log(res);
const data = await res.json();
And share the network request?
Cape lionOP
this is when i execute it on client side
@Cape lion this is when i execute it on client side
looks good for me
@B33fb0n3 perfect. After that, can you remove (or comment out) all the code inside your route, so that only this is left:
tsx
export async function GET(request: Request) {
console.log("hello world")
}
Also remove all the imports. When you call your route now, are you able to see the "hello world" message in the serverside log?
Cape lionOP
this is what i get for only logging hello world
same error
@Cape lion this is what i get for only logging hello world
thanks for testing. Modify your code so it look like the following:
Now check the serverside console and see if there is now data inside it
import { cookies } from "next/headers";
import Image from "next/image";
import { Mail } from "./_components/mail";
import { accounts } from "./data";
import ActionBar from "@/app/(common)/_components/ActionBar";
import { fetchInbox } from "./_actions";
export default async function MailPage() {
const mails = await fetchInbox();
const layout = cookies().get("react-resizable-panels:layout");
const collapsed = cookies().get("react-resizable-panels:collapsed");
console.log("mails: ", mails)
return (
<>
<ActionBar actionBarComponent={null} />
<div className="hidden flex-col md:flex">
<Mail
accounts={accounts}
mails={mails}
defaultLayout={defaultLayout}
defaultCollapsed={defaultCollapsed}
navCollapsedSize={4}
/>
</div>
</>
);
}Now check the serverside console and see if there is now data inside it
Cape lionOP
yeah
there is now data?
Cape lionOP
no no, just checking. one sec
oh you might want to comment out the the "Mail" component xD
Cape lionOP
haha, yeah. server screamed that at me
sorry mb
Cape lionOP
nah nah, it's good. i appreciate you taking out your time to help. give me a sec, i'll just see the result
nah, same error
it does work when i convert it to a client component, but i wanted to know why it's not working with server component.
before i faced this error, it was cause of my middleware but i doubt that's the case this time
before i faced this error, it was cause of my middleware but i doubt that's the case this time
i've sent the middleware file above as well for reference
@Cape lion this is what i get for only logging hello world
you also remove the imports, right?
@B33fb0n3 you also remove the imports, right?
Cape lionOP
yeah, i commented them out. just kept the get request
you want me to try removing them all together as well? doubt that would make a difference
@Cape lion yeah, i commented them out. just kept the get request
weird... can you create a minimal repro via jsfiddle or https://codesandbox.io/ that shows the same behavior? I would like to take a deeper look into it
DONT share any sensitive details. As you just saw you can archive the same error when not providing anything inside the route handler. So just remove everything inside it 🙂
Cape lionOP
Hey, so I gave it one more shot to understand what's actually happening.
This is what I found:
- I'm using Clerk for authentication and most of the routes, I'm getting the current user with the help of the request being sent.
- The Mail Page is a server component (so it'll render into HTML from the server itself first). Now I added the /api/mailbox route in list of public to see if it finds the route then. Turns out, it did. No more 404.
- However, it showed that user is not authenticated. So I checked the server component if I'm getting the user ID from clerk and I was.
I think it's a mix of middleware and clerk auth that's the issue. I'll figure out the rest (probably might convert it to a client component in the end)
But thank you so so much @B33fb0n3 for taking out your time. Means a lot :))
This is what I found:
- I'm using Clerk for authentication and most of the routes, I'm getting the current user with the help of the request being sent.
- The Mail Page is a server component (so it'll render into HTML from the server itself first). Now I added the /api/mailbox route in list of public to see if it finds the route then. Turns out, it did. No more 404.
- However, it showed that user is not authenticated. So I checked the server component if I'm getting the user ID from clerk and I was.
I think it's a mix of middleware and clerk auth that's the issue. I'll figure out the rest (probably might convert it to a client component in the end)
But thank you so so much @B33fb0n3 for taking out your time. Means a lot :))
Clerk is showing I'm signed out in the request headers. So I'm probably doing something wrong with Clerk and not next
Cape lionOP
Yeah, took me a while to get it. I'll simplify the flow of this but thanks a lot, man
@Cape lion Yeah, took me a while to get it. I'll simplify the flow of this but thanks a lot, man
Netherland Dwarf
Hey @Cape lion - curious to know what more you discovered. I am having a similar error and I suspect it's something to do with Clerk
@Netherland Dwarf Hey <@759464492433670166> - curious to know what more you discovered. I am having a similar error and I suspect it's something to do with Clerk
Cape lionOP
Hey. From what I remember, when I was fetching data while the component was a server component, Clerk was showing signed out in the request. I tried to find out why but didn't get anywhere.
At the end, I ended up doing it the old way of making it a client component and just fetching data through that because then Clerk was working properly
At the end, I ended up doing it the old way of making it a client component and just fetching data through that because then Clerk was working properly
Netherland Dwarf
I think have a different problem, but there is something similar going on .
thanks for responding