Enable declarative configuration and mounting of expressjs routes.
This library exposes classes and methods that allow the definition of expressjs routes as distinct processing steps, making it easy to test the individual steps, and also allowing for declarative route definitions for the server.
When creating routes on a web server such as expressjs, it is advantageous from a testing and configuration perspective to split the processing of the http request into discrete blocks. When broken out in this way, each request can be seen as being sent through a chain of processing blocks, each performing an action, and passing its output on the next block.
This approach not only allows each block to be tested individually, but also allows the creation of declarative route definitions. Each route can be defined as a collection of blocks, specified declaratively. These definitions, can in turn be parsed by the server at start up time, creating the actual routes that will be supported.
This module takes the approach of breaking the processing pipeline into four distinct blocks:
This library can be installed using npm:
npm install @vamship/expressjs-routes
This library has been developed in typescript, and exports type declarations for applications developed using typescript. Read the API documentation for more details.
The core export from this library is a HandlerBuilder
class that can be used
to build out a route handler that conforms to expressjs' route handler
signature. Individual routes can be built as follows:
const HandlerBuilder = require('@vamship/expressjs-routes');
const express = require('express');
// This will be used in logs, use the path/method to make it meaningful
const handlerName = 'GET /:greeting/:name';
const greetingHandler = ({ greeting, name }) => {
return { message: `${greeting}, ${name}` };
};
// The input mapper can either be a function or a map of properties to
// the corresponding values in the expressjs request.
const inputMapper = (req) => {
return {
name: req.params.name,
greeting: req.params.greeting
};
};
const schema = {
$schema: 'http://json-schema.org/draft-07/schema#',
description: 'Schema for greet user API',
properties: {
greeting: { type: 'string', enum: ['hello', 'hola', 'bonjour' ] },
name: { type: 'string', minLength: 1 }
},
required: ['name', 'greeting']
};
const outputMapper = (data, res, next) => {
res.json(data);
};
const builder = new HandlerBuilder(handlerName, greetingHandler)
.setInputMapper(inputMapper)
.setSchema(schema)
.setOutputMapper(outputMapper);
const handler = builder.build();
...
const app = express();
app.get('/:greeting/:name', handler);
...
While the above steps can be used to construct individual routes, a utility
method buildRoutes
has been provided to construct a set of routes using
declarative route definitions as follows:
const { buildRoutes } = require('@vamship/expressjs-routes');
const express = require('express');
const routeDefinitions = [{
method: 'GET',
path: '/:greeting/:name',
handler: ({ greeting, name }) => ({ message: `${greeting}, ${name}` }),
// Use mapping instead of function
inputMapper:{
name: 'params.name',
greeting: 'params.greeting'
},
// No schema validation (not really a good idea)
schema: undefined,
// Uses the default, which basically calls res.json(data);
outputMapper: undefined
}];
const app = express();
// Construct a router using the route definitions, and return the
// resulting router object
const router = buildRoutes(routeDefinitions);
// Mount the routes under a path called /greeting-api
app.use('/greeting-api', router);
...
This library has been developed using typescript, and exports type declarations for the different classes. Since typescript is transpiled into javascript, this library can also be used in applications built using javascript.
A word of caution, however - this library does not perform explicit argument type checks in code, and relies on typescript's strong type system to enforce input argument types. Because plain javascript does not have a type system, using the apis and methods exposed by this library in javascript can lead to confusing errors if the input arguments are not of the correct type, or do not expose the expected properties.
This is not a new or ground breaking idea, but it is prudent to be reminded of it. Read the API documentation carefully :).
Generated using TypeDoc