From 1aae0c61b89934863219f72d85db2db9355539bc Mon Sep 17 00:00:00 2001 From: Daniel Bachler Date: Sat, 17 Aug 2024 15:13:38 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20add=20fetching=20grapher=20configs?= =?UTF-8?q?=20by=20UUID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- functions/_common/grapherRenderer.ts | 40 +++++++++++++---- functions/grapher/[slug].ts | 6 ++- functions/grapher/by-uuid/[uuid].ts | 66 ++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 9 deletions(-) create mode 100644 functions/grapher/by-uuid/[uuid].ts diff --git a/functions/_common/grapherRenderer.ts b/functions/_common/grapherRenderer.ts index 8e4e42b9f89..2326d5442fd 100644 --- a/functions/_common/grapherRenderer.ts +++ b/functions/_common/grapherRenderer.ts @@ -166,8 +166,20 @@ interface FetchGrapherConfigResult { etag: string | undefined } +interface GrapherSlug { + type: "slug" + id: string +} + +interface GrapherUuid { + type: "uuid" + id: string +} + +type GrapherIdentifier = GrapherSlug | GrapherUuid + export async function fetchUnparsedGrapherConfig( - slug: string, + identifier: GrapherIdentifier, env: Env, etag?: string ) { @@ -178,10 +190,15 @@ export async function fetchUnparsedGrapherConfig( ? [env.GRAPHER_CONFIG_R2_BUCKET_PATH] : ["by-branch", env.CF_PAGES_BRANCH] + const directory = + identifier.type === "slug" + ? R2GrapherConfigDirectory.publishedGrapherBySlug + : R2GrapherConfigDirectory.byUUID + const key = excludeUndefined([ ...topLevelDirectory, - R2GrapherConfigDirectory.publishedGrapherBySlug, - `${slug}.json`, + directory, + `${identifier.id}.json`, ]).join("/") console.log("fetching grapher config from this key", key) @@ -197,8 +214,8 @@ export async function fetchUnparsedGrapherConfig( const topLevelDirectory = env.GRAPHER_CONFIG_R2_BUCKET_FALLBACK_PATH const fallbackKey = excludeUndefined([ topLevelDirectory, - R2GrapherConfigDirectory.publishedGrapherBySlug, - `${slug}.json`, + directory, + `${identifier.id}.json`, ]).join("/") fallbackUrl = new URL( fallbackKey, @@ -211,11 +228,15 @@ export async function fetchUnparsedGrapherConfig( } export async function fetchGrapherConfig( - slug: string, + identifier: GrapherIdentifier, env: Env, etag?: string ): Promise { - const fetchResponse = await fetchUnparsedGrapherConfig(slug, env, etag) + const fetchResponse = await fetchUnparsedGrapherConfig( + identifier, + env, + etag + ) if (fetchResponse.status === 404) { // we throw 404 errors instead of returning a 404 response so that the router @@ -253,7 +274,10 @@ async function fetchAndRenderGrapherToSvg( ): Promise { const grapherLogger = new TimeLogger("grapher") - const grapherConfigResponse = await fetchGrapherConfig(slug, env) + const grapherConfigResponse = await fetchGrapherConfig( + { type: "slug", id: slug }, + env + ) if (grapherConfigResponse.status === 404) { // we throw 404 errors instad of returning a 404 response so that the router diff --git a/functions/grapher/[slug].ts b/functions/grapher/[slug].ts index f1a8bfd9a48..50497a53b25 100644 --- a/functions/grapher/[slug].ts +++ b/functions/grapher/[slug].ts @@ -167,7 +167,11 @@ async function handleConfigRequest( const shouldCache = searchParams.get("nocache") === null console.log("Preparing json response for ", slug) - const grapherPageResp = await fetchUnparsedGrapherConfig(slug, env, etag) + const grapherPageResp = await fetchUnparsedGrapherConfig( + { type: "slug", id: slug }, + env, + etag + ) if (grapherPageResp.status === 304) { console.log("Returning 304 for ", slug) diff --git a/functions/grapher/by-uuid/[uuid].ts b/functions/grapher/by-uuid/[uuid].ts new file mode 100644 index 00000000000..9fcc75d7785 --- /dev/null +++ b/functions/grapher/by-uuid/[uuid].ts @@ -0,0 +1,66 @@ +import { Env } from "../../_common/env.js" +import { fetchGrapherConfig } from "../../_common/grapherRenderer.js" +import { IRequestStrict, Router, error, StatusError } from "itty-router" + +const router = Router() +router + .get( + "/grapher/by-uuid/:uuid.config.json", + async ({ params: { uuid } }, { searchParams }, env, etag) => + handleConfigRequest(uuid, searchParams, env, etag) + ) + .all("*", () => error(404, "Route not defined")) + +export const onRequest: PagesFunction = async (context) => { + const { request, env } = context + const url = new URL(request.url) + + return router + .fetch( + request, + url, + { ...env, url }, + request.headers.get("if-none-match") + ) + .catch((e) => { + if (e instanceof StatusError) { + return error(e.status, e.message) + } + + return error(500, e) + }) +} + +async function handleConfigRequest( + uuid: string, + searchParams: URLSearchParams, + env: Env, + etag: string | undefined +) { + const shouldCache = searchParams.get("nocache") === null + console.log("Preparing json response for uuid ", uuid) + + const grapherPageResp = await fetchGrapherConfig( + { type: "uuid", id: uuid }, + env, + etag + ) + + if (grapherPageResp.status === 304) { + return new Response(null, { status: 304 }) + } + + console.log("Grapher page response", grapherPageResp.grapherConfig.title) + + const cacheControl = shouldCache + ? "public, s-maxage=3600, max-age=0, must-revalidate" + : "public, s-maxage=0, max-age=0, must-revalidate" + + return new Response(JSON.stringify(grapherPageResp.grapherConfig), { + headers: { + "content-type": "application/json", + "Cache-Control": cacheControl, + ETag: grapherPageResp.etag, + }, + }) +}