#Overwriting default not found logic on api routes.
1 messages · Page 1 of 1 (latest)
Based on the provided knowledge sources:
Overwriting Default Not Found Logic on API Routes
For API Routes in the Pages Router (pages/api), if a route does not exist, Next.js will return a default 404 response. If a route exists but the HTTP method is not implemented, it will return a 405 Method Not Allowed. There is no built-in way to globally override the 404 or 405 logic for all API routes directly in Next.js configuration.
However, if you want to customize the 404 response for API routes, you can use a catch-all API route (e.g., pages/api/[...slug].js) as a fallback. This route will match any request that doesn't match a more specific API route, allowing you to return a custom 404 response:
// pages/api/[...slug].js
export default function handler(req, res) {
res.status(404).json({ message: 'Not Found' });
}
This approach ensures that any unmatched API route will return your custom 404 response. Note, however, that predefined and dynamic API routes take precedence over catch-all routes, so this will only handle truly unmatched routes see docs.
Alternatively, on Vercel, you can use a vercel.json rewrite to direct unmatched API requests to a custom handler, as described in the Vercel guide:
{
"rewrites": [{ "source": "/api/(.*)", "destination": "/api/404.js" }]
}
This will ensure that any unmatched API route will be handled by /api/404.js, where you can return a custom response see Vercel guide.
Handling All HTTP Methods in a Single Route
For both API Routes and App Router Route Handlers, you must explicitly define each HTTP method you want to handle. There is no built-in way to define a single handler that automatically catches all HTTP methods. If a method is not implemented, Next.js will return a 405 Method Not Allowed response see docs.
For example, in a Route Handler (app/api/route.ts):
export async function GET(request) { /* ... */ }
export async function POST(request) { /* ... */ }
// etc.
If you want to handle all methods with the same logic, you must declare each method and call a shared function:
async function handle(request) {
// shared logic
}
export async function GET(request) { return handle(request); }
export async function POST(request) { return handle(request); }
// ...repeat for other methods
There is no documented way to define a "catch-all" HTTP method handler in a single function for API routes or Route Handlers.
Summary:
- You can use a catch-all API route or Vercel rewrites to customize 404 responses for API routes.
- You must explicitly declare each HTTP method you want to handle; there is no built-in "all methods" handler in Next.js API routes or Route Handlers.
If you need more advanced routing or method handling, you may need to implement your own logic within the catch-all route or use custom server middleware see docs see Vercel guide.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@molten swan Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@earnest wagon I'm using app route though.
Let me check the knowledge base for you again. Give me one moment! :books:
If you are using the App Router (app/ directory), here’s what the knowledge sources say:
Overwriting Default Not Found Logic for API (Route Handlers)
- In the App Router, API endpoints are implemented using Route Handlers (e.g.,
app/api/route.ts). - If a request is made to a non-existent route handler, Next.js will return a default 404 response. There is no documented way to globally override this behavior for all API routes in the App Router.
- You can, however, create a catch-all route handler (e.g.,
app/api/[...path]/route.ts) to handle unmatched API routes and return a custom response:
// app/api/[...path]/route.ts
export async function GET() {
return new Response(JSON.stringify({ message: 'Not Found' }), { status: 404 });
}
This will catch all unmatched API routes under /api/* and return your custom 404 response see docs.
Handling All HTTP Methods in a Single Route Handler
- In Route Handlers, you must explicitly export a function for each HTTP method you want to handle (
GET,POST,PUT, etc.). - There is no built-in way to export a single function that handles all HTTP methods. If a method is not implemented, Next.js will return a 405 Method Not Allowed response see docs.
- If you want to use the same logic for multiple methods, you need to export each method and delegate to a shared function:
async function handle(request: Request) {
// shared logic
return new Response('Handled', { status: 200 });
}
export { handle as GET, handle as POST, handle as PUT, handle as DELETE };
Summary:
- You can use a catch-all route handler to customize 404 responses for API endpoints in the App Router.
- You must explicitly export each HTTP method you want to handle; there is no "catch-all" method export for Route Handlers.
If you need more advanced routing, you may need to implement your own logic within a catch-all route handler see docs.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@molten swan Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@earnest wagon That works, cheers. Now, is there any way to like catch errors from all api routes. So I want to be able to throw like a custom error in a route, and then have it catch that error and format it to my desired error json structure.
E.g. in a route throw NotFoundException("No route found") (has some properties like statusText, statusCode, message, etc.)
Gets caught, returns json response of { status: "fail", message: "404 Not Found: No route found" } with the status code from the exception statusCode. The "404 Not Found" bit comes from the statusText, and the message is added after.
Let me check the knowledge base for you again. Give me one moment! :books:
I'm sorry, but the knowledge sources do not describe a built-in or global mechanism in the Next.js App Router (Route Handlers) to automatically catch and format errors thrown from all API routes in a centralized way.
The recommended approach, according to the documentation, is to use try/catch blocks within each individual Route Handler to catch errors and format the response as needed. For example:
// app/api/example/route.ts
export async function GET(request: Request) {
try {
// ...your logic
throw new NotFoundException("No route found");
} catch (error) {
// Manually format the error response
return new Response(
JSON.stringify({
status: "fail",
message: `${error.statusCode} ${error.statusText}: ${error.message}`,
}),
{ status: error.statusCode, headers: { "Content-Type": "application/json" } }
);
}
}
There is no mention in the documentation of a way to define a global error handler for all Route Handlers in the App Router. Each route must handle its own errors and format the response accordingly see docs.
If you want consistent error formatting, you can create a utility function to handle error formatting and call it in each route's catch block.
Summary:
- There is no built-in global error handler for all API Route Handlers in the App Router.
- You must use try/catch in each handler and format the error response yourself see docs.
If future versions of Next.js introduce a global error handling mechanism for Route Handlers, it will be documented in the official docs.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@molten swan Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@earnest wagon If you want consistent error formatting, you can create a utility function to handle error formatting and call it in each route's catch block. That would be nice, can you make it so I have to repeat minimal code per route. I just want it quick and easy.
Let me check the knowledge base for you again. Give me one moment! :books:
The knowledge sources confirm that there is no built-in global error handler for all API Route Handlers in the Next.js App Router. However, you can minimize repetition by creating a utility function for error formatting and a simple wrapper for your handlers. You will still need to use this wrapper in each route, but it keeps your route code concise.
Here’s a pattern based on the official recommendation to use try/catch in each handler, with minimal per-route code:
// app/api/utils/errorHandler.ts
export async function withErrorHandling(handler: (request: Request) => Promise<Response>) {
return async function(request: Request) {
try {
return await handler(request);
} catch (error: any) {
// Customize this logic as needed
const statusCode = error.statusCode || 500;
const statusText = error.statusText || "Internal Server Error";
const message = error.message || "An unexpected error occurred";
return new Response(
JSON.stringify({
status: "fail",
message: `${statusCode} ${statusText}: ${message}`,
}),
{ status: statusCode, headers: { "Content-Type": "application/json" } }
);
}
};
}
Then, in your route handler:
// app/api/example/route.ts
import { withErrorHandling } from '../utils/errorHandler';
async function handler(request: Request) {
// ...your logic
throw new NotFoundException("No route found");
}
export const GET = withErrorHandling(handler);
This approach is not mentioned as a built-in feature in the documentation, but it follows the documented pattern of using try/catch in each handler and allows you to keep your per-route code minimal and consistent see docs.
Note: You still need to wrap each handler, but this is the minimal and recommended approach given the current capabilities of Next.js App Router. There is no way to apply this globally to all routes without explicitly using the wrapper in each file.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@molten swan Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@earnest wagon Okay, now can you modify that code to use "fail" and "error" statuses. "error" is when its an exception (not manually thrown). "fail" is when its manually thrown exception.
Let me check the knowledge base for you again. Give me one moment! :books:
The knowledge sources do not provide a built-in or recommended way to distinguish between "manually thrown" and "unexpected" exceptions in Next.js Route Handlers. However, the official documentation does recommend using try/catch in each handler and formatting your error responses as needed see docs.
To implement your desired logic, you would need to define a custom error class for "fail" (manually thrown) errors, and treat all other errors as "error" (unexpected exceptions). Here’s how you could structure this, minimizing per-route code:
// app/api/utils/errorHandler.ts
export class FailException extends Error {
statusCode: number;
statusText: string;
constructor(message: string, statusCode = 400, statusText = "Bad Request") {
super(message);
this.statusCode = statusCode;
this.statusText = statusText;
}
}
export function withErrorHandling(handler: (request: Request) => Promise<Response>) {
return async function(request: Request) {
try {
return await handler(request);
} catch (error: any) {
const isFail = error instanceof FailException;
const statusCode = error.statusCode || 500;
const statusText = error.statusText || "Internal Server Error";
const message = error.message || "An unexpected error occurred";
return new Response(
JSON.stringify({
status: isFail ? "fail" : "error",
message: `${statusCode} ${statusText}: ${message}`,
}),
{ status: statusCode, headers: { "Content-Type": "application/json" } }
);
}
};
}
Usage in a route:
// app/api/example/route.ts
import { withErrorHandling, FailException } from '../utils/errorHandler';
async function handler(request: Request) {
// Manually thrown error (will be "fail")
throw new FailException("No route found", 404, "Not Found");
// Or, for unexpected errors, just throw new Error("...") or let errors bubble up
}
export const GET = withErrorHandling(handler);
This pattern is consistent with the documented approach of using try/catch and custom error formatting in each handler [see docs](<https://nextjs.org/docs/app/guides/backend-for-frontend#proxying-to-a-backend>). There is no built-in or global mechanism for this in Next.js App Router.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
@molten swan Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@earnest wagon I'd prefer an Exception class, and then classes that extend or impleemnt it. Like NotFoundException. I'd also include the predefined statusText and statusCode. Still have an option for a message for all exceptions.
Let me check the knowledge base for you again. Give me one moment! :books:
The knowledge sources do not provide a built-in Exception class hierarchy for API error handling in the Next.js App Router. However, they do recommend using try/catch in each handler and formatting your error responses as needed, and they show that you can create utility functions to minimize repetition see docs.
To achieve your goal, you can define a base Exception class and extend it for specific cases like NotFoundException, each with predefined statusCode and statusText, while still allowing a custom message. Here’s how you could structure this, following the recommended patterns:
// app/api/utils/Exception.ts
export class Exception extends Error {
statusCode: number;
statusText: string;
constructor(message: string, statusCode: number, statusText: string) {
super(message);
this.statusCode = statusCode;
this.statusText = statusText;
}
}
export class NotFoundException extends Exception {
constructor(message = "Resource not found") {
super(message, 404, "Not Found");
}
}
// You can add more exceptions as needed, e.g.:
export class BadRequestException extends Exception {
constructor(message = "Bad request") {
super(message, 400, "Bad Request");
}
}
Then, your error handler utility:
// app/api/utils/errorHandler.ts
import { Exception } from './Exception';
export function withErrorHandling(handler: (request: Request) => Promise<Response>) {
return async function(request: Request) {
try {
return await handler(request);
} catch (error: any) {
const isCustom = error instanceof Exception;
const statusCode = isCustom ? error.statusCode : 500;
const statusText = isCustom ? error.statusText : "Internal Server Error";
const message = error.message || "An unexpected error occurred";
return new Response(
JSON.stringify({
status: isCustom ? "fail" : "error",
message: ${statusCode} ${statusText}: ${message},
}),
{ status: statusCode, headers: { "Content-Type": "application/json" } }
);
}
};
}
And in your route handler:
```ts
// app/api/example/route.ts
import { withErrorHandling } from '../utils/errorHandler';
import { NotFoundException } from '../utils/Exception';
async function handler(request: Request) {
// Manually thrown error (will be "fail")
throw new NotFoundException("No route found");
}
export const GET = withErrorHandling(handler);
This approach is consistent with the documented Next.js pattern of using try/catch and custom error formatting in each handler, and it keeps your per-route code minimal see docs.
There is no built-in or global mechanism for this in Next.js App Router, so this utility-based approach is the most maintainable and DRY solution available within the current framework.