Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/banzaicloud/service-tools

Prepare your Node.js application for production
https://github.com/banzaicloud/service-tools

express koa kubernetes middleware prometheus shutdown

Last synced: about 2 months ago
JSON representation

Prepare your Node.js application for production

Awesome Lists containing this project

README

        


Node.js Service Tools


Prepare your Node.js application for production!



CircleCI


npm version

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](http://kubernetes.io/).

- [Installation](#installation)
- [Usage](#usage)
- [Main exports](#main-exports)
- [`catchErrors(options)`](#catcherrorsoptions)
- [`gracefulShutdown(handlers, options)`](#gracefulshutdownhandlers-options)
- [`logger`](#logger)
- [Use provided logger instead of `console`](#use-provided-logger-instead-of-console)
- [Config](#config)
- [`config.environment`](#configenvironment)
- [`config.pino`](#configpino)
- [Middleware (Koa)](#middleware-koa)
- [`errorHandler(options)`](#errorhandleroptions)
- [`healthCheck(checks, options)`](#healthcheckchecks-options)
- [`prometheusMetrics(options)`](#prometheusmetricsoptions)
- [`requestValidator(options)`](#requestvalidatoroptions)
- [`requestLogger(options)`](#requestloggeroptions)
- [Middleware (Express)](#middleware-express)
- [`errorHandler(options)`](#errorhandleroptions-1)
- [`healthCheck(checks, options)`](#healthcheckchecks-options-1)
- [`prometheusMetrics(options)`](#prometheusmetricsoptions-1)
- [`requestValidator(options)`](#requestvalidatoroptions-1)

## Installation

```sh
npm i @banzaicloud/service-tools
# or
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](https://expressjs.com/) and [Koa](https://koajs.com/) frameworks. Check out the _[examples](/examples)_ folder!

### Main exports

#### `catchErrors(options)`

Catch uncaught exceptions and unhandled Promise rejections. It is not safe to resume normal operation after ['uncaughtException'](https://nodejs.org/api/process.html#process_event_uncaughtexception).

```js
const { catchErrors } = require('@banzaicloud/service-tools')

// ...

// the handlers return a Promise
// the handlers are called in order
catchErrors([closeServer, closeDB])

// the error will be caught and the handlers will be called before exiting
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`.

```js
const { gracefulShutdown } = require('@banzaicloud/service-tools')

// ...

// the handlers return a Promise
// the handlers are called in order
gracefulShutdown([closeServer, closeDB])
```

#### `logger`

A [pino](https://github.com/pinojs/pino) structured JSON logger instance configured with [`config.pino`](#config).

```js
const { logger } = require('@banzaicloud/service-tools')

logger.info({ metadata: true }, 'log message')
// > {"level":30,"time":,"msg":"log message","pid":0,"hostname":"local","metadata":true,"v":1}
```

##### Use provided logger instead of `console`

Globally overwrite the `console` and use the logger provided by the library to print out messages.

```js
const { logger } = require('@banzaicloud/service-tools')

console.log('log message')
// > log message

logger.interceptConsole()

console.log('log message')
// > {"level":30,"time":,"msg":"log message","pid":0,"hostname":"local","v":1}
```

### Config

Load configurations dynamically.

#### `config.environment`

Uses the `NODE_ENV` environment variable, with accepted values of: production, development, test.

```js
const { config } = require('@banzaicloud/service-tools')
// validates the NODE_ENV environment variable
console.log(config.environment)
// > { nodeEnv: 'production' }
```

#### `config.pino`

Used by the provided [logger](#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'`).

```js
const pino = require('pino')
const { config } = require('@banzaicloud/service-tools')

const logger = pino(config.pino)

logger.info({ metadata: true, password: 'secret' }, 'log message')
// > {"level":30,"time":,"msg":"log message","pid":0,"hostname":"local","metadata":true,"password":"[REDACTED]","v":1}
```

### Middleware (Koa)

Several middleware for the [Koa](https://koajs.com/) web framework.

#### `errorHandler(options)`

Koa error handler middleware.

```js
const Koa = require('koa')
const { koa: middleware } = require('@banzaicloud/service-tools').middleware

const app = new Koa()

// this should be the first middleware
app.use(middleware.errorHandler())
```

#### `healthCheck(checks, options)`

Koa health check endpoint handler.

```js
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()

// the checks return a Promise
router.get('/health', middleware.healthCheck([checkDB]))

app.use(router.routes())
app.use(router.allowedMethods())
```

#### `prometheusMetrics(options)`

Koa [Prometheus](https://prometheus.io/) metrics endpoint handler. By default it collects some [default metrics](https://github.com/siimon/prom-client#default-metrics).

```js
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](https://github.com/hapijs/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`.

```js
const joi = require('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())
// query parser
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.

```js
const Koa = require('koa')
const { koa: middleware } = require('@banzaicloud/service-tools').middleware

// ...

const app = new Koa()

// this should be the second middleware after the error handler
// ...
app.use(middleware.requestLogger())
```

### Middleware (Express)

Several middleware for the [Express](https://expressjs.com/) web framework.

#### `errorHandler(options)`

Express error handler middleware.

```js
const express = require('express')
const { express: middleware } = require('@banzaicloud/service-tools').middleware

const app = express()

// this should be the last middleware
app.use(middleware.errorHandler())
```

#### `healthCheck(checks, options)`

Express health check endpoint handler.

```js
const express = require('express')
const { express: middleware } = require('@banzaicloud/service-tools').middleware

// ...

const app = express()

// the checks return a Promise
app.get('/health', middleware.healthCheck([checkDB]))
```

#### `prometheusMetrics(options)`

Express [Prometheus](https://prometheus.io/) metrics endpoint handler. By default it collects some [default metrics](https://github.com/siimon/prom-client#default-metrics).

```js
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](https://github.com/hapijs/joi) schemas for `body` (body parser required), `params` and `query`. Returns with `400` if the request is not valid. Assigns validated values to `req`.

```js
const joi = require('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
// ...
}
)
```