New: Introducing PHP and Composer Support.Read the Announcement
Socket
Book a DemoInstallSign in
Socket

@root/async-router

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@root/async-router

Write Express middleware and route handlers using async/await

Source
npmnpm
Version
1.0.12
Version published
Weekly downloads
237
-4.44%
Maintainers
1
Weekly downloads
 
Created
Source

@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

  • API-compatible with express.Router()
    • NO refactoring required!
  • supports Promises
  • supports async/await
  • Proper error handling!
    • No more unhandledPromiseRejectionWarning
    • No more unhandledRejection
    • No uncaught exception server crashes
  • 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 user;
});

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

Alternatives

If you'd like to go dependency-free and use vanilla Express.js as-is, your best options are probably:

  • Use a wrapper promise in each Handler

    app.use(function (req, res, next) {
        async function h() {
            let result = await DB.doStuff();
            res.json(result);
        }
        Promise.resolve().then(h).catch(next);
    });
    
  • Wrap around each handler

    app.use(
        nextify(async function (req, res, next) {
            let result = await DB.doStuff();
            res.json(result);
        })
    );
    
    function nextify(fn) {
        return function (req, res, next) {
            async function h() {
                await fn(req, res, next);
            }
            Promise.resolve().then(h).catch(next);
        };
    }
    

LICENSE

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

MIT License

See LICENSE.

Keywords

middleware

FAQs

Package last updated on 28 Sep 2022

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts