Created
April 20, 2022 18:38
-
-
Save nibtime/2b169edbea14f4a6a684724d2e909363 to your computer and use it in GitHub Desktop.
instantly publish DatoCMS pages with Next 12.1 On-Demand ISR
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// pages/api/webhooks/datocms/revalidate-pages.function.ts | |
// custom page extensions in next.config.js: pageExtensions: ['page.tsx', 'function.ts', 'page.jsx', 'function.js'], | |
import type { NextApiRequest, NextApiResponse } from 'next'; | |
import { i18n } from 'next.config'; | |
import type { Payload } from './types'; | |
import { | |
getModelId, | |
getWebhookHeaders, | |
revalidateMultiplePaths, | |
} from './utils'; | |
const { defaultLocale } = i18n ?? {}; | |
const lookupModelApiKey = { | |
'1654963': 'composable_page', | |
'1654955': 'home_page', | |
'1654957': 'journal_article', | |
'1654956': 'journal_index', | |
} as const; | |
const modelApiKeys = Object.values(lookupModelApiKey); | |
type ModelApiKey = typeof modelApiKeys[0]; | |
const getModelApiKey = (payload: Payload): ModelApiKey | undefined => { | |
return lookupModelApiKey[getModelId(payload)]; | |
}; | |
const getSlugsWithLocale = ( | |
payload: Payload | |
): [locale: string, slug: string][] => { | |
return Object.entries<string>(payload?.entity?.attributes?.slug ?? {}); | |
}; | |
const getRevalidatePaths = (payload: Payload) => { | |
const modelApiKey = getModelApiKey(payload); | |
return getSlugsWithLocale(payload).flatMap(([locale, slug]) => { | |
const localePrefixed = locale !== defaultLocale ? `/${locale}` : ''; | |
if (modelApiKey === 'home_page') { | |
return [localePrefixed || '/']; | |
} | |
if (modelApiKey === 'journal_index') { | |
return [`${localePrefixed}/journal`]; | |
} | |
if (modelApiKey === 'composable_page') { | |
return [`${localePrefixed}/${slug}`]; | |
} | |
if (modelApiKey === 'journal_article') { | |
return [`${localePrefixed}/journal/${slug}`, `${localePrefixed}/journal`]; | |
} | |
return []; | |
}); | |
}; | |
const revalidatePages = async (req: NextApiRequest, res: NextApiResponse) => { | |
const revalidatePaths = getRevalidatePaths(req.body); | |
try { | |
const allRevalidated = await revalidateMultiplePaths( | |
res, | |
revalidatePaths | |
).then((results) => | |
results.every((result) => result.status === 'fulfilled') | |
); | |
res.json({ allRevalidated }); | |
} catch (err) { | |
// If there was an error, Next.js will continue | |
// to show the last successfully generated page | |
res.status(500).send('Error revalidating'); | |
} finally { | |
res.end(); | |
} | |
}; | |
export default async function handler( | |
req: NextApiRequest, | |
res: NextApiResponse | |
) { | |
const { secret } = getWebhookHeaders(req); | |
// Check for secret to confirm this is a valid request | |
if (secret !== process.env.PREVIEW_SECRET) { | |
return res.status(401).json({ message: 'Invalid token' }); | |
} | |
return revalidatePages(req, res); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// pages/api/webhooks/datocms/types.ts | |
export type Entity = { | |
id: string; | |
type: string; | |
meta: Record<string, any>; | |
attributes: Record<string, any>; | |
relationships: Record<string, any>; | |
}; | |
export type Payload = { | |
environment: string; | |
event_type: string; | |
entity_type: string; | |
entity: Entity; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// pages/api/webhooks/datocms/utils.ts | |
import type { NextApiRequest, NextApiResponse } from 'next'; | |
import type { Payload } from './types'; | |
export const getWebhookHeaders = (req: NextApiRequest) => { | |
return { | |
siteId: req.headers['x-site-id']?.toString() ?? '', | |
webhookId: req.headers['x-webhook-id']?.toString() ?? '', | |
environment: req.headers['x-environment']?.toString() ?? '', | |
// this has to be added to the webhook config in DatoCMS dashboard | |
secret: req.headers['x-webhook-secret']?.toString() ?? '', | |
}; | |
}; | |
export const getModelId = (payload: Payload): string => { | |
return payload?.entity?.relationships?.item_type?.data?.id || ''; | |
}; | |
export const revalidateMultiplePaths = async ( | |
res: NextApiResponse, | |
paths: string[] | |
) => { | |
const revalidate = res.unstable_revalidate.bind(res); | |
return Promise.allSettled(paths.map(revalidate)); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Webhook Setup in DatoCMS