Skip to content

Instantly share code, notes, and snippets.

@etdev
Last active April 29, 2024 13:28
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save etdev/bb49f0f60ea5ec9deb5977b1fbfb4046 to your computer and use it in GitHub Desktop.
Save etdev/bb49f0f60ea5ec9deb5977b1fbfb4046 to your computer and use it in GitHub Desktop.
Algolia cache proxy - Cloudflare worker
const ALGOLIA_APP_ID = "<your algolia app id>";
addEventListener('fetch', event => {
try {
const request = event.request;
if (request.method.toUpperCase() === 'POST') return event.respondWith(handlePostRequest(event));
return handleRequest(request);
} catch (e) {
return event.respondWith(new Response('Error thrown ' + e.message));
}
});
async function handleRequest(request) {
const algoliaUrl = new URL(request.url);
algoliaUrl.host = `${ALGOLIA_APP_ID}-dsn.algolia.net`;
const algoliaRequest = new Request(algoliaUrl, {
body: request.body,
headers: request.headers,
method: request.method,
redirect: request.redirect
});
let response = await fetch(algoliaRequest);
// Reconstruct the Response object to make its headers mutable.
response = new Response(response.body, response);
response.headers.delete("cache-control");
response.headers.set("Access-Control-ALlow-Origin", "*");
response.headers.set("Access-Control-ALlow-Methods", "GET,HEAD,POST,OPTIONS");
return response;
}
// post caching
async function handlePostRequest(event) {
const request = event.request;
const dupRequest = request.clone();
// assumes JSON body
const body = await dupRequest.json();
// Hash the request body to use it as a part of the cache key
const hash = await sha256(JSON.stringify(body));
const cacheUrl = new URL(request.url);
// Store the URL in cache by prepending the body's hash
cacheUrl.pathname = '/posts' + cacheUrl.pathname + hash;
// Convert to a GET to be able to cache
const cacheKey = new Request(cacheUrl.toString(), {
headers: request.headers,
method: 'GET',
});
const cache = caches.default;
// Find the cache key in the cache
let response = await cache.match(cacheKey);
// if not in cache, fetch response to POST request from origin + cache it
if (!response) {
response = await handleRequest(request);
event.waitUntil(cache.put(cacheKey, response.clone()));
}
return response;
}
async function sha256(message) {
// encode as UTF-8
const msgBuffer = new TextEncoder().encode(message);
// hash the message
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
// convert bytes to hex string
return [...new Uint8Array(hashBuffer)].map(b => b.toString(16).padStart(2, '0')).join('');
}
@andyg5000
Copy link

Hey @etdev

I was writing something similar and came across your gist. In my case, it processes the request, but I'm still getting CF-Cache-Status: DYNAMIC and showing hits in the Algolia API logs repeated requests. Did you have to do anything else to get the cached response to return ?

Thanks!

@andyg5000
Copy link

Actually looks like it's working. I must not have been patient enough with the rollout of the worker. Thanks for putting this together and sharing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment