Skip to content

Instantly share code, notes, and snippets.

@nirzaq
Created March 8, 2018 04:11
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nirzaq/85e84d2bb0fc4a3ed17aab014e47885f to your computer and use it in GitHub Desktop.
Save nirzaq/85e84d2bb0fc4a3ed17aab014e47885f to your computer and use it in GitHub Desktop.
Cache API Call and Cache rendered pages in Next.js
const express = require("express");
const cors = require("cors")
const { join } = require("path");
const { parse } = require("url");
const next = require("next");
const fetch = require("isomorphic-unfetch")
const LRUCache = require('lru-cache')
const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
const apicache = require("apicache")
const server = express();
let cache = apicache.middleware
const API_URL = `https://api.rss2json.com/v1/api.json?rss_url=https%3A%2F%2Fmedium.com%2Ffeed%2Fwwwid`
server.get('/api/feed', cors(), cache('60 minutes'), (req, res) => {
fetch(API_URL)
.then( r => r.json() )
.then( data => {
res.json(data)
});
console.log("API SERVED..")
});
// This is where we cache our rendered HTML pages
const ssrCache = new LRUCache({
max: 100,
maxAge: 1000 * 60 * 60 // 1hour
})
app
.prepare()
.then(() => {
server.get('/', (req, res) => {
renderAndCache(req, res, '/')
})
server.get("/articles/:title", (req, res) => {
const actualPage = "/article";
const queryParams = { title: req.params.title };
renderAndCache(req, res, actualPage, queryParams);
});
server.get("/category/:cat", (req, res) => {
const actualPage = "/category";
const queryParams = { cat: req.params.cat };
renderAndCache(req, res, actualPage, queryParams);
});
server.get("*", (req, res) => {
const parsedUrl = parse(req.url, true);
const { pathname } = parsedUrl;
if (pathname === "/service-worker.js") {
const filePath = join(__dirname, ".next", pathname);
app.serveStatic(req, res, filePath);
} else {
handle(req, res, parsedUrl);
}
});
server.listen(3000, err => {
if (err) throw err;
console.log("> Ready on http://localhost:3000");
});
})
.catch(ex => {
console.error(ex.stack);
process.exit(1);
});
/*
* NB: make sure to modify this to take into account anything that should trigger
* an immediate page change (e.g a locale stored in req.session)
*/
function getCacheKey (req) {
return `${req.url}`
}
async function renderAndCache (req, res, pagePath, queryParams) {
const key = getCacheKey(req)
// If we have a page in the cache, let's serve it
if (ssrCache.has(key)) {
res.setHeader('x-cache', 'HIT')
res.send(ssrCache.get(key))
return
}
try {
// If not let's render the page into HTML
const html = await app.renderToHTML(req, res, pagePath, queryParams)
// Something is wrong with the request, let's skip the cache
if (res.statusCode !== 200) {
res.send(html)
return
}
// Let's cache this page
ssrCache.set(key, html)
res.setHeader('x-cache', 'MISS')
res.send(html)
} catch (err) {
app.renderError(err, req, res, pagePath, queryParams)
}
}
@anhdn
Copy link

anhdn commented Apr 1, 2020

Currently, have you used it on production?

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