Node Service/API Boilerplate
Node.js
boilerplate for building Services/API
focused on separation of concerns and scalability.
It is heavily inspired by node-api-boilerplate of Talysson De Oliveira.
Table of Contents
- Features
- Requirements
- Getting Started
- Directories
- Configuration
- Source Code
- Documentation
- Deployment
- Credits
Features
Multilayer folder structure
- following Domain Driven Design and Clean ArchitectureProduction Ready
- setup with PM2Scalable Web Server
- uses Express.jsDependency Injection
- using awilixServerless Ready
- via serverless frameworkContainerized Application Ready
- via dockerOpenAPI 3.0 Documentation
- using swaggerDatabase Integration
- ORM support using sequelizeMulti-tenant Database Setup
Structured Logging
- using winstonCode Linting
- using eslint following airbnb-style-guideBDD/TDD Ready
- test suite using mocha and chai
Requirements
- Node.js
v.10+
- Javascript Runtime - npm - Node Package Manager
- sequelize-cli - for Database ORM Tool
- serverless - for Serverless Framework
- docker - for Containerizing Application
Getting Started
- Clone the repository.
$ git clone git@github.com:agaphetos/node-service-api-boilerplate.git
- Install package dependencies.
$ npm install
- Run the application. Application is running on http://localhost:3000/. You can also see the sample
API documentation
on http://localhost:3000/api/v1/docs
$ npm start
Directories
Directory structure of the project
Configuration
Configurations for are ready for the following with the use of ENVIRONMENT VARIABLES
:
Application Configuration
This contains Application
specific configuration like API Integration
, Service Configuration
and all related for the application you are building.
Logging Configuration
We are using winston as our logging library.
By default, our application
uses structured logging
pattern using json
format.
To customize the logging
configuration. There is an example config file logging.js.example.
For more detailed usage about winston
. See official documentation on https://github.com/winstonjs/winston.
Database Configuration
We are using sequelize v5 as our ORM
.
By default, our application
loads our staged environment
from config/database.js
file.
To define the database connection and options
. There is an example config file database.js.example.
For more detailed usage about sequelize
. See official documentation on https://sequelize.org/master/.
Multi-tenant Database Setup
A multi-tenant
database allows us to support multiple database for our infra/database
codebase.
This setup is inspired by the article Using multiple databases with NodeJS and Sequelize from Medium.
The steps below will help you setup a specific database source
.
- Setup a datasource registration on
config/database.js
by adding a property(key: value)
on the exportable object. Seeexample
on config/database.js.example andspecification
below:
<datasource-identifier>: {
host: process.env.SPECIFIC_DB_HOST,
username: process.env.SPECIFIC_DB_USERNAME,
password: process.env.SPECIFIC_DB_PASSWORD,
database: process.env.SPECIFIC_DB_DATABASE,
dialect: process.env.SPECIFIC_DB_DIALECT,
...options,
},
- Add the desired
ENVIRONMENT VARIABLES
on.env
orenv.yml
. Seespecification
below:
.env
: See example
on .env.example
SPECIFIC_DB_HOST=<value-here>
SPECIFIC_DB_USERNAME=<value-here>
SPECIFIC_DB_PASSWORD=<value-here>
SPECIFIC_DB_DATABASE=<value-here>
SPECIFIC_DB_DIALECT=<value-here>
env.yml
: See example
on env.yml.example
<stage-name>:
SPECIFIC_DB_HOST: <value-here>
SPECIFIC_DB_USERNAME: <value-here>
SPECIFIC_DB_PASSWORD: <value-here>
SPECIFIC_DB_DATABASE: <value-here>
SPECIFIC_DB_DIALECT: <value-here>
Note:
The steps above (1 and 2) will enable the application to load database models
to our application instance
.
-
Create a
.sequelizerc
for the specific datasource. Seeexample
on .sequelize.example -
Add an
npm-script
entry for the datasource instance. See specification below:
{
"scripts": {
...,
"sequelize:<datasource-identifier>:migrate": "sequelize --options-path ./.sequelize-<datasource-identifier> --env <datasource-identifier> db:migrate",
"sequelize:<datasource-identifier>:migrate:undo": "sequelize --options-path ./.sequelize-<datasource-identifier> --env <datasource-identifier> db:migrate:undo",
"sequelize:<datasource-identifier>:seed:all": "sequelize --options-path ./.sequelize-<datasource-identifier> --env <datasource-identifier> db:seed:all"
...
}
}
NOTE:
The steps above (3 and 4) will enable the us to execute sequelize
commands like migrate
and seed
using the npm-script
defined.
Runtime Setup
Defined ENVIRONMENT VARIABLES
are loaded by automatically upon runtime.
There are 2 runtimes supported by our application.
Server-based Runtime
The ENVIRONMENT VARIABLES
are loaded using dotenv. Setup with the use of .env
file. See sample .env.example
Serverless Runtime
The ENVIRONMENT VARIABLES
are loaded by serverless
upon package deployment
and offline
execution. Setup with the use of env.yml
file. See sample [env.yml.examp
Source Code
The src/
directory contains the API source code.
It uses a folder structure and logical architecture focused on separation of concerns
based in Domain-driven design
and Clean architecture
.
Instead of the classical controllers/models/services
folders, we now have layers inside the src/
folder. Each of the folder layers is scoped by a namespace regarding the concern it is about.
Application layer
The application layer is responsible to mediate between your input interfaces and your business domain. In this layer we'll have the use cases of your application and your application services.
Domain layer
Here you'll define your business domain classes, functions and services that compose your domain model. All your business rules should be declared in this layer so the application layer can use it to compose your use cases.
Infrastructure layer
This is the lowest of the layers. In the infra layer you'll have the communication with what is outside your application, like the database, external services and direct communication with frameworks.
Interfaces layer
This folder contains all the entry points for your application. From the beginning here's where your Express controllers will be (inside the interfaces/http folder).
Documentation
Documentations about the API:
API Specifications
Shows the API Specs following OAS3
standard and was written following a swagger.yaml template
using swagger
.
The sample API Specification
can be seen on http://localhost:3000/api/v1/docs/.
For more detailed usage about swagger
. See official documentation on https://swagger.io/docs/specification/about/.
Deployment
Currently our application supports the following deployments:
Server Hosted Deployment
$ npm start
Serverless Deployment
$ sls deploy -s [your-stage]
Containerizing Application
The contains separate Dockerfile
for development
and production
stage releases.
Building a Docker Image
To build a docker image. Use docker build
command.
$ docker build -t <workspace/image-name:version> -f <stage>.Dockerfile
Running the Docker Image
To run a docker image. Use docker run
command.
Use the following options for running our image:
-p
- specify port mappings-d
- docker image to run-e, --env, --env-file
- specify an environment variable or environment file
$ docker run -p <machine-port>:<container-port> -d <workspace/image-name>
Credits
- Talysson De Oliveira -
node-api-boilerplate
- Lucas Spreiter -
multi-tenant database setup