npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@vamship/expressjs-routes

v3.0.2

Published

Enable declarative configuration and mounting of expressjs routes

Downloads

44

Readme

Express Routes

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.

API Documentation

API documentation can be found here.

Motivation

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:

  1. Input Mapping: Convert the raw HTTP request into a simple javascript object that can be validated and processed by downstream blocks
  2. Schema Validation: This is an optional block that can be used to ensure that the mapped input has the expected properties set on it.
  3. Request Processing: This accepts a javscript object from the input mapping, and returns the response object that forms the response to the client. The return from this block can also be a promise that eventually resolves to the final response.
  4. Output Mapping: Convert the response from the request processing step into an HTTP response that will be sent to the client.

Installation

This library can be installed using npm:

npm install @vamship/expressjs-routes

Usage

This library has been developed in typescript, and exports type declarations for applications developed using typescript. Read the API documentation for more details.

Construct individual routes

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);

    ...

Construct routers using declarative definitions

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);

...

A Note on Typescript

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 :).