npm package: @keeex/boilerplate-express
Description: Utility code to spin up an express server
Author: KeeeX SAS
Latest version: 2.1.4

# @keeex/boilerplate-express

[![Bugs](https://devtools.keeex.me/sonar/api/project_badges/measure?project=boilerplate-express&metric=bugs&token=sqb_e696c7167015af958780e9d9959c202bf255d955)](https://devtools.keeex.me/sonar/dashboard?id=boilerplate-express)
[![Code Smells](https://devtools.keeex.me/sonar/api/project_badges/measure?project=boilerplate-express&metric=code_smells&token=sqb_e696c7167015af958780e9d9959c202bf255d955)](https://devtools.keeex.me/sonar/dashboard?id=boilerplate-express)
[![Maintainability Rating](https://devtools.keeex.me/sonar/api/project_badges/measure?project=boilerplate-express&metric=sqale_rating&token=sqb_e696c7167015af958780e9d9959c202bf255d955)](https://devtools.keeex.me/sonar/dashboard?id=boilerplate-express)
[![Security Rating](https://devtools.keeex.me/sonar/api/project_badges/measure?project=boilerplate-express&metric=security_rating&token=sqb_e696c7167015af958780e9d9959c202bf255d955)](https://devtools.keeex.me/sonar/dashboard?id=boilerplate-express)
[![Vulnerabilities](https://devtools.keeex.me/sonar/api/project_badges/measure?project=boilerplate-express&metric=vulnerabilities&token=sqb_e696c7167015af958780e9d9959c202bf255d955)](https://devtools.keeex.me/sonar/dashboard?id=boilerplate-express)
[![Technical Debt](https://devtools.keeex.me/sonar/api/project_badges/measure?project=boilerplate-express&metric=sqale_index&token=sqb_e696c7167015af958780e9d9959c202bf255d955)](https://devtools.keeex.me/sonar/dashboard?id=boilerplate-express)
[![Coverage](https://devtools.keeex.me/sonar/api/project_badges/measure?project=boilerplate-express&metric=coverage&token=sqb_e696c7167015af958780e9d9959c202bf255d955)](https://devtools.keeex.me/sonar/dashboard?id=boilerplate-express)

This library contains a handful of utilities to perform common setup actions when running an express
server.
Express servers are commonly defined as an "app" object, which defines how the routes are handled,
and is then started as a listening server.
This library provides facilities to define the "app" and start he server.

## Defining the "app"

An "app" can be created by calling the `createPipeline()` function:

```javascript
import express from "express";
import {createPipeline} from "@keeex/boilerplate-express/lib/express.js";

export const app = express();
app.use(createPipeline({
  topLevels: [],
  routes: [],
  statics: [],
  postStatics: [],
  errorHandlers: [],
  options: {
    log: {},
    middleware: {
      urlencoded: false,
      text: false,
      raw: false,
      json: true,
    },
    defaultErrorHandler: true,
  }
});
```

Most options are optional.
The most important properties are:

- `topLevels` : middlewares and routes that go before anything else
- `routes` : application routes
- `statics` : serve static files from express (this will happen after routes)
- `postStatics` : routes that are registered after statics
- `errorHandlers` : custom express error handlers
- `options.middleware` : enable some common middleware for populating `body`

More detailed info can be found in the TSDoc.

### Defining routes

`topLevels`, `routes` and `postStatics` are arrays of handlers.
Each handler can be either another Router (for route composition), a simple handler without route
specification (a simple `req, res, next` function), or a complete route definition in the form of an
object with the following properties:

- route: the route to handle
- handler: the route handler (or an array, or a Router)
- method: the method this route should handle. Defaults to "get".

### Defining error handlers

The `errorHandlers` property accept an array of functions that follow the express "error handler"
kind of functions (four parameters: `err`, `req`, `res` and `next`).
If provided, and if the default error handler is set, they will be called before it.

### Providing statics

To serve static files, the `statics` property can be used.
It's an array of either directly the path to a directory, in which case it will be served at the
root of the service, or an object with the following properties:

- root: The directory where the static files are
- options: The options to pass to express static handler
- route: The route under which the static files will be served

### Logging and timeout

The logging system will log all routes as soon as they arrive, log their final output, and implement
a timeout mechanism.
The default configuration logs everything.

The `options.log` property allows some customization of the logging system; see the tsdoc.

Individual routes can prevent logging some properties from the body using `bodyLogger()`.

```JavaScript
router.post(
  "/login",
  bodyLogger(
    ["login"],
    req => ({
      passwordLength: req.body.password.length,
    }),
  ),
  processLogin,
);
```

In addition to excluding properties from the body of a request and adding custom properties, it can
be useful to always identify a request coming from a logged-in user.

You can provide a `authFromReq` property to the `options.log` configuration.
It should be a function that receive `req` as its argument and returns a string identifying the
logged-in user.

If a request is expected to take longer than the configured timeout, use `timeoutRefresh()`.
If your code use callback-based code that breaks the logging, you can wrap the callback function with `logBind()`.

#### Server shutting down

A pending timeout can prevent a program from shutting down.
An event can be sent on the Express application called "keeexRayCloseEvent" (there is a constant named `rayCloseEvent` in `consts.js`) to disarm all pending timeout.

If you use `appStart()`, the server closing will automatically emit this event.
If you want to send the event manually, use:

```javascript
app.emit(rayCloseEvent);
```

Also note that a pending _request_ will prevent the server from triggering its own "close" event until the request completes.
Meaning if a request is pending (no response sent and the request was not destroyed), the close event from the server will not trigger immediately.
And since its that event that will kill all timeout, it is possible to end in a situation where a loose request still prevent the process from closing.

Make sure to either use `appStart()` or send the event as needed, and not have open requests.

### Configuring global aspects of an Express App

#### Configuring the template engine

A helper is provided to setup a template engine on the whole Express application.

```JavaScript
import {setViewEngine} from "@keeex/boilerplate-express/lib/express.js";

const app = express();
setViewEngine(app, "pug", "webres/views", {});
```

The last parameter is optional; if provided it will define values available to the template engine.

## Running the server

Once the express application is defined, it need to be started to serve files and resources.
A helper is provided to do so, using the `appStart()` function.

```JavaScript
import {consoleLogger} from "@keeex/boilerplate-express/lib/winston.js";
import app from "./app.js";
import {appStart} from "@keeex/boilerplate-express/lib/express.js";

appStart({
  app,
  listenInterface: false,
  port: 3000,
  shutdownFunction: () => {;},
  logger: consoleLogger,
  noReady: false,
}).then(({port, server}) => {;});
```

The settings are:

- listenInterface: listen only to localhost or not. Can also be used to specify the address of an
  interface to bind to.
- port: port to listen to. Can be 0 to use a random available port
- shutdownFunction: a function to call after the server stop listening
- logger: a winston logger to log that the server started listening
- noReady: if true, does not call `process.send("ready");` (used by PM2)

The shutdown function can return a promise, and if it returns/resolve with `true` the process is
left alive.
Otherwise `process.exit()` is called after `shutdownFunction()` resolves/returns.

The `appStart()` function returns a promise that resolve with the actual port used for listening
when the server is started.

The server is automatically registered using the `autoclose` part to stop when a SIGINT signal is
received.

### Extra middleware

### singlepageapp

If you want to serve a statically built webapp based on a single html entrypoint, you can use the
middleware provided in `/lib/express/middlewares/singlepageapp.js`.

Basic usage:

```JavaScript
import express from "express";
import {singlePageApp} from "@keeex/boilerplate-express/lib/middlewares/singlepageapp.js";

const someRouter = express.Router();
someRouter.use("/app", singlePageApp({rootDir: "dist/webapp"});
```

Available config options are:

- `rootDir`: mandatory, root directory containing the SPA
- `htmlFile`: optional, name of the HTML file to serve (defaults to "index.html")
- `staticRootDirectories`: optional, name of directories (in the above root directory) to serve as
  static files. Defaults to `["js", "css", "img"]`.

A convenience command is available as "serve_spa" to be called from the command line.
It is possible to pass it some parameters; run it with `--help` for more informations.