Part 51: Enhancing Error Handling in Next.js with Custom Error Classes
[Pages] Data Fetching

In web development, handling errors gracefully is as important as developing features. It ensures a seamless user experience even when things go wrong. In our Next.js application, we initially set up a generic error handling mechanism that returned a "not found" page for any error encountered while fetching product data. However, this approach was too broad and could mislead users by indicating a non-existent product when the issue might be a temporary server outage. In this post, we'll refine our error handling by introducing a custom error class for more nuanced responses.
Introducing Fine-Grained Error Handling
The Problem
Our initial solution returned a 404 "not found" page for all errors, which wasn't ideal. We wanted to display a 404 page only when a product truly doesn't exist, not for every possible error, such as a network issue or server downtime.
The Solution: Custom Error Class
To address this, we created a custom error class, ApiError, which extends the built-in Error class. This allows us to capture more specific error details and handle them appropriately.
Creating the ApiError Class
ApiError ClassHere's how we implemented our custom error class:
// lib/api.js
export class ApiError extends Error {
constructor(url, status) {
super(`'${url}' returned ${status}`);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, ApiError);
}
this.name = 'ApiError';
this.status = status;
}
}
export async function fetchJson(url) {
const response = await fetch(url);
if (!response.ok) {
throw new ApiError(url, response.status);
}
return await response.json();
}Explanation
ApiErrorClass: This class captures the URL and status code of a failed HTTP request, providing more context about the error.Error Message: The error message includes the URL and status, making it clearer what went wrong.
Status Property: The
statusproperty allows us to check the HTTP status code when handling errors.Stack Trace: If supported by the environment,
captureStackTracehelps preserve the stack trace, aiding in debugging.
For more information on custom error types, visit the MDN documentation.
Updating the Product Page
With our custom error class in place, we updated the ProductPage to handle errors more effectively:
// pages/products/[id].js
import Head from 'next/head';
import Title from '../../components/Title';
import { ApiError } from '../../lib/api';
import { getProduct, getProducts } from '../../lib/products';
export async function getStaticProps({ params: { id } }) {
try {
const product = await getProduct(id);
return {
props: { product },
revalidate: 30, // seconds
};
} catch (err) {
if (err instanceof ApiError && err.status === 404) {
return { notFound: true };
}
throw err;
}
}Explanation
Error Handling: We check if the error is an instance of
ApiErrorand specifically a 404 status. Only then do we return a "not found" page.Re-throw Other Errors: For other types of errors, we re-throw them, allowing Next.js to handle them as unexpected server errors.
Benefits of Custom Error Handling
Precision: By using
ApiError, we can precisely handle different error scenarios, improving the user experience.Clarity: Detailed error messages help developers quickly identify issues during development and debugging.
Scalability: This approach sets a foundation for handling more complex error scenarios as the application grows.
Conclusion
Custom error classes like ApiError provide a structured way to handle errors more effectively in your applications. By capturing detailed information about errors, you can make more informed decisions about how to present them to users. This not only enhances the user experience but also aids developers in maintaining and debugging the application. Remember, refining error handling is an ongoing process, and as your application evolves, your error handling strategy should too.
Last updated