This is a small docker-deployable app that listens for contract events and revalidates static pages on Next.js.
Starting with v12.2.0
Next.js supports On-Demand Incremental Static Regeneration. This app takes advantage of that and allows to regenerate a given path on contract events. You can grab the event args to generate the path, or use a static one.
The app assumes you have set up and endpoint allowing POST requests on Next.js, and will a request with the following body:
{
"secret": "<REVALIDATE_TOKEN>",
"path": "<path_to_revalidate>"
}
On the app side, you'll need to provide:
- A config file
config.json
- The contracts ABIs
- The revalidate token
REVALIDATE_TOKEN
On the Next.js side, you'll need to set up the API endpoint to revalidate, as we'll see below.
Most configuration is done adding a folder config
on the root and putting inside a config.json
file. If running from docker, you'll need to add a volume on /config
.
Sample config.json
:
{
"provider": "<provider_url>",
"events": [
{
"signature": "PostCreated(uint256)",
"contract": {
"address": "0x03c626D63410e79Aa31329e8Afb270A7c3C823A7",
"name": "Blog"
},
"api": {
"url": "<website_url>/api/revalidate",
"path": "/[0]"
}
}
]
}
In this sample config file, we'll be revalidating the path /[0]
where [0]
will be replaced by the first argument of the event. So if the event was
PostCreated(1)
then the path to revalidate will be
/1
This can be extended to as many events you want and form the path with as many args you want.
The contract ABIs must be put inside a abi
folder on the root. They must have the same name as the contract name defined in the config file. In the sample given, we should provide an abi with the name Blog.json
.
The ABI should follow the following format:
{
"abi": ["..."]
}
The revaldation token or secret is provided through an env variable REVALIDATE_TOKEN
.
On the Next.js side, you'll need to create an API endpoint that allows to send a body with a secret
and a path
to revalidate.
Sample:
import type { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const body = req.body as { path?: string; secret?: string };
if (body.secret === undefined) {
return res.status(400).json({ message: "Missing token" });
}
if (body.secret !== process.env.REVALIDATE_TOKEN) {
return res.status(401).json({ message: "Invalid token" });
}
if (body.path === undefined) {
return res.status(400).json({ message: "Missing path" });
}
try {
await res.revalidate(body.path);
return res.json({ revalidated: true });
} catch (err) {
return res.status(500).send("Error revalidating");
}
}
To run this app as a docker container you can use for example the following command:
docker run \
-e REVALIDATE_TOKEN=<my_token> \
-v <my_config_folder>:/app/config \
-v <my_abis_folder>:/app/abi \
revalidate-on-event
Or on docker-compose:
version: "3"
services:
revalidate-on-event:
image: revalidate-on-event
environment:
- REVALIDETE_TOKEN=<my_token>
volumes:
- <my_config_folder>:/app/config
- <my_abis_folder>:/app/abi
restart: unless-stopped
Collaborating is welcomed! This was done in a short period of time, when I found I needed this feature on a project I was building. There are probably a lot of edge cases I haven't thought of, but I think this is a good start point.