@ianwremmel/tracks-boot
v1.0.8
Published
<!-- (optional) Put banner here -->
Downloads
13
Readme
tracks-boot (@ianwremmel/tracks-boot)
@ianwremmel/tracks-boot is a tiny module to start Express apps asynchronously
Most tutorials for Express show how to get up and running quickly with a synchronous example. Unfortunately, the reality is that sometimes we need to do async work before we can start listening for connections. Maybe we need to load config from a file or wait for database connections. Maybe we're pulling config from a remote store like Consul. In any case, it can get pretty clunky. This module aims to streamline that clunkiness as much as possible.
Table of Contents
Install
npm install @ianwremmel/tracks-boot
Usage
tracks-boot exports two functions, prepare
for doing all of the async work of
preparing your application and boot
for binding it to a port. These are
separate functions so that you can use e.g. supertest against a prepare app
without needing to test over http.
First, import tracks boot
import {boot, prepare} from '@ianwremmel/tracks-boot';
Next, create your app factory (yes, I said "factory"; it's not that bad. it's just a function).
export function createApp() {
return prepare(async (app) => {
// do all of your normal app setup here. add middleware, routes, etc.
app.get('/ping', (req, res) => {
res.send('It Works!');
});
// This is an async function, so you can use await anywhere you need to.
});
}
Now, define your boot behavior. You could put this in the same file as your app
factory and rely on testing require.main === module
to only start the app when
appropriate or you could use a separate file. The example below assumes
everything goes in the same file. This example just confirms the environment is
set correctly to bind to a port. (I recommend doing most other env-var checking
in the app factory rather than here. PORT
is checked here because it's
explicitly needed by boot()
).
if (require.main === module) {
if (!process.env.PORT) {
throw new Error('PORT is not defined');
}
const port = Number(process.env.PORT);
if (Number.isNaN(port)) {
throw new Error('PORT must be a number');
}
// we'll just pass console as our logger, but if you're using something more
// complex like bunyan, that's fine too. Just make sure it implements
// `info: (arg: string) => void`
boot({logger: console, port}, create());
}
boot returns a
Promise<http.Server>
, so if you need to shut it down programmatically (vs killing the process), you can use e.g.boot(...).then((server) => server.close());
Finally, we can use supertest to test our app without binding it to a port
import {createApp} from '.';
it('responds to pings', async () =>
supertest(await createApp())
.get('/api/v1/healthcheck')
.expect(200)
.expect('It Works!'));
Maintainer
Contribute
PRs Welcome
License
MIT © Ian Remmel 2019 until at least now