From fdb7ab493b4c2697d543c09d12160ad6cc4ceec0 Mon Sep 17 00:00:00 2001 From: Amio / Date: Sun, 5 Aug 2018 08:40:10 +0800 Subject: [PATCH] feat: add api server (#74) Mainly two purposes: 1. Provide https://api.badgen.net 2. Serve this api behind Now CDN as a cache layer --- libs/index-api.md | 6 +++++ ...live-badge-handlers.js => live-fetcher.js} | 22 +-------------- libs/live-handlers.js | 27 +++++++++++++++++++ libs/serve-api.js | 26 ++++++++++++++++++ now.json | 4 +-- package.json | 4 +-- service.js | 17 +++++++++--- 7 files changed, 78 insertions(+), 28 deletions(-) create mode 100644 libs/index-api.md rename libs/{live-badge-handlers.js => live-fetcher.js} (50%) create mode 100644 libs/live-handlers.js create mode 100644 libs/serve-api.js diff --git a/libs/index-api.md b/libs/index-api.md new file mode 100644 index 0000000..790407a --- /dev/null +++ b/libs/index-api.md @@ -0,0 +1,6 @@ +# api.badgen.net + +## Examples + +- https://api.badgen.net/npm/v/micro +- https://api.badgen.net/npm/dependents/got diff --git a/libs/live-badge-handlers.js b/libs/live-fetcher.js similarity index 50% rename from libs/live-badge-handlers.js rename to libs/live-fetcher.js index bb077a9..693273f 100644 --- a/libs/live-badge-handlers.js +++ b/libs/live-fetcher.js @@ -1,26 +1,6 @@ -const { get } = require('micro-fork') -const liveFns = require('./live-fns/_index.js') -const serveBadge = require('./serve-badge.js') const waitings = {} // Cache ongoing fetching, prevent redundant request -module.exports = Object.entries(liveFns).map(([name, fn]) => { - return get(`/${name}/*`, async (req, res) => { - const style = req.headers.host === 'flat.badgen.net' ? 'flat' : undefined - const { - subject = name, - status = 'unknown', - color = 'grey', - failed = false - } = await fetchLiveParams(name, fn, req.params['*']) - - req.params = { subject, status, color, style } - serveBadge(req, res, { - maxAge: failed ? '0' : (Math.random() * 60 + 60).toFixed() - }) - }) -}) - -async function fetchLiveParams (scope, fn, paramsPath) { +module.exports = async function fetchLiveParams (scope, fn, paramsPath) { const fetchKey = `#${scope} ${paramsPath}` if (waitings[fetchKey]) return waitings[fetchKey] diff --git a/libs/live-handlers.js b/libs/live-handlers.js new file mode 100644 index 0000000..2e165c1 --- /dev/null +++ b/libs/live-handlers.js @@ -0,0 +1,27 @@ +const axios = require('./axios.js') +const { get } = require('micro-fork') +const liveFns = require('./live-fns/_index.js') +const serveBadge = require('./serve-badge.js') +const liveFetcher = require('./live-fetcher.js') + +const { API_HOST } = process.env + +module.exports = Object.entries(liveFns).map(([name, fn]) => { + return get(`/${name}/*`, async (req, res) => { + const { + subject = name, + status = 'unknown', + color = 'grey', + failed = false + } = await (API_HOST + ? axios(API_HOST + req.url).then(res => res.data) + : liveFetcher(name, fn, req.params['*']) + ) + + const style = req.headers.host === 'flat.badgen.net' ? 'flat' : undefined + req.params = { subject, status, color, style } + serveBadge(req, res, { + maxAge: failed ? '0' : (Math.random() * 60 + 60).toFixed() + }) + }) +}) diff --git a/libs/serve-api.js b/libs/serve-api.js new file mode 100644 index 0000000..b72574a --- /dev/null +++ b/libs/serve-api.js @@ -0,0 +1,26 @@ +const fs = require('fs') +const path = require('path') +const { send } = require('micro') +const { router, get } = require('micro-fork') +const liveFunctions = require('./live-fns/_index.js') +const liveFetcher = require('./live-fetcher.js') + +const CACHE_CONTROL = `public, max-age=60, stale-while-revalidate=86400, stale-if-error=86400` +const sMaxAges = { + 'github': '240' +} + +const apiHandlers = Object.entries(liveFunctions).map(([name, fn]) => { + return get(`/${name}/*`, async (req, res) => { + res.setHeader('Cache-Control', `${CACHE_CONTROL}, s-maxage=${sMaxAges[name] || '120'}`) + send(res, 200, await liveFetcher(name, fn, req.params['*'])) + }) +}) + +const indexContent = fs.readFileSync(path.join(__dirname, 'index-api.md'), 'utf8') +const serveIndex = (req, res) => send(res, 200, indexContent) + +module.exports = router()( + get('/', serveIndex), + ...apiHandlers +) diff --git a/now.json b/now.json index 13dcd76..350a8fa 100644 --- a/now.json +++ b/now.json @@ -2,9 +2,9 @@ "alias": [ "badgen", "badgen.net", - "flat.badgen.net" + "flat.badgen.net", + "api.badgen.net" ], - "public": true, "files": [ "package-lock.json", "service.js", diff --git a/package.json b/package.json index 22dcdde..feb5103 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,11 @@ "dev": "micro-dev service.js -s", "pretest": "npm run lint", "test": "tap test/*.js --reporter spec -j12", - "start": "micro service.js", + "start": "node service.js", "precanary": "now alias rm badgen-canary -y -T amio", "canary": "now -T amio && now alias badgen-canary -T amio", "predeploy": "now rm badgen-service --safe -y -T amio || true", - "deploy": "now -T amio && now alias -T amio" + "deploy": "now -T amio -e API_HOST='https://api.badgen.net'" }, "dependencies": { "axios": "^0.18.0", diff --git a/service.js b/service.js index 301122b..df04cdd 100644 --- a/service.js +++ b/service.js @@ -5,9 +5,10 @@ const serveIndex = require('./libs/serve-index.js') const serve404 = require('./libs/serve-404.js') const serveDocs = require('./libs/serve-docs.js') const serveBadge = require('./libs/serve-badge.js') -const liveBadgeHandlers = require('./libs/live-badge-handlers.js') +const liveHandlers = require('./libs/live-handlers.js') +const serveApi = require('./libs/serve-api.js') -module.exports = router()( +const main = router()( get('/*', serve404), get('/', serveIndex), get('/docs/:topic', serveDocs), @@ -15,9 +16,19 @@ module.exports = router()( get('/favicon.svg', serveFavicon), get('/badge/:subject/:status', (req, res) => serveBadge(req, res)), get('/badge/:subject/:status/:color', (req, res) => serveBadge(req, res)), - ...liveBadgeHandlers + ...liveHandlers ) +module.exports = function (req, res) { + switch (req.headers.host) { + case 'api.badgen.net': + case '127.0.0.1:3000': + return serveApi(req, res) + default: + return main(req, res) + } +} + if (require.main === module) { micro(module.exports).listen(3000) }