Revalidar páginas de NextJS desde Wagtail

A partir de v12.2.0, Next.js soporta On-Demand Incremental Static Regeneration para purgar manualmente la caché de Next.js para una página específica.

En este artículo, veremos cómo esto se puede integrar con un despliegue headless de Wagtail para solicitar automáticamente a nuestro frontend NextJS que revalide las páginas cuando se crean o actualizan.

Creación de la ruta API de revalidación en NextJS

Empezaremos creando un endpoint de la API para permitir la revalidación bajo demanda en nuestra aplicación NextJS.

Para ello crearemos el siguiente fichero: pages/api/revalidate/[...path].ts con el siguiente contenido:

import type { NextApiRequest, NextApiResponse } from "next";

type ResponseMessage = {
  message: string;
  results?: any;
  err?: string;
};


export default async (
  req: NextApiRequest,
  res: NextApiResponse<ResponseMessage>
) => {
  if (req.method === "GET") {
    // Authentication
    const token = req.headers.token || null;
    if (token !== process.env.CMS_REVALIDATE_TOKEN) {
      return res.status(403).json({ message: "error", err: "Not authorized" });
    }

    try {
      const { path } = req.query;
      await res.revalidate(`/${(path as Array<string>).join("/")}`);
      res.status(200).json({
        message: "ok",
        results: "Revalidated",
      });
    } catch (err) {
      console.log(err);
      res.status(500).json({
        message: "error",
        err: "Error occured while revalidating page.",
      });
    }
  } else {
    // Only POST supported
    res.status(405).json({ message: "error", err: "Method not supported" });
  }
};

El código anterior utiliza la variable de entorno CMS_REVALIDATE_TOKEN para autenticar las peticiones contra un token recibido como cabecera y después de eso, obtiene la ruta que necesita ser revalidada de la ruta de la petición y la pasa a la función revalidate.

Integración con Wagtail

En el lado de Wagtail, empezaremos creando una función de utilidad que simplemente reciba la ruta que necesitamos revalidar, lea el FRONTEND_REVALIDATION_TOKEN necesario para realizar la solicitud de revalidación desde la configuración de django y realice la solicitud de revalidación.

Un ejemplo de código para hacer esto se puede encontrar a continuación:

from django.conf import settings
import requests
import logging

logger = logging.getLogger(__name__)


def revalidate_frontend_page(path: str):
    response = requests.get(
        f"https://example.com/api/revalidate/{path.lstrip('/')}",
        headers={"token": settings.FRONTEND_REVALIDATION_TOKEN},
    )
    if response.status_code != 200:
        logger.error(
            f"Received a response with status code {response.status_code} revalidating {path}"
        )

Ahora podemos utilizar las signals Wagtail existentes para la publicación y despublicación de páginas, para engancharnos a cuando una página se publica o despublica y solicitar a nuestro frontend NextJS que revalide esa página utilizando la función revalidate_frontend_page.

El siguiente código debe ser colocado en un archivo signals.py y muestra cómo se podría hacer:

from django.dispatch import receiver
from wagtail.signals import page_published, page_unpublished
from wagtail.models import Page
from myapp.utils import revalidate_frontend_page


@receiver(page_published, sender=Page)
def after_page_publish_signal(sender, instance, **kwargs):
    revalidate_frontend_page(instance.get_url())


@receiver(page_unpublished, sender=Page)
def after_page_unpublish_signal(sender, instance, **kwargs):
    revalidate_frontend_page(instance.get_url())