Part 51: Enhancing Error Handling in Next.js with Custom Error Classes

[Pages] Data Fetching

[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

Here'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

  • ApiError Class: 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 status property allows us to check the HTTP status code when handling errors.

  • Stack Trace: If supported by the environment, captureStackTrace helps 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 ApiError and 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

  1. Precision: By using ApiError, we can precisely handle different error scenarios, improving the user experience.

  2. Clarity: Detailed error messages help developers quickly identify issues during development and debugging.

  3. 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