/ts-express-typeorm-boilerplate

Scalable RESTful API boilerplate Typescript, Express.js, Typeorm based.

Primary LanguageTypeScriptMIT LicenseMIT

Typescript / Express.js / Typeorm RESTful API boilerplate

Node TypeScript Express Typeorm MIT Licence

Build Status Coverage Dependencies devDependencies Known Vulnerabilities

Scalable RESTful API boilerplate Express.js, Typescript and TypeORM based.

Thanks to Daniel F. Sousa for the inspiration with Express REST 2017 boilerplate.

Table of contents

Getting started

Install

Clone boilerplate :

$ git clone https://github.com/konfer-be/ts-express-typeorm-boilerplate.git your-project-name/

Build

Give kickstart :

$ npm run kickstart

This will install Typescript, Typeorm and Kem (cli entity generator) globaly, NPM packages, create dist directory and sub-directories, and run a one shot compilation.

Configure

Adapt/create .env files with your own configuration for mandatory properties :

# TypeORM
TYPEORM_HOST = "localhost"
TYPEORM_DB = "your-database-name"
TYPEORM_USER = "root"
TYPEORM_PWD = "root"
TYPEORM_PORT = "3306"

Enjoy with :

$ nodemon

Development features

Typescript

The latest version of Typescript is used by default.

Configuration

You can adapt Typescript configuration in ./tsconfig.json file :

{
  "compilerOptions": {
    "outDir": "./dist/",
    "sourceMap": false,
    "baseUrl": "./src",
    "paths": {
      "@bases/*": ["api/types/classes/*"],
      "@config/*": ["config/*"],
      "@controllers/*": ["api/controllers/*"],
      "@enums/*": ["api/types/enums/*"],
      "@errors/*": ["api/types/errors/*"],
      "@interfaces/*": ["api/types/interfaces/*"],
      "@middlewares/*": ["api/middlewares/*"],
      "@models/*": ["api/models/*"],
      "@repositories/*": ["api/repositories/*"],
      "@routes/*": ["api/routes/v1/*"],
      "@serializers/*": ["api/serializers/*"],
      "@services/*": ["api/services/*"],
      "@utils/*": ["api/utils/*"],
      "@validations/*": ["api/validations/*"],
      "@whitelists/*": ["api/serializers/whitelists/*"]
    },
    "lib": ["dom", "es5", "es6", "es7"],
    "target": "es2017",
    "module": "commonjs",
    "allowSyntheticDefaultImports": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
  },
  "exclude" : [
    "**/**/node_modules",
    "node_modules"
  ]
}

More info about tsconfig.json.

Compilation

Run time compilation :

$ tsc

Watching compilation :

$ tsc --watch

ORM

ORM couch is provided by Typeorm.

Configuration

Update .env files (development, staging, production, test) with your own settings :

# TypeORM
TYPEORM_TYPE = "mysql"
TYPEORM_NAME = "default"
TYPEORM_HOST = "localhost"
TYPEORM_DB = "your-database-name"
TYPEORM_USER = "root"
TYPEORM_PWD = "root"
TYPEORM_PORT = "3306"
TYPEORM_SYNC = 0
TYPEORM_LOG = 0

If you will use Typeorm as CLI, update also the ormconfig.json file and fill it with your own configuration :

{
  "type": "mysql",
  "name": "default",
  "host": "localhost",
  "port": 3306,
  "username": "root",
  "password": "root",
  "database": "your-database",
  "synchronize": false,
  "logging": false,
  "entities": [
    "./dist/api/models/**/*.js"
  ],
  "migrations": [
    "./dist/migrations/**/*.js"
  ],
  "cli": {
    "migrationsDir": "./dist/migrations",
    "subscribersDir": "./dist/subscribers"
  },
  "subscribers": [
    "src/subscribers/**/*.ts"
  ]
}

More info about ormconfig file and typeorm cli.

Migration

A Typeorm migration is a DB synchronizing. If your schema have pending changes, migration tool allow you to synchronize it.

$ typeorm migration:generate -n NameOfYoursPendingChanges
$ typeorm migration:run

Although this case is anticipated/prevented in the boilerplate, be extremely careful with the synchronize parameter. When is true, Typeorm will automaticaly execute pending changes on your database, and some data may be lost. Set synchronize at true only in development|staging|test environments.

More info about typeorm migration.

Events subscribers

Typeorm provides events listening on your models. So, you can define your owns listeners/subscribers, and use it to do actions when a specific event is fired.

More info about typeorm subscribers.

Entity generating

The boilerplate provide a basic entity generator (kfr-kem), which be used as cli tool. This generate following files :

  • Controller
  • Model
  • Repository
  • Validation
  • Route
  • Test
  • Serializer
  • Whitelist

To use the file generating, run the following command :

$ kem

First, the prompt ask you local folder destination, and check if the directory exists. Please, provide absolute root folder path of the project (ie /var/www/my-project).

Next, you will enter the name of the entity to generate. You can provide one or many words separated by spaces, generator will use hyphens for filename, and PascalCase for entity name.

Note that generated files contains only basic features and some parts must be obviously filled by yourself :

  • Container: The dependencies container must be updated with the controller. At least one.
  • Proxy-router: The proxy-router service must be updated with the created router.
  • Model: model is filled with a primary auto-incremented id, and date system columns. Fill it with your columns and relations.
  • Serializer: attributes as empty by default. Fill it with your entity attributes.
  • Validation rules: body rules are created but empty by default. Fill it with your rules.

Tests

Many packages are used to provide an useful test environment: Mocha, Chai and Supertest.

Basic tests are already writted and are located in test directory.

To run your tests, launch the following command :

$ npm run test --env test

Travis

A ./travis.yml file is provided with a basic configuration.

Code coverage

When you launch your tests, a coverage report is automaticaly generated by Istanbul in ./docs/nyc-coverage.

You can also launch a plato code coverage inspection :

$ npm run coverage

A coverage report is generated in ./docs/plato-coverage.

Unfortunately, Plato is not longer maintened and some functionalities are broken with ES6. See es6-plato if you wish implements this feature.

Deployment

Project implements a basic PM2 configuration to allow easy deployment.

First, install PM2 globaly :

$ npm i pm2 -g

Note that PM2 should also be installed on other server environments, and that your SSH public key must be granted by the destination server.

Configuration

Configure the ecosystem.config.js file with your environments informations.

deploy : {
  staging : {
    path : 'path-to-your-SSH-public-key',
    user : 'node',
    host : '212.83.163.1',
    ref  : 'origin/master',
    repo : 'git@github.com:repo.git',
    path : '/var/www/staging',
    'post-deploy' : 'npm install && pm2 reload ecosystem.config.js --env staging'
  },
  production : {
    path : 'path-to-your-SSH-public-key',
    user : 'node',
    host : '212.83.163.1',
    ref  : 'origin/master',
    repo : 'git@github.com:repo.git',
    path : '/var/www/production',
    'post-deploy' : 'npm install && pm2 reload ecosystem.config.js --env production'
  }
}

More info about PM2 ecosystem.config.js file.

Deploy

# Setup deployment at remote location
$ pm2 deploy production setup

# Update remote version
$ pm2 deploy production update

# Revert to -1 deployment
$ pm2 deploy production revert 1

# execute a command on remote servers
$ pm2 deploy production exec "pm2 reload all"

More info about PM2 deploy.

More info about PM2.

Documentation

Here are two ways to generate your documentation : api and code.

API documentation

This way provide a documentation for consumers.

$ npm run apidoc-ci

An API documentation website is generated into ./docs/apidoc/.

See apidoc for more informations about customization.

Code documentation

This way provide a documentation for developers.

$ npm run typedoc-ci

A code documentation website is generated into ./docs/typedoc/.

See typedoc for more informations about customization.

Todo and fixme tasks

A small tool is provided to help you with recensement of lost todo's. Run npm task to recense TODO and FIXME patterns.

$ npm run todo-ci

More information about leasot.

Application features

A lot of parameters are setted/plugged in the Application config file. Heavier configurations are maked in dedicated config.

Dependency injection

Awilix is used to provide controllers and services instances as dependencies. Each dependency is resolved as singleton, but you can easily adapt this behavior.

See Container class.

Authentication

Full authentication process is principaly based on passport.js.

  • Implemented strategies: Bearer, oauth Facebook, oauth Google
  • Token lifetime/secret: see .env files

File upload

Files can be managed as Documents entities, and are uploaded with Uploader middleware.

The middleware use Multer and Jimp, and provide following features:

  • Document creation
  • Single upload
  • Multiple uploads
  • Image resizing

You can set upload options from scratch on each route, or by default in .env files. By default, upload middleware is only plugged on document router, but it can be used on other routes whitout difficult, with or without Document creation.

Validation

Route validation is implemented with express-validator, express-validation and Joi.

One entity, one validation file.

You can define your own globals validation settings in dedicated config file. This file wrap express-validator and provide it to the validation middleware, which is used on routes to validate.

Logs management

Simple logs management is provided, principaly based on Morgan and Winston.

You can configure main parameters in dedicated config file.

Errors management

API respond always on the same format :

  • Success: JSON body which contain one or more entities. Or empty, with 200, 201 or 204 HTTP status code.
  • Error: JSON object which implements IError interface. Includes upload errors, db errors or 404 errors. The errors property can be an array of strings, or an array of IFieldError.
{
    "statusCode": 401,
    "statusText": "Unauthorized",
    "errors": [
      "Forbidden area"
    ]
}

Depending by environment, errors can be logged or not.

Security

Some classic features are implemented with CORS, Helmet, Hpp and Express rate limit.

Dependencies

  • awilix (dependency injection)
  • axios (http requests)
  • bcrypt (cryptography)
  • body-parser (payload exposition)
  • boom (errors throwing)
  • compression (gzip responses)
  • cookie-parser (cookie exposition)
  • cors (security)
  • crypto (cryptography)
  • dotenv (.env files)
  • errorhandler (errors handling)
  • es6-promisify (es6 promisification)
  • express (framework)
  • express-rate-limit (rate limit on api)
  • express-validation (validation)
  • express-validator (on the fly validation)
  • helmet (security)
  • hpp (security)
  • http-status (easy HTTP status response)
  • jimp (image manipulation)
  • joi (validation rules)
  • json-api-serializer (serializing)
  • jwt-simple (JWT enconding / decoding)
  • lodash (utils)
  • module-alias (typescript paths)
  • moment (date treatments)
  • moment-timezone (date treatments)
  • morgan (HTTP logs)
  • multer (file upload)
  • node-notifier (desktop notifications)
  • passport (authentification)
  • passport-facebook (authentification with Facebook graph)
  • passport-google-auth (authentification with Google oAuth)
  • passport-http-bearer (authentification with Bearer strategy)
  • passport-jwt (authentification with JWT)
  • passport-local (authentification with local database)
  • pluralize (pluralization)
  • reflect-metadata (model reflection)
  • typeorm (ORM)
  • uuid (unique identifier generating)
  • winston (logs)