From e7fbb90e5929faa49fbbc1a9f504066c4894a3a2 Mon Sep 17 00:00:00 2001 From: 0xkenj1 Date: Thu, 22 Aug 2024 18:18:18 -0300 Subject: [PATCH] feat: add 60s caching to api --- apps/api/package.json | 3 +- .../src/common/middleware/cache.middleware.ts | 36 +++++++++++++++++++ apps/api/src/metrics/routes/index.ts | 5 +-- pnpm-lock.yaml | 23 ++++++++++++ 4 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 apps/api/src/common/middleware/cache.middleware.ts diff --git a/apps/api/package.json b/apps/api/package.json index 08bc78e..72e241a 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -17,15 +17,16 @@ "test:cov": "vitest run --config vitest.config.ts --coverage" }, "dependencies": { + "@zkchainhub/chain-providers": "workspace:*", "@zkchainhub/metrics": "workspace:*", "@zkchainhub/pricing": "workspace:*", - "@zkchainhub/chain-providers": "workspace:*", "@zkchainhub/shared": "workspace:*", "bignumber.js": "9.1.2", "cache-manager": "5.7.6", "cors": "2.8.5", "dotenv": "16.4.5", "express": "4.19.2", + "node-cache": "5.1.2", "swagger-ui-express": "5.0.1", "viem": "2.19.6", "yaml": "2.5.0", diff --git a/apps/api/src/common/middleware/cache.middleware.ts b/apps/api/src/common/middleware/cache.middleware.ts new file mode 100644 index 0000000..c6fec22 --- /dev/null +++ b/apps/api/src/common/middleware/cache.middleware.ts @@ -0,0 +1,36 @@ +import { NextFunction, Request, Response } from "express"; +import NodeCache from "node-cache"; + +const DEFAULT_TTL = 60; // 1 minute +const cache = new NodeCache(); + +//FIXME: This is a temporary cache implementation. It is not recommended for production use. +// might be replaced with a more robust solution in the future. +/** + * A middleware that caches responses for a given time to live (TTL). + * @param args - The time to live (TTL) in seconds for the cached response. + * @returns A middleware function that caches responses for a given time to live (TTL). + */ +export function cacheMiddleware(args: { ttl: number } = { ttl: DEFAULT_TTL }) { + return async (req: Request, res: Response, next: NextFunction): Promise => { + const key = req.originalUrl || req.url; + const cachedResponse = await cache.get(key); + if (cachedResponse) { + // Check if the cached response is a JSON object or plain text + res.json(cachedResponse); + } else { + // Store the original send and json functions + const originalJson = res.json.bind(res); + // Override the json function + + res.json = (body): Response => { + // Cache the response body + cache.set(key, body, args.ttl); + // Call the original json function with the response body + return originalJson(body); + }; + + next(); + } + }; +} diff --git a/apps/api/src/metrics/routes/index.ts b/apps/api/src/metrics/routes/index.ts index a9d6026..5f13414 100644 --- a/apps/api/src/metrics/routes/index.ts +++ b/apps/api/src/metrics/routes/index.ts @@ -2,6 +2,7 @@ import { z } from "zod"; import { ILogger } from "@zkchainhub/shared"; +import { cacheMiddleware } from "../../common/middleware/cache.middleware.js"; import { BaseRouter } from "../../common/routes/baseRouter.js"; import { ChainNotFound, MetricsController } from "../index.js"; @@ -27,7 +28,7 @@ export class MetricsRouter extends BaseRouter { * Retrieves the ecosystem information. * @returns {Promise} The ecosystem information. */ - this.router.get("/ecosystem", async (_req, res, next) => { + this.router.get("/ecosystem", cacheMiddleware(), async (_req, res, next) => { try { const data = await this.metricsController.getEcosystem(); res.json(data); @@ -42,7 +43,7 @@ export class MetricsRouter extends BaseRouter { * @param {number} chainId - The ID of the chain. * @returns {Promise} The chain information. */ - this.router.get("/zkchain/:chainId", async (req, res, next) => { + this.router.get("/zkchain/:chainId", cacheMiddleware(), async (req, res, next) => { try { const { params } = ChainIdSchema.parse(req); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8fc392..13eec1e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -103,6 +103,9 @@ importers: express: specifier: 4.19.2 version: 4.19.2 + node-cache: + specifier: 5.1.2 + version: 5.1.2 swagger-ui-express: specifier: 5.0.1 version: 5.0.1(express@4.19.2) @@ -2087,6 +2090,13 @@ packages: } engines: { node: ">=12" } + clone@2.1.2: + resolution: + { + integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==, + } + engines: { node: ">=0.8" } + color-convert@1.9.3: resolution: { @@ -3679,6 +3689,13 @@ packages: integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==, } + node-cache@5.1.2: + resolution: + { + integrity: sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==, + } + engines: { node: ">= 8.0.0" } + node-releases@2.0.14: resolution: { @@ -6102,6 +6119,8 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + clone@2.1.2: {} + color-convert@1.9.3: dependencies: color-name: 1.1.3 @@ -7006,6 +7025,10 @@ snapshots: neo-async@2.6.2: {} + node-cache@5.1.2: + dependencies: + clone: 2.1.2 + node-releases@2.0.14: {} npm-run-path@5.3.0: