Skip to content

Instantly share code, notes, and snippets.

@nirzaq
Created March 8, 2018 04:11
Show Gist options
  • Select an option

  • Save nirzaq/85e84d2bb0fc4a3ed17aab014e47885f to your computer and use it in GitHub Desktop.

Select an option

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)
}
}
@replynodes-ai

Copy link
Copy Markdown

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