Add caching to feed endpoint (#45)
In order to reduce load on Deno KV as the costs are relatively high.
This commit is contained in:
parent
4e0ea3b324
commit
e81d59f2aa
|
|
@ -1,5 +1,5 @@
|
|||
import { assertEquals, assertNotEquals } from "$std/assert/mod.ts";
|
||||
import { responseJSON, responseXML } from "./utils.ts";
|
||||
import { responseJSON, responseXML, withExpiry } from "./utils.ts";
|
||||
|
||||
Deno.test("JSON response is stringified", async () => {
|
||||
const body = { message: "Hello, World!" };
|
||||
|
|
@ -14,3 +14,41 @@ Deno.test("XML resopnse is _not_ stringified", async () => {
|
|||
assertEquals(responseBody, body);
|
||||
assertNotEquals(responseBody, JSON.stringify(body));
|
||||
});
|
||||
|
||||
Deno.test(
|
||||
"Response with cache control returns a response with the correct header",
|
||||
() => {
|
||||
const response = responseJSON({ message: "Hello, World!" }, 200);
|
||||
const cachedResponse = withExpiry(response, 3600);
|
||||
assertEquals(cachedResponse.headers.get("Cache-Control"), "max-age=3600");
|
||||
},
|
||||
);
|
||||
|
||||
Deno.test(
|
||||
"Response with cache control returns the same body as the original",
|
||||
async () => {
|
||||
const body = { message: "Hello, World!" };
|
||||
const response = responseJSON(body, 200);
|
||||
const cachedResponse = withExpiry(response, 3600);
|
||||
assertEquals(await cachedResponse.text(), await response.text());
|
||||
},
|
||||
);
|
||||
|
||||
Deno.test("Response with cache control does not modify the original", () => {
|
||||
const response = responseJSON({ message: "Hello, World!" }, 200);
|
||||
withExpiry(response, 3600);
|
||||
assertEquals(response.headers.get("Cache-Control"), null);
|
||||
});
|
||||
|
||||
Deno.test(
|
||||
"Response with cache control returns the correct number of seconds",
|
||||
() => {
|
||||
const response = responseJSON({ message: "Hello, World!" }, 200);
|
||||
const ttlInSeconds = 1234;
|
||||
const cachedResponse = withExpiry(response, ttlInSeconds);
|
||||
assertEquals(
|
||||
cachedResponse.headers.get("Cache-Control"),
|
||||
`max-age=${ttlInSeconds}`,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,12 @@ export function responseXML(body: string, status: Status) {
|
|||
return response(body, status, "xml");
|
||||
}
|
||||
|
||||
export const withExpiry = <T>(response: Response, ttlInSeconds: number) => {
|
||||
const clonedResponse = response.clone();
|
||||
clonedResponse.headers.set("Cache-Control", `max-age=${ttlInSeconds}`);
|
||||
return clonedResponse;
|
||||
};
|
||||
|
||||
function response(body: string, status: number, type: "json" | "xml") {
|
||||
return new Response(body, {
|
||||
status,
|
||||
|
|
|
|||
|
|
@ -1,18 +1,36 @@
|
|||
import { FreshContext, STATUS_CODE } from "$fresh/server.ts";
|
||||
import { caching } from "../../../lib/caching.ts";
|
||||
import { rss } from "../../../lib/rss.ts";
|
||||
import { responseJSON, responseXML } from "../../../lib/utils.ts";
|
||||
import { responseJSON, responseXML, withExpiry } from "../../../lib/utils.ts";
|
||||
|
||||
export const handler = async (_req: Request, ctx: FreshContext): Promise<Response> => {
|
||||
const FEED_CACHE_KEY = "feeds-cache";
|
||||
|
||||
export const handler = async (
|
||||
request: Request,
|
||||
ctx: FreshContext,
|
||||
): Promise<Response> => {
|
||||
const seriesId = ctx.params.seriesId;
|
||||
|
||||
const cache = await caches.open(FEED_CACHE_KEY);
|
||||
const cachedResponse = await cache.match(request);
|
||||
if (cachedResponse) {
|
||||
console.log(`Cache hit for feed ${seriesId}`);
|
||||
return cachedResponse;
|
||||
}
|
||||
|
||||
const series = await caching.getSeries({ id: seriesId });
|
||||
if (!series) {
|
||||
return responseJSON({ message: "Series not found" }, STATUS_CODE.NotFound);
|
||||
}
|
||||
|
||||
const feed = rss.assembleFeed(series);
|
||||
|
||||
const xml = responseXML(feed, STATUS_CODE.OK);
|
||||
const response = withExpiry(
|
||||
responseXML(feed, STATUS_CODE.OK),
|
||||
// 2 hours
|
||||
60 * 60 * 2,
|
||||
);
|
||||
|
||||
return xml;
|
||||
await cache.put(request, response.clone());
|
||||
return response;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue