@root/async-router
    TypeScript icon, indicating that this package has built-in type declarations

    1.0.10 • Public • Published

    @root/async-router

    A lightweight, zero-dependency JavaScript library to bring native Promises and async/await to Express.

    express-async-router_14 1 1-youtube

    Wraps the Express Router and provides a drop-in replacement to allow you to progressively enhance your routes with Promise and await support.

    // Handle Async & Promise routes - and normal routes too!
    app.get('/foo', async function (req, res) {
        // no more try/catch wrappers
        // no more 'unhandledRejection' errors
        let user = await UserService.findById(req.user.id);
        
        res.json(users);
    });

    Features

    • [x] API-compatible with express.Router()
      • [x] NO refactoring required!
    • [x] supports Promises
    • [x] supports async/await
    • [x] Proper error handling!
      • [x] No more unhandledPromiseRejectionWarning
      • [x] No more unhandledRejection
      • [x] No uncaught exception server crashes
    • [x] res.json() can be called automatically

    Usage

    TL;DR

    Swap out app for a the async router, and handle the server separately:

    let app = require('@root/async-router').Router();
    
    // ...
    
    let server = express().use('/', app);
    http.createServer(server).listen(3000, onListen);

    Keep existing routes just they way they are...

    // yuck!
    app.get('/profile', async function (req, res, next) {
        try {
            let results = await ProfileModel.get(req.user.id);
            res.json(results);
        } catch(e) {
            return next(e);
        }
    })

    Or give them a facelift:

    // yay!
    app.get('/profile', async function (req, res) {
        res.json(await ProfileModel.get(req.user.id));
    })

    Caveats

    If you need to set express options, you'll move that down to the bottom as well:

    let app = require('@root/async-router').Router();
    
    // ...
    
    let server = express()
        .use('trust proxy', 1)
        .use('view engine', 'pug')
        .use('/', app);
    http.createServer(server).listen(3000, onListen);

    Also, if you do happen to have a few routes that explicitly res.json() in a callback after having returning a value, those would need to be updated - a very rare case, but I'm sure it exists in some code somewhere.

    Full Example

    'use strict';
    
    let http = require('http');
    let express = require('express');
    let app = require('@root/async-router').Router();
    
    // Handle Async & Promise routes
    app.get('/foo', async function (req, res) {
        let user = await UserService.findById();
        if (!user) {
            throw new Error('User not found');
        }
    
        // Note: if you return a value,
        // res.json() will be called automatically
        // (however, just because you can doesn't mean you should)
        return users;
    });
    
    // Handles existing routes too - no refactoring required!
    app.get('/foo', async function (req, res) {
        try {
            let user = await UserService.findById();
        } catch (e) {
            console.error('Unexpected');
            console.error(e);
            res.statusCode = 500;
            res.end('Internal Server Error');
        }
    
        if (!user) {
            res.statusCode = 404;
            res.json({ error: 'User not found' });
            return;
        }
    
        res.json(users);
    });
    
    // Handle errors (must come after associated routes)
    app.use('/', function (err, req, res, next) {
        console.error('Unhandled Error');
        console.error(err);
        res.statusCode = 500;
        res.end(err.message);
    });
    
    // Start node.js express server
    let server = express().use('/', app);
    http.createServer(server).listen(3000, function () {
        console.info('Listening on', this.address());
    });

    Also, since it's useful to have this snippet for demos:

    async function sleep(ms) {
        await new Promise(function (resolve) {
            setTimeout(resolve, ms);
        });
    }

    API

    Router() - same as express.Router()

    let app = require('@root/async-router').Router();

    This is just a wrapper around express.Router(), which is what provides the default router and "mini apps" of express - so it has all of the same methods and function signatures:

    app.use(path, middlewares);
    app.route(path, minApp);
    app.head(path, fns);
    app.get(path, fns);
    app.post(path, fns);
    app.patch(path, fns);
    app.delete(path, fns);
    // ... etc

    Any incompatibility should be file as a bug.

    NOT an express server

    It does NOT copy the top-level express server API. You should still use express for that:

    // top-level options are still handled by the express server instance
    let server = express()
        .set('trust proxy', 1)
        .set('view engine', 'pug')
        .use('/', app);
    
    require('http')
        .createServer(server)
        .listen(3000, onListen);
        
    function onListen() {
        console.info('Listening on', this.address());
    }

    wrap(app)

    The wrap(app) is the best way to add async/await support to your Express app or Router.

    let syncApp = express.Router();
    let app = require('@root/async-router').wrap(syncApp);

    LICENSE

    Fork of express-promisify-router to bugfix error handling.

    MIT License

    See LICENSE.

    Install

    npm i @root/async-router

    DownloadsWeekly Downloads

    21

    Version

    1.0.10

    License

    MIT

    Unpacked Size

    12 kB

    Total Files

    6

    Last publish

    Collaborators

    • coolaj86