1.0.0 • Published 5 years ago

boiler-begone v1.0.0

Weekly downloads
1
License
MIT
Repository
-
Last release
5 years ago

boiler-begone

boiler-begone is a small NodeJS library which helps make writing routes in Express a little easier. It comes with three important functions. Two are easy to explain:

  • die makes it easy to throw an error with a particular status. Instead of writing the following code over and over again inside your routes:
if(!userInDatabase){
   const error = new Error();
   error.status = 404;
   next(error);
}

You can just do:

if(!userInDatabase)
  die(404);
}

And everything will work as expected.

  • makeHandler lets you create handlers inside express routes without throwing try-catch blocks all over the place. Instead of writing:
app.get('/', async (req, res, next) => {
  try {
    /* Very interesting code */
  } catch (err) {
    next(err);
  }
});

Do:

app.get('/', makeHandler(async (req, res) => {
  /* Very interesting code */
}))

And it will work exactly the same way.

makeMain: Simplify Enabling Middleware

The makeMain function is a bit more complicated. Most of the time, before starting an Express Server, a whole bunch of awkward declarations are necessary:

const express = require('express');
const morgan = require('morgan');
const bodyParser = require('body-parser');
const listEndpoints = require('express-list-endpoints');

const app = express();

app.use(morgan('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use((err, req, res, next) => {
  console.error(err);
  res.status(err.status).send('Oh no! An error!');
});

async function main(){
  listEndpoints(app);
  /* Database calls involving await usually go here... */
  app.listen(8080, () => 'App is listening on Port 8080');
}

main()

Writing all of those require and use statements is somewhat error prone and tedious, especially when they're spread around a file. The problem only gets worse and worse as we add more and more middleware. Why not keep everything in one place instead? Let's couple every require statement and its corresponding app.use together by writing functions similar to the one below:

const express = require('express');
const app = express();

function useBodyParser(){
  const bodyParser = require('body-parser');
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({extended: true}));
}

This trick helps a little, but it doesn't solve our problem entirely. Having a bunch of these functions all over the place would get messy! If only we could put them somewhere...

What we really need is a store ala Redux---a hash table that serves as a single source truth for our application's middleware. The keys on it should be strings which describe the middlewares we'd like to plug, and the values should be functions which load those middlewares in. All of the functions we write should execute right before we start our server through an asynchronous main function.

Calling makeMain creates a store and a main function which does the right thing. Using it, the big code snippet written above becomes:

const express = require('express');
const { makeMain } = require('BoilerBegone');

const app = express();
const main = makeMain(app);
main()

A bit of terminology: We call the functions which live inside the store and run just before our server starts when main executes behaviors. If you want to see all of the behaviors on main, call:

main.getBehaviors()

If you want to add or change one of the behaviors, call:

main.setBehavior(behaviorName, behaviorFunction)

Finally, to remove a behavior:

main.removeBehavior(behaviorName)

By default, main will use both morgan and body-parser. It'll also list out all of the endpoints you've put into your Express app. To control the port which the server started by main uses, simply make main.port a different number. It will be 8080 unless you change it.

If you don't want to use any of the default behaviors, makeBehaviorlessMain creates a main function with a completely empty store that you can customize however you'd like.

That's it! Hopefully, these tools will help you write cleaner and more elegant server-side code. I may add functions to this library later on which make using Sequelize and Postgres together a little easier, too; pull requests are welcome.