boilerplate-server
A lean JS server framework designed to get you kicking and hacking on the edge of things real fast.
Design principles
- Convention over configuration boilerplate-server heavily borrows from the Ruby on Rails concept to behave by convention instead of explicit configuration. In practice this means that boilerplate-server does a lot of things automagically based on sane defaults. See Extending boilerplate-server for examples.
- Bleeding edge The entire boilerplate-server source is designed with future ways of creating javascript applications on the server in mind. Therefore this project uses bleeding edge
babel
features uncompromisingly. See Development for details. - Hardcore modularity Splitting things up into their smallest useful form helps with code readability and reasoning about responsibilities.
- Do things right™ boilerplate-server strives to be compliant with the principles verbalized by the 12Factor initiative.
Getting started
boilerplate-server has few global dependencies.
We recommend nvm
or n
for node/io version management.
// ./package.json"engines": "iojs": ">= 1.4.3" "node": ">= 0.12.0" "npm": ">= 2.5.1"
# Fetch and start the project git clone https://github.com/sinnerschrader/boilerplate-server.gitcd boilerplate-servernvm use v1.4.3 # assuming nvm is installed npm installnpm start
or
# Install and use as dependency npm install --save git+https://github.com/sinnerschrader/boilerplate-server.git
// in your package.json "scripts": "start": "boilerplate-server" "console": "boilerplate-console"
npm start
Usage
boilerplate-server is designed to cater for as many use cases as possible. For dependency cases, refer to CLI Usage or programmatic Usage. For deployment and boilerplate project scenarios refer to environment variables or configuration files. The precedence chain of all interfaces is:
- CLI
- Evironment variables
- Configuration files
CLI
After installation boilerplate-server exposes two commands. When installed globally they will be available in your $PATH
, when installed locally they are to be found in ./node_modules/.bin/
an therefore are useable from npm scripts
.
boilerplate-server
Start a boilerplate-server. The command line interface allows you to override the default configuration found in ./source/configuration
. Note that you can override nested configuration options by using flags with dot notation. --server.port=1338
will override the value found in ./source/configuration/server.js
stored in the property port
. Most common use cases are presented as examples below.
boilerplate-server --development # Run in development mode, default --production # Run in production mode --server.port=[PORT] # Port to bind the server to, defaults to 1337 --server.host=[HOST] # Host to bind the server to, defaults to localhost --cwd=[PATH] # Set the path from where the application and configuration folders should be searched. Defaults to process.cwd
boilerplate-console
Start the boilerplate-console and run a task. Note that there is only a very simple example task provided by default. See Extending boilerplate-server > Tasks to learn about creating and running your own tasks.
boilerplate-console [taskname] # Task name is required
Environment variables
For easy deployments boilerplate-server accepts configuration via specific environment variables. Explicit configuration via CLI take precedence over them.
- ENV sets
application.runtime.env
- PORT sets
server.port
- HOST sets
server.host
- LOG_LEVEL sets
log.level
To avoid conflicts with other processes using these environment variables, they are aliased with the following prefixes, ordered by precedence. Unprefixed variables have the lowest priority. It is recommended to use the most specific prefix (BOILERPLATESERVER_*
).
- BOILERPLATESERVER_*
- BOILERPLATE_*
- NODE_*
Configuration files
Although boilerplate-server is designed to be installed and used as dependency in your project, you can check out this repository and use it as a starting point for your own setup. In this case your primary interface will be the configuration files in ./source/configuration
, which compile to ./configuration
. See Development > Building for details. Edit the files at ./source/configuration
and make sure to build them, as they are not applied if not found in ./configuration
.
Environments
Based on environment file-based configuration can be overridden, e.g. a less verbose log level can be applied for production mode. Place the override config in ./source/configuration/environments/${environmentname}/${filetooverride}.js
. Files found in an applicable environment directory are deep-merged with their generic counterparts during configuration phase. E.g. source/configuration/production/server.js
is merged with source/configuration/server.js
when running in production.
// boilerplate-server --production// configuration/server.js 'host': 'localhost' 'port': 1337 'autoPort': true // configuration/environments/production/server.js 'autoPort': false // application.configuration.server 'host': 'localhost' 'port': 1337 'autoPort': false
Programmatic API
boilerplate-server exposes itself as commonjs module. The only export is a factory for the Application object.
; let application = ;await applicationstart;
Application
The application object carries the following public methods
-
async start ( host = this.configuration.server.host, port = this.configuration.server.port )
- Mount routes, middlewares and start the internal koa server, binding it to the configured or passed hostname and port. -
async stop ( )
- Stop the internal koa server, freeing the used port. -
mount( mountable, path = '/' )
- Mountmountable
onpath
, making its configuration, hooks, routes and middlewares available to the application. Routes and registered on mountable are available prefixed withpath
after starting the host application. Typically mountable is another boilerplate-server application. The mountable inherits active middlewares and tasks from the host application. Mounting has to be performed before starting the host application.
Extending boilerplate-server
Routes
Routes are run when boilerplate-server receives requests matching their path
configuration. Only the first matched route runs for every given request. Refer to the koa documentation about information how to write routes. Included routes:
/ => index
- Compliments you about getting boilerplate-server started and wants you to create own routes
Basics
- Place in
./applcation/routes/${routeName}.js
- Expected to export a factory function. Received parameters
application
- The hosting boilerplate-server instanceconfig
- Route configuration read from./configuration/routes.js[${routeName}]
- The factory function is expected to return a valid koa middleware function
- The technical documentation for koa middlewares applies
- async-await and generator style middlewares are supported
Example
// application/middlewares/example.js { return { applicationlog; thisbody = 'Hello world, ${this.params.id}'; };}
Configuration
In order to enable a route for boilerplate-server you have enable it in configuration by adding a config object under the key ${routeName} to the routes configuration.
Available options:
enabled = true
, boolean, If the route is to be mounted, useful for environment based toggling of routesmethod = 'GET'
, string['GET', 'PUT', 'POST', 'DELETE', 'HEAD']
, HTTP method the route should respond topath
, string, path-to-regexp expression matching against the requested path. Named and anonymous params are passed to the route context as members ofparams
(See route example)
// configuration/routes.jsconst routes = 'enabled': 'example': 'enabled': true 'method': 'GET' 'path': '/example/:id?' ; ;
Middlewares
Middlewares are run for every given request against boilerplate-server. Any number of middlewares can be run for every given request. Included middlewares:
- environment - Set a custom
X-Environment
header field with the value ofapplication.runtime.env
- jsonerror - Central error handling and json response utiltiy
- log - Log requests
- response-time - Measure response time and set a custom
X-ResponseTime
header field with the elapsed time in milliseconds.
Basics
- Place in
./application/middlewares/${middlewareName}.js
- Expected to export a factory function. Received parameters
application
- The hosting boilerplate-server instanceconfig
- Route configuration read from./configuration/middlewares.js[${middlewareName}]
- The factory function is expected to return a valid koa middleware function
- The technical documentation for koa middlewares applies
- async-await and generator style middlewares are supported
Example
// application/middlewares/log.js { return { let start = ; next; let delta = - start; applicationlog; };}
Configuration
// configuration/middlewares.jsconst middlewares = 'enabled': 'log': true ; ;
Hooks
Hooks are run when starting the application and provide an interface to alter and extend core behaviour of the application. boilerplate-server uses the hook API internally to provide most of its functionality. Included hooks:
- configure - Find, read, aggregate all configuration sources
- console - Provide application wide task runner utility
- engine - Maintain and start the internal koa application
- log - Provide application wide logging utility
- middlewares - Read, configure, mount middlewares
- routes - Read, configure, mount routes
- user-hooks - Find, configure and run user provided hooks
Basics
- Place in
./application/hooks/${middlewareName}/index.js
- Expected to export a configuration object. See API.
Example
This hook waits for the engine hook to start before printing a log message
'wait': false 'after': 'hooks:engine:start:after' { applicationlog; }
API
'wait': true // The application will not report as started before the hook has executed when this is true. Defaults to true. 'disabled': false // If this hook should be ignored during startup. Defaults to false. 'modes': // Modes this hook should be executed for (server, console are available). Defaults to [], running in every mode, 'after': 'application:after' /** * Events to wait for before running this hook. Every hook emits events for all run stages: * hooks:${hookName}:register:before * hooks:${hookName}:register:after * hooks:${hookName}:configure:before * hooks:${hookName}:configure:after * hooks:${hookName}:start:before * hooks:${hookName}:start:after **/ {} /* Sets configuration property of the hook by default, can be overridden here */ {} /* Final stage, here will most of your hook responsibilities live */ {} /* Lifecycle callback run right before configure */ { } /* Lifecycle callback run right after configure */ {} /* Lifecycle callback run right before hook registers with host application */ {} /* Lifecycle callback run right after hook registers with host application */ {} /* Lifecycle callback run right before hook runs */ {} /* Lifecycle callback run right after hook has run */;
Tasks
Tasks are functions that can be called by boilerplate-console
or application.run
Basics
- Place in
./application/tasks/${taskName}/index.js
- Expected to export an async function. Passed parameters:
- application - Host application instance
- config - configuration read from './configuration/tasks.js${taskName}'
Example
// application/tasks/test/index.js { console;} // configuration/tasks.js 'test': 'message': 'Hello, i am the test task' ;
$ boilerplate-console test$ Hello, i am the test task
or
await application;
Development
Tooling
Make sure to install the following plugins for your editor
- editorconfig
- eslint
npm scripts
"scripts": "start" // Start the boilerplate-server, "console" // Run the boilerplate-console, "build": // Build from ./source to ./, "watch": // Build from ./source to ./, watch changes, "clean": // Remove compile products