RESTful api with Domain Driven Design
- Clone the repository with
git clone --depth=1 https://github.com/joshuaalpuerto/node-ddd-boilerplate.git
- Install the dependencies with Yarn
- Install global dependencies Application Setup
- Create the development and test Databases
- Run database migrations and seed with
yarn db:refresh
- Run the application in development mode with
yarn start
- Access
http://localhost:<PORT>/api/<VERSION>
and you're ready to go!
$ npm install -g standard # JavaScript Standard Style
$ npm install -g babel-eslint # required by StandardJs
$ npm install -g snazzy # Format JavaScript Standard Style as beautiful output
$ npm install -g sequelize-cli # CLI for Sequelize
- Install PostgreSql - v9.6.
- Create an empty database named -
node_ddd
andnode_ddd_test
for test enviroment. - Rename the .env and populate it with the correct credentials and settings of your Postgresql databases
- Enable SSL in the
postgresql.conf
configuration file of your Postgresql installation.
Follow the the steps in the next section to enable Posgresql SSL connections.
$ psql
psql (9.6.0)
Type "help" for help.
$ CREATE DATABASE node_ddd;
$ CREATE DATABASE node_ddd_test;
- uses Node.js > v9
- written using ES6
- uses Yarn for package dependency management
- uses JavaScript Standard Style
- uses
sequelize
andsequelize-cli
as ORM and data migration toolcan change easily to diffrent ORM and migration tool.
- Filename convention -
camelCase
should never be used. This leavessnake_case
andkebab-case
, I prefersnake_case
for file.
yarn start
- start the Node-DDD API Boilerplate locallyyarn test
- run Unit testsyarn db:refresh
- run all migrations and seeds.standard
- lint codebase using JavaScript Standard Stylestandard --fix
- fix code according to JS Standard Stylesequelize model:create --name newmodel
--attributes "id:integer, title:string - create a new modelsequelize db:migrate
- apply db changes using migration scriptyarn add <package-name>
- add a new package to package.jsonyarn remove <package-name>
- remove package from package.json
Sequelize is used to define mappings between models and database tables. It will automatically add the attributes created_at
and updated_at
to the tables created. However for consistency for our naming we change this to createdAt
and updatedAt
. This will cause issue when using model so we have to add this on config:
module.exports = function (sequelize, DataTypes) {
const User = sequelize.define('users', {
...
}, {
timestamps: false, // Add this
})
}
Basic commands
$ sequelize db:migrate Run pending migrations.
$ sequelize db:migrate:old_schema Update legacy migration table
$ sequelize db:migrate:undo Revert the last migration run.
$ sequelize db:migrate:undo:all Revert all migrations ran.
$ sequelize db:seed Run seeders.
$ sequelize db:seed:undo Deletes data from the database.
$ sequelize db:seed:undo:all Deletes data from the database.
$ sequelize model:create --name modelname --attributes "text:text, url:string" # create model
$ sequelize seed:create # create seeder
IMPORTANT: as of 6/23/17
the model file created with the sequelize db:model
command still initializes a model with an empty classMethods
object with an associate
property in the options passed to sequelize.define
method. You cannot define associations this way anymore as of Sequelize v4.0.0-1. This tripped me up for a hot second because the generated model file did not reflect this change, and the fact that support for the old way had been removed is seemingly buried in the changelogs. Don’t make the same mistake I did and be super confused for too long about why associations aren’t working.
//old way that will be included in your generated model file
module.exports = function(sequelize, DataTypes) {
var nameofmodel = sequelize.define('nameofmodel', {
...model attributes
}, {
classMethods: {
associate: function(models) {
// associations can be defined here
}
}
})
return nameofmodel
};
//The right way to set associations in model files
module.exports = function(sequelize, DataTypes) {
var nameofmodel = sequelize.define('nameofmodel', {
...model attributes
});
nameofmodel.associate = function (models) {
// associations can be defined here
};
return nameofmodel
}
For reference, see: https://github.com/sequelize/cli
- Express - Node Framweork
- Awilix - dependency resolution support powered by
Proxy
- PM2 - production process manager for Node.js applications with a built-in load balancer
- Tcomb - s a library for Node.js and the browser which allows you to check the types of JavaScript values at runtime with a simple and concise syntax
- Express-status-monitor - Simple, self-hosted module based on Socket.io and Chart.js to report realtime server metrics for Express-based node servers.
- CORS - a node.js package for providing a Connect/Express middleware that can be used to enable CORS with various options.
- Body-parser - Node.js body parsing middleware.
- Compression - Node.js compression middleware.
- Http-status - Utility to interact with HTTP status code.
- Winston - A multi-transport async logging library for node.js.
- Morgan - HTTP request logger middleware for node.js
- Ramda - A practical functional library for JavaScript programmers.
- Sequelize - promise-based ORM for Node.js v4 and up. It supports the dialects PostgreSQL, MySQL, SQLite and MSSQL and features solid transaction support, relations, read replication and more.
- Faker - generate massive amounts of fake data in the browser and node.js
- Bcrypt - Lib to help you hash passwords
- Passport - is Express-compatible authentication middleware for Node.js.
- Passport-jwt - A Passport strategy for authenticating with a JSON Web Token.
- Json Webtoken - An implementation of JSON Web Tokens.
- Moment - Parse, validate, manipulate, and display dates and times in JavaScript.
- Moment-timezone - Parse and display dates in any timezone.
- Swagger-ui - visualize and interact with the API’s resources without having any of the implementation logic in place.
- Swagger-jsdoc- enables you to integrate Swagger using JSDoc comments in your code. Just add @swagger on top of your DocBlock and declare the meaning of your code in yaml complying to the OpenAPI specification.
- winston - a multi-transport async logging library for Node.js. It is designed to be a simple and universal logging library with support for multiple transports. A transport is essentially a storage device for your logs. Each instance of a winston logger can have multiple transports configured at different levels. For example, one may want error logs to be stored in a persistent remote location (like a database), but all logs output to the console or a local file.
- morgan - HTTP request logger middleware for Node.js. A helper that collects logs from your server, such as your request logs.
- mocha - JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun
- chai - a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework.
- supertest - HTTP assertions made easy via superagent.
- cross-env - makes it so you can have a single command without worrying about setting or using the environment variable properly for the platform
- We mainly use this so mocha can use the absolute path of files
Adding pre-commit
to your project can be helpful to encourage consistency and quality of your code repository.
- pre-commit - pre-commit is a pre-commit hook installer for
git
. It will ensure that yournpm test
(or other specified scripts) passes before you can commit your changes. This all conveniently configured in yourpackage.json
. - lint-staged - Linting makes more sense when running before committing your code. By doing that you can ensure no errors are going into repository and enforce code style. But running a lint process on a whole project is slow and linting results can be irrelevant. Ultimately you only want to lint files that will be committed.
- 2 spaces – for indentation
- Single quotes for strings – except to avoid escaping
- No unused variables – this one catches tons of bugs!
- No semicolons – [It's][1] [fine.][2] [Really!][3]
- Never start a line with
(
,[
, or`
- This is the only gotcha with omitting semicolons – automatically checked for you!
- [More details][4]
- Space after keywords
if (condition) { ... }
- Space after function name
function name (arg) { ... }
- Always use
===
instead of==
– butobj == null
is allowed to checknull || undefined
. - Always handle the node.js
err
function parameter - Always prefix browser globals with
window
– exceptdocument
andnavigator
are okay- Prevents accidental use of poorly-named browser globals like
open
,length
,event
, andname
.
- Prevents accidental use of poorly-named browser globals like
- And more goodness
This boilerplate is open to suggestions and contributions, documentation contributions are also important! :)
This boilerplate is forked and modified from node-api-boilerplate - Talysson de Oliveira Cassiano 👏
MIT License - fork, modify and use however you want.