From 5738ead5fb4c46ef78614abffa0a13564626d0b2 Mon Sep 17 00:00:00 2001 From: Alexandru Gologan Date: Sat, 28 Oct 2023 10:19:09 +0300 Subject: [PATCH] Cache supegraph in memory --- src/helpers/middleware.ts | 43 +++++++++++++++++++++++++++++++++++++++ src/logger.ts | 6 +++++- src/router/index.ts | 18 ++++++++++++---- 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/helpers/middleware.ts b/src/helpers/middleware.ts index 38627940..6e30ac57 100644 --- a/src/helpers/middleware.ts +++ b/src/helpers/middleware.ts @@ -1,5 +1,48 @@ +import { logger } from '../logger'; + export function asyncWrap(fn) { return (req, res, next) => { Promise.resolve(fn(req, res, next)).catch(next); }; } + +export function cache(key) { + return (req, res, next) => { + const locals = req.app.locals; + if (!locals.cache) { + locals.cache = {}; + } + + const cached = locals.cache[key]; + if (cached) { + logger.info(`Sending cached: ${key}`); + res.set(cached.headers); + return res.send(cached.body); + } else { + res.__send = res.send; + res.send = (body) => { + locals.cache[key] = { + body, + headers: res.getHeaders(), + }; + res.__send(body); + logger.info(`Cached: ${key}`); + }; + } + next(); + }; +} + +export function invalidate(key) { + return (req, res, next) => { + const locals = req.app.locals; + if (!locals.cache) { + return next(); + } + + logger.info(`Invalidating: ${key}`); + delete locals.cache[key]; + + return next(); + }; +} diff --git a/src/logger.ts b/src/logger.ts index 26f1a3bd..7de299c2 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -31,10 +31,14 @@ export const logger = createLogger({ function buildPrettyFormat() { return format.combine( + format.errors({ stack: true }), format.colorize(), format.timestamp(), format.printf(({ timestamp, level, message, stack }) => { - return `[${timestamp}] ${level}: ${message} ${stack}`; + if (stack) { + return `[${timestamp}] ${level}: ${message} ${stack}`; + } + return `[${timestamp}] ${level}: ${message}`; }) ); } diff --git a/src/router/index.ts b/src/router/index.ts index 96e3d4fc..cd7c2ddb 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -2,7 +2,7 @@ import express from 'express'; // eslint-disable-next-line new-cap const router = express.Router(); import { json } from 'body-parser'; -import { asyncWrap } from '../helpers/middleware'; +import { asyncWrap, cache, invalidate } from '../helpers/middleware'; import parseMiddleware from '../middleware/parse-request'; import { indexHtml, assetRouter } from './assets'; @@ -46,18 +46,28 @@ router.get( router.get('/', indexHtml()); assetRouter(router); +const supergraphKey = 'supergraph'; + router.get('/persisted_query', asyncWrap(persistedQuery.get)); router.post('/persisted_query', asyncWrap(persistedQuery.create)); router.get('/schema/latest', asyncWrap(schema.composeLatest)); -router.get('/schema/supergraph', asyncWrap(schema.supergraph)); +router.get( + '/schema/supergraph', + cache(supergraphKey), + asyncWrap(schema.supergraph) +); router.post('/schema/compose', asyncWrap(schema.compose)); -router.post('/schema/push', asyncWrap(schema.push)); +router.post('/schema/push', invalidate(supergraphKey), asyncWrap(schema.push)); router.post('/schema/diff', asyncWrap(schema.diff)); router.delete('/schema/:schemaId', asyncWrap(schema.remove)); router.post('/schema/validate', asyncWrap(schema.validate)); -router.delete('/service/:name', asyncWrap(service.remove)); +router.delete( + '/service/:name', + invalidate(supergraphKey), + asyncWrap(service.remove) +); export default router;