Strapi + Next.js refresh static props like it's cache
Tags: typescript, nextjs, tutorial, javascript
Published: 2023-02-23 01:08:08

## Intro
If you made a headless website or e-commerce, you've run into the issue that it didn't immediately refresh live after you changed your content? Relax; you're not alone!
I've been working on a cool [MedusaJS](http://medusajs.com/) project, and we had the problem that our SEO experts were working in [Strapi](https://strapi.io/) and didn't see their changes... Annoying when there are some minor or important edits you want to see live/in realtime.


## How does it work?
The solution is quite simple. Next.js has a feature called [Incremental Static Regeneration](https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration). This allows you to refresh the static props every x seconds, or what we desire: [on-demand revalidation](https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration#on-demand-revalidation). This function can be triggered by the [Strapi Webhook Events](https://docs.strapi.io/dev-docs/backend-customization/webhooks#available-events).


### On demand revalidation
In short, you execute a `revalidate` function with the correct URL path to perform the revalidation.
A small example:
```tsx
    await res.revalidate('/path-to-revalidate')
    return res.json({ revalidated: true })
```
One downside, you can only revalidate a specific path. No wildcards or whatsoever are allowed. Our goal is to revalidate a strapi content entry every time we update, publish or create it.


### Strapi webhook events
As simple as can be, register a webhook, fill in the correct URL, enable the right events, and you're ready to go!


### Requirements
To have this all working, we need one thing. Ensure the slug/path is known or can be generated with strapi information! 
In our example, we set a `slug` to every content type and made sure the content type name corresponds with our slug on the frontend.
( oke... fair enough.. one exception for pages )


## Let's create our solution!
First, we'll create the next.js solution. Our projects always use Typescript. For a javascript version, remove the types in the function variables.


### Next.js (Medusa.js with Next.js in our case)
**/src/pages/api/revalidate.tsx**
```tsx
import type { NextApiRequest, NextApiResponse } from "next"

export default async function handler(
    req: NextApiRequest,
    res: NextApiResponse
) {
    // or a secret from an environment variable
    if (req.query.secret !== "SomeRandomSecret")
        return res.status(401).json({ message: "Invalid token" })

    try {
        const { event, entry, model } = req.body
        switch (event) {
            case "entry.update":
            case "entry.create":
            case "entry.publish":
                await res.revalidate(
                    `${model !== "page" ? "/" + model : ""}/${entry?.slug ?? ""}`
                )
                break
            default:
                return res.status(500).send(`Invalid event "${event}"`)
                break
        }
        return res.json({ revalidated: true })
    } catch (err) {
        return res.status(500).send("Error revalidating")
    }
}

```
For this tutorial, I didn't [set an `Authorization` header](https://docs.strapi.io/dev-docs/backend-customization/webhooks#securing-your-webhooks) with bearer, but **I do recommend this!**

In our code, we check if the secret is valid, which event is fired, and what path to revalidate.


#### What if my paths don't correspond with my models?
No worries. You could setup a small object which maps your model to the correct path. Here is a quick example:
```tsx
const pathMaps = { blogContent: '/blog' }
//...
await res.revalidate(
    `${pathMaps[model]??""}/${entry?.slug ?? ""}`
)
```

### Strapi
Navigate to Settings --> Webhooks and click on `Create new webhook`.
![Settings --> Webhooks strapi](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/983zfqlqbrhh7p20t3wy.jpg)
Fill the fields accordingly with your domain and hit save.
![Strapi webhook setup](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v7vd499gcg8ltidjs85k.jpg)


### Done
That's it; go get yourself a coffee to celebrate! Whenever you change something in Strapi, your static props are invalidated in your Next.js frontend!

![Cat programmer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/egeu1iff15w77g0bkb86.jpg)


## Resources:
- [Starting Banner](https://ossi.dev/post/i-jam-stack-d-my-portfolio)
- [Data-cleaning icons created by Freepik - Flaticon](https://www.flaticon.com/free-icons/data-cleaning)
- [Strapi docs for webhooks](https://docs.strapi.io/dev-docs/backend-customization/webhooks)
- [Next.js - Data Fetching: Incremental Static Regeneration](https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration)