Scalable RESTful API boilerplate Express.js, Typescript and TypeORM based.
Thanks to Daniel F. Sousa for the inspiration with Express REST 2017 boilerplate.
Clone boilerplate :
$ git clone https://github.com/konfer-be/ts-express-typeorm-boilerplate.git your-project-name/
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.
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
The latest version of Typescript is used by default.
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.
Run time compilation :
$ tsc
Watching compilation :
$ tsc --watch
ORM couch is provided by Typeorm.
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.
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.
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.
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.
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
A ./travis.yml file is provided with a basic configuration.
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.
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.
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.
# 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.
Here are two ways to generate your documentation : api and code.
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.
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.
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.
A lot of parameters are setted/plugged in the Application config file. Heavier configurations are maked in dedicated config.
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.
Full authentication process is principaly based on passport.js.
- Implemented strategies: Bearer, oauth Facebook, oauth Google
- Token lifetime/secret: see .env files
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.
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.
Simple logs management is provided, principaly based on Morgan and Winston.
You can configure main parameters in dedicated config file.
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.
Some classic features are implemented with CORS, Helmet, Hpp and Express rate limit.
- 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)