// Ignore paths for logging, metrics and docs // Fast, minimalist web framework for node. import express from 'express' // Helmet helps you secure your Express app by setting various HTTP headers import helmet from 'helmet' // Fastest HTTP logger for Node.js in town import { logger } from './logger.js' import pinoHttp from 'pino-http' // Readiness and liveness checks middleware import health from '@cloudnative/health-connect' // Prometheus middleware for standard api metrics import promBundle from 'express-prom-bundle' // Swagger UI for api-docs import swaggerUi from 'swagger-ui-express' import yaml from 'js-yaml' import fs from 'fs' import fetch from 'node-fetch' const ignorePaths = ['/ready', '/healthy'] const logger = new Logger() const httpLogger = pinoHttp({ logger, autoLogging: { ignorePaths } }) const swaggerDocument = yaml.load(fs.readFileSync('./src/swagger.yaml', 'utf8')) const bypass = (request) => ignorePaths.includes(request.path) const metricsMiddleware = promBundle({ bypass }) export function createApp () { // The app returned by express() is in fact a JavaScript Function, designed to be passed to Node’s HTTP servers as a callback to handle requests. const app = express() const healthCheck = new health.HealthChecker() // Application-level middleware app.use(httpLogger) app.use(helmet()) app.use('/healthy', health.LivenessEndpoint(healthCheck)) app.use('/ready', health.ReadinessEndpoint(healthCheck)) app.use(metricsMiddleware) app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)) app.use('/swagger.json', (req, res) => res.json(swaggerDocument)) const urls = yaml.load(fs.readFileSync('./config/manifests/urls.yaml', 'utf8')).manifests let manifestCache = [] let lastCached app.timeout = 30000 const fetchManifest = async () => { if (+new Date() < lastCached + (app.timeout || 30000)) return const results = urls.map(url => fetch(url).then(result => { if (!result.ok) throw new Error(`Failed to load manifest for url ${result.url} (Status: ${result.status}: ${result.statusText})`) return result.json().catch(err => { throw new Error(`Failed to load manifest for url ${result.url}: ${err}`) }) })) manifestCache = (await Promise.all(results)).flat() lastCached = +new Date() } app.get('/api/manifest.json', async (req, res, next) => { try { await fetchManifest() res.json(manifestCache || []) } catch (err) { next(err) } }) app.use(function (err, req, res, next) { logger.error(err) res.status(500).end() }) return app }