How to Revalidate a Next.js Dynamic Route Manually Using an API Route?

In my application built with Next.js, I have a dynamic page that displays resources at the route /resource/[id]. When a user edits a resource, such as #5, I want to refresh the cached page at /resource/5.

I've created an API route in my /pages directory to handle resource editing. According to what I've read, I should be able to trigger a refresh of the display route using:

response.revalidate(`/resource/${id}/`);

However, this approach is not working as expected, and it's throwing an error:

Error: Failed to revalidate /resource/2153/: Invalid response 200
    at revalidate (/home/jeremy/GoblinCrafted/next/node_modules/next/dist/server/api-utils/node.js:388:15)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
- error unhandledRejection: Error: Failed to revalidate /resource/2153/: Invalid response 200
    at revalidate (/home/jeremy/GoblinCrafted/next/node_modules/next/dist/server/api-utils/node.js:388:15)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  digest: undefined

It seems like Next.js attempts to revalidate through an HTTP request, but perhaps the revalidation endpoint has been moved? The reason for this failure remains unclear to me.

UPDATE: Upon investigating the Next source code, I discovered that the revalidate function sends a simulated request to the route being refreshed. In the file

node_modules/next/dist/server/router.js
, you can see:

async revalidate({ urlPath , revalidateHeaders , opts  }) {
        const mocked = (0, _mockrequest.createRequestResponseMocks)({
            url: urlPath,
            headers: revalidateHeaders
        });
        const handler = this.getRequestHandler();
        await handler(new _node.NodeNextRequest(mocked.req), new _node.NodeNextResponse(mocked.res));
        await mocked.res.hasStreamed;
        if (mocked.res.getHeader("x-nextjs-cache") !== "REVALIDATED" && !(mocked.res.statusCode === 404 && opts.unstable_onlyGenerated)) {
            throw new Error(`Invalid response ${mocked.res.statusCode}`);
        }

The error message originates from the final throw statement, which puzzles me because when I log urlPath, it matches the path I'm attempting to refresh (e.g., /resource/5). Requesting this path via GET (in the browser or Postman) yields a 200 status code rather than a redirect.

To address this, I appended a slash / to the end of the path:

response.revalidate(`/resource/${id}/`);

This resulted in a similar error, albeit concerning a 200 response instead of a 308:

Error: Invalid response 200

Evidently, the actual status code isn't crucial; the issue lies within the condition

mocked.res.getHeader("x-nextjs-cache") !== "REVALIDATED"
. Although this header setting occurs deep within the router code, I couldn't figure out why the mock request fails to activate it, especially since other requests do reach that part despite
isSSG && !this.minimalMode
being true for all.

Furthermore, I attempted to use revalidatePath from next/cache:

revalidatePath(`/resource/[id]`);

Unfortunately, this method triggered another error:

revalidatePath(`/resource/[id]`);

Error: Invariant: static generation store missing in revalidateTag /resource/[id]
    at revalidateTag (/home/me/project/next/node_modules/next/dist/server/web/spec-extension/revalidate-tag.js:15:15)
    at revalidatePath (/home/me/project/next/node_modules/next/dist/server/web/spec-extension/revalidate-path.js:13:45)
    at handler (webpack-internal:///(api)/./pages/api/resource.js:88:67)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

My assumption is that revalidatePath is designed solely for usage within the /app directory.

Finally, I stumbled upon response.unstable_revalidate, supposedly tailored for refreshing dynamic paths:

response.unstable_revalidate(`/resource/${id}/`);

Despite trying this approach, the method does not exist on the response object:

TypeError: response.unstable_revalidate is not a function
    at handler (webpack-internal:///(api)/./pages/api/resource.js:88:18)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Answer №1

Consider the following options for improving your Next.js website:

`return { paths, fallback: 'blocking' }`
According to the Next.js documentation:
{ fallback: 'blocking' } will server-render pages on-demand if the path doesn't exist.

Another option is to adjust your getStaticProps function by either removing revalidate: true or setting it to false.

As per Next.js Documentation: If revalidate is omitted, Next.js will use the default value of false (no revalidation) and only revalidate the page on-demand when revalidate() is called.

Answer №3

Based on my research, using res.revalidate seems to be the recommended method, but I seem to have encountered a bug of some kind. I've submitted a report to the Vercel team over at https://github.com/vercel/next.js/issues/54420, and now I'm patiently awaiting their response.

Answer №4

There are a couple of issues that need addressing:

The functions revalidate and revalidatePath should only be utilized in GET handlers, not API routes. Since your editing handler is set up as an API route, it will not function properly.

In Next 11, unstable_revalidate has been eliminated in favor of the new invalidation API.

Here's the recommended approach moving forward:

Within your API route, make use of the new invalidation API:

const { invalidatePages } = require('next/dist/server/router')

// ...

await invalidatePages('/resource/[id]')

Include a revalidation hook in getStaticPaths:

export async function getStaticPaths() {
  // ...

  return {
    paths: paths,
    fallback: true
  }
}

export async function getStaticProps({ params }) {
  // ...

  return {
    props: {},
    revalidate: 10 // revalidate every 10 seconds
  }
}

This will prompt Next to re-render the dynamic page upon invalidation.

Key points to remember:

- Employ invalidatePages from API routes to initiate rebuilds - Integrate revalidation configuration in getStaticProps so that Next is aware of when to re-render

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Unable to display toast notification in React/MUI/Typescript project

Currently tackling error notifications targeted at 400,401, and 500 errors within a large-scale project. I am facing an issue where I want to integrate my ErrorToastNotification component into my layout.tsx file to avoid duplicating it across multiple page ...

Error: The call stack has reached the maximum size limit in nodejs and reactjs

When I attempt to submit the token received from my registration using the code snippet below, I encounter an error stating "maximum call stack exceeded." exports.activationController = (req, res) => { const { token } = req.body; exports.activation ...

Using jQuery to target adjacent elements excluding those that are separated by other text

I have been attempting to locate and combine adjacent em tags within paragraphs, but it has proven to be a more challenging task than I initially anticipated. Let's explore some examples to illustrate this issue: <p><em>Hello</em>&l ...

Retrieve Header information when making a cross-domain AJAX request

I've been working on a way to validate image URLs by using an AJAX call to check if the image is still available. The challenge I'm facing is that the image server is on a different domain, so I included the crossDomain: true attribute in my AJAX ...

Encountered an issue when executing "npm start": The system does not recognize 'next' as a valid internal or external command

Encountering an issue when running the "npm start" command in the terminal while attempting to create a cryptocurrency tracker using React.js Displayed contents of my package.json file: { "name": "nextjs-crypto-api", "version ...

What steps can be taken to customize this code in order to develop a dictation application?

Currently, I have a code that functions by comparing two strings: str2 (which represents user input) and str1 (our reference string). The purpose is to determine whether any words in str2 are spelled correctly or incorrectly. So far, the code works well. H ...

How can I bind the ID property of a child component from a parent component in Angular 2 using @Input?

I have a unique requirement in my parent component where I need to generate a child component with a distinct ID, and then pass this ID into the child component. The purpose of passing the unique ID is for the child component to use it within its template. ...

Initiate the printing process by executing the window.print() function. As the document is being

Here's the code snippet : <body> <div class="headerCont noprint"> <div class="headerHold"> <div class="logoCont"><img src="images/logo.jpg" width="104" height="74" alt="Logo"> ...

What causes my code to break completely when I import something?

My chrome extension has a simple function that retrieves a user's selected text using the Chrome Tabs API. I am looking to integrate a Hugging Face API in the future, but I am facing an issue. Whenever I try to import the necessary model, the Chrome T ...

Setting attributes to a DOM element using String in jQuery

I am currently facing a challenge where I have a list of attributes saved as a string variable, and I need to add that variable to a <div>. Unfortunately, I am stuck and uncertain about the best approach. Here is what I have so far: HTML: <div&g ...

Tips for sending get parameter data to a component in React

Currently, I am utilizing react (next.js) to develop a basic application. The specific issue I am facing involves creating a form in both add and edit modes. Depending on whether the get parameter contains 'edit', the form makes certain API calls ...

What is the best approach to transfer information from the client side to a node

I have an ejs page that looks like this: <%- include('../blocks/header', {bot, user, path}) %> <div class="row" style="min-width: 400px;"> <div class="col" style="min-width: 400px;"> <div class="card text-white mb-3" & ...

Fill the input field with data retrieved from a json file

I'm working on a Rails app where I need to populate a field with a value from JSON that is returned after clicking on a link. Can anyone point me to a tutorial that explains how to use Ajax correctly for this purpose? Here's my plan: 1. Send a G ...

React-router-sitemap lacks a definition for 'Require'

According to the official documentation here, this is how the sitemap-builder.js file should be structured: require('babel-register'); const router = require('./router').default; const Sitemap = require('../').default; ( ...

Unusual behavior experienced with raycasting in Three JS when objects are are repositioned

Software Versions THREE.ObjectLoader2: 2.4.1 THREE.LoaderSupport.MeshBuilder: 1.2.1 THREE.LoaderSupport.WorkerSupport: 2.2.0 THREE.WebGLRenderer: 93 THREE.REVISION: 93 Anomalies Discovered During a raycast operation on objects within my scene, I encount ...

Having trouble retrieving the selected date from the Material-Ui datepicker after the first selection

I am facing an issue with the material-ui dateandtimepicker where I am unable to retrieve the date value on the first select. The value only shows up after the second click, and it's always the previous one. Is there a way to convert the date to a for ...

Incorporate pictures from the popup onto the main page

I have developed a basic PHP image editor script where users can select images from galleries and merge them together. However, I am facing an issue: The galleries open in a popup while the editor area is on the parent page. I am looking for a JavaScript ...

What steps can I take to prevent Internet Explorer from caching my webpage?

After implementing Spring MVC for Angular JS on the front end, I encountered an issue where logging in with different user credentials resulted in incorrect details being displayed. This problem only occurred in Internet Explorer, requiring me to manually ...

React Next.js failing to trigger useEffect hook on live application

Recently, in my Next.js/React application, some previously functional pages began to exhibit strange behavior. Specifically, certain Axios requests within a useEffect hook are no longer being sent at all. Additional Information: The problematic file is a ...

Error message from OpenAI GPT-3 API: "openai.completions function not found"

I encountered an issue while trying to execute the test code from a tutorial on building a chat app with GPT-3, ReactJS, and Next.js. The error message I received was: TypeError: openai.completions is not a function This occurred when running the follow ...