Include alphanumeric model IDs in Webhook payloads and Content Delivery API payloads

Is your feature request related to a problem? Please describe.
When processing webhook updates from the Content Delivery API, the alphanumeric model IDs (e.g. ‘article’) are not included, so we don’t know which models are involved without cross-referencing itemTypes for the models manually. Writing business logic against itemType IDs is painful and not scalable because we don’t know what they are by looking at them.

Describe the solution you’d like
Include the alphanumeric model ID (aka ItemType.attributes.api_key) in the Content Management API payloads) in the in both webhook payloads and Content Delivery API responses. Mocked webhook payload below, note the addition of relationships.item_type.key

Describe alternatives you’ve considered
The workaround requires us to grab a list of all models from the Content Management API, cache it on our own server for fast lookups, then cross-reference that in order to process webhook updates. Then create a webhook processor to watch for model changes in order to invalidate our cache of the model list.

Additional context

{
  "entity_type": "item",
  "event_type": "update",
  "entity": {
    "id": "1272501",
    "type": "item",
    "attributes": {
      "slug": "test1",
      "header1": "test",
      "header2": "Hello",
      "body": "Blah blah",
    },
    "relationships": {
      "item_type": {
        "data": {
          "id": "115919",
          "type": "item_type"
          "key": "article"
        }
      },
      "creator": {
        "data": {
          "id": "24999",
          "type": "access_token"
        }
      }
    },
    "meta": {
      "created_at": "2019-07-20T14:37:56.951-07:00",
      "updated_at": "2019-07-22T19:54:03.680-07:00",
      "published_at": "2019-07-22T19:54:03.680-07:00",
      "publication_scheduled_at": null,
      "first_published_at": "2019-07-20T14:37:56.967-07:00",
      "is_valid": true,
      "status": "published",
      "current_version": "2433169"
    }
  }
}

I’ve run into this too. It’s a perfectly good design using the IDs, but there are a few situations where it’d save a few roundtrips or a few levels of indirection in code to have the model names printed inline too.

1 Like

plus one for this :+1:

+1 on this one. Trying to build a webhook for Next new on-demand revalidation. Would be great to know which type of record was updated in the payload

1 Like

@bjornthief

I recently integrated on-demand ISR with a mutlilingual site: On-Demand ISR on publication with Next.JS 12.1. You can find a Gist there that has my solution.

Not having this feature requires a hardcoded workaround to obtain page paths to revalidate and this is bad, as numeric Model ID is not stable. Adding the stable alphanumeric Model ID to the webhook would rectify this.

+1 on this. Not a huge thing, solved it by making multiple webhooks with ?model=_ in the URL. Great feature and the debug log too. Nice work.

Here’s the reference:

import { revalidatePath } from "next/cache";
import { type NextRequest, NextResponse } from "next/server";
import { z } from "zod";

import { SUPPORTED_LOCALES } from "~/constants";

export const runtime = "edge";

const schema = z.object({
  environment: z.string(),
  entity_type: z.string(),
  event_type: z.string(),
  entity: z.object({
    id: z.string(),
    type: z.string(),
    attributes: z.object({ slug: z.string().optional() }),
    meta: z.object({
      created_at: z.coerce.date(),
      updated_at: z.coerce.date(),
      published_at: z.coerce.date(),
      publication_scheduled_at: z.coerce.date().nullable(),
      unpublishing_scheduled_at: z.coerce.date().nullable(),
      first_published_at: z.coerce.date(),
      is_valid: z.boolean(),
      is_current_version_valid: z.boolean(),
      is_published_version_valid: z.boolean(),
      status: z.string(),
      current_version: z.string(),
      stage: z.null(),
    }),
  }),
});

export async function POST(request: NextRequest) {
  const model = request.nextUrl.searchParams.get("model");
  const result = schema.safeParse(await request.json());

  if (!result.success) {
    console.warn("Couldn't parse");
    return NextResponse.json({});
  }

  if (model === "home_page") {
    revalidatePath("/");
  }

  if (model === "tour") {
    const slug = result.data.entity.attributes.slug;
    if (slug) {
      for (const locale of SUPPORTED_LOCALES) {
        const path = `/${locale}/tours-and-activities/${slug}-${result.data.entity.id}`;
        console.debug(`Invalidating ${path}`);
        revalidatePath(path);
      }
    }
  }

  return NextResponse.json({});
}

We just released Enhanced Webhook Payloads to solve this and many other similar cross-reference issues!