Create a custom API cache using KV in a Cloudflare Worker
Posted on September 24, 2024
Why use KV in Cloudflare Workers?
When exposing data via an API, especially one that frequently fetches data from a database, you might face performance issues or unnecessary costs if the database is queried too often.
A solution is to cache the response in Cloudflare KV storage to reduce load and improve response times.
Steps
Set up KV Namespace First, create a namespace for your KV storage in the Cloudflare dashboard:
- Go to Workers & KV.
- Create a new KV Namespace.
Fetching from Cache Whenever a request comes in, the first step is to check if there’s already a cached response in KV:
res = await env.my_kv_namespace.get(request.url);
Here, env.my_kv_namespace
refers to your KV namespace, and request.url
acts as a cache key. If there's an existing cached response, you can return it immediately:
if (res) {
return new Response(res, {
status: 200,
headers: { 'Cache-Control': 'no-cache' }
});
}
Setting the Cache If there's no cached response, fetch the data (e.g., from a database), then store the result in KV for future use:
await env.my_kv_namespace.put(request.url, JSON.stringify(payload), { expirationTtl: CACHE_TTL });
payload
is the data you want to cache.CACHE_TTL
is the expiration time (in seconds) for how long the cached data should be stored.
Example Workflow
- Client makes a request to your API.
- Cloudflare Worker checks KV storage for a cached response using
request.url
as the key. - If a cached response exists, it returns that response.
- If not, it fetches the data from your database, stores it in KV, and then returns the fresh data.
This approach minimizes database hits and speeds up the response times for your API.
Code Example
In this code, we first check KV storage for the cached response and serve it if available. Otherwise, we fetch data from the database, cache it, and then serve it. The cache TTL is set to 1 hour (3600
seconds).
async function handleRequest(request, env) {
// Check if the response is already cached
let cachedResponse = await env.my_kv_namespace.get(request.url);
if (cachedResponse) {
return new Response(cachedResponse, {
status: 200,
headers: { 'Cache-Control': 'no-cache' }
});
}
// Fetch data from your database (simulated here)
const payload = { data: 'Fetched from DB' }; // Replace with real fetch logic
// Cache the response
await env.my_kv_namespace.put(request.url, JSON.stringify(payload), { expirationTtl: 3600 });
return new Response(JSON.stringify(payload), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
}
This method is efficient, scalable, and reduces strain on your database while providing faster responses to repeated API calls.
Hope this helps!