Node.js Service Tools
Prepare your Node.js application for production!
This library provides common functionalities, like graceful error handling & shutdown, structured JSON logging and several HTTP middleware to make your application truly ready for modern containerised environments, like Kubernetes.
Installation
npm i @banzaicloud/service-tools
yarn add @banzaicloud/service-tools
Usage & Examples
This library is written in TypeScript, refer to the published types or the source code for argument and return types.
Examples are available for Express and Koa frameworks. Check out the examples folder!
Main exports
catchErrors(options)
Catch uncaught exceptions and unhandled Promise rejections. It is not safe to resume normal operation after 'uncaughtException'.
const { catchErrors } = require('@banzaicloud/service-tools')
catchErrors([closeServer, closeDB])
throw new Error()
gracefulShutdown(handlers, options)
Graceful shutdown: release resources (databases, HTTP connections, ...) before exiting. When the application receives SIGTERM
or SIGINT
signals, the close handlers will be called. The handlers should return a Promise
.
const { gracefulShutdown } = require('@banzaicloud/service-tools')
gracefulShutdown([closeServer, closeDB])
logger
A pino structured JSON logger instance configured with config.pino
.
const { logger } = require('@banzaicloud/service-tools')
logger.info({ metadata: true }, 'log message')
Use provided logger instead of console
Globally overwrite the console
and use the logger provided by the library to print out messages.
const { logger } = require('@banzaicloud/service-tools')
console.log('log message')
logger.interceptConsole()
console.log('log message')
Config
Load configurations dynamically.
config.environment
Uses the NODE_ENV
environment variable, with accepted values of: production, development, test.
const { config } = require('@banzaicloud/service-tools')
console.log(config.environment)
config.pino
Used by the provided logger. Uses the LOGGER_LEVEL
and LOGGER_REDACT_FIELDS
environment variables. The LOGGER_LEVEL
can be one of the following: fatal, error, warn, info, debug, trace. LOGGER_REDACT_FIELDS
is a comma separated list of field names to mask out in the output (defaults to: 'password, pass, authorization, auth, cookie, _object'
).
const pino = require('pino')
const { config } = require('@banzaicloud/service-tools')
const logger = pino(config.pino)
logger.info({ metadata: true, password: 'secret' }, 'log message')
Middleware (Koa)
Several middleware for the Koa web framework.
errorHandler(options)
Koa error handler middleware.
const Koa = require('koa')
const { koa: middleware } = require('@banzaicloud/service-tools').middleware
const app = new Koa()
app.use(middleware.errorHandler())
healthCheck(checks, options)
Koa health check endpoint handler.
const Koa = require('koa')
const Router = require('koa-router')
const { koa: middleware } = require('@banzaicloud/service-tools').middleware
const app = new Koa()
const router = new Router()
router.get('/health', middleware.healthCheck([checkDB]))
app.use(router.routes())
app.use(router.allowedMethods())
prometheusMetrics(options)
Koa Prometheus metrics endpoint handler. By default it collects some default metrics.
const Koa = require('koa')
const Router = require('koa-router')
const { koa: middleware } = require('@banzaicloud/service-tools').middleware
const app = new Koa()
const router = new Router()
router.get('/metrics', middleware.prometheusMetrics())
app.use(router.routes())
app.use(router.allowedMethods())
requestValidator(options)
Koa request validator middleware. Accepts Joi schemas for body
(body parser required), params
and query
(query parser required). Returns with 400
if the request is not valid. Assigns validated values to ctx.state.validated
.
const joi = require('@hapi/joi')
const qs = require('qs')
const Koa = require('koa')
const Router = require('koa-router')
const bodyParser = require('koa-bodyparser')
const { koa: middleware } = require('@banzaicloud/service-tools').middleware
const app = new Koa()
const router = new Router()
const paramsSchema = joi
.object({
id: joi
.string()
.hex()
.length(64)
.required(),
})
.required()
const bodySchema = joi.object({ name: joi.string().required() }).required()
const querySchema = joi.object({ include: joi.array().default([]) }).required()
router.get(
'/',
middleware.requestValidator({ params: paramsSchema, body: bodySchema, query: querySchema }),
async function routeHandler(ctx) {
const { params, body, query } = ctx.state.validated
}
)
app.use(bodyParser())
app.use(async function parseQuery(ctx, next) {
ctx.query = qs.parse(ctx.querystring, options)
ctx.request.query = ctx.query
await next()
})
app.use(router.routes())
app.use(router.allowedMethods())
requestLogger(options)
Koa request logger middleware. Useful for local development and debugging.
const Koa = require('koa')
const { koa: middleware } = require('@banzaicloud/service-tools').middleware
const app = new Koa()
app.use(middleware.requestLogger())
Middleware (Express)
Several middleware for the Express web framework.
errorHandler(options)
Express error handler middleware.
const express = require('express')
const { express: middleware } = require('@banzaicloud/service-tools').middleware
const app = express()
app.use(middleware.errorHandler())
healthCheck(checks, options)
Express health check endpoint handler.
const express = require('express')
const { express: middleware } = require('@banzaicloud/service-tools').middleware
const app = express()
app.get('/health', middleware.healthCheck([checkDB]))
prometheusMetrics(options)
Express Prometheus metrics endpoint handler. By default it collects some default metrics.
const express = require('express')
const { express: middleware } = require('@banzaicloud/service-tools').middleware
const app = express()
app.get('/metrics', middleware.prometheusMetrics())
requestValidator(options)
Express request validator middleware. Accepts Joi schemas for body
(body parser required), params
and query
. Returns with 400
if the request is not valid. Assigns validated values to req
.
const joi = require('@hapi/joi')
const express = require('express')
const { express: middleware } = require('@banzaicloud/service-tools').middleware
const app = express()
const paramsSchema = joi
.object({
id: joi
.string()
.hex()
.length(64)
.required(),
})
.required()
const bodySchema = joi.object({ name: joi.string().required() }).required()
const querySchema = joi.object({ include: joi.array().default([]) }).required()
app.use(express.json())
app.get(
'/',
middleware.requestValidator({ params: paramsSchema, body: bodySchema, query: querySchema }),
function routeHandler(req, res) {
const { params, body, query } = req
}
)