Boilerplate setup with:
- Express
- Typescript
- TypeORM
- Morgan/Winston (logging)
- Jest + Supertest (testing)
- MySQL Database
This boilerplate was designed based on the clean architecture principle.
Code dependencies can only come from the outer levels inward.
Route tier takes care of:
- Redirecting incoming requests to the expected controller.
- Handling responses to client.
Controller tier takes care of:
- Receiving requisitions from Routes.
- Applying business rules.
- Interacting with Repository tier.
- Returning data to Routes.
Repository tier takes care of:
- Acessing database
Service tier is meant to be used whenever a code must be used for both controller and scripts or even for multiple controllers.
- Node 14.1.0 or higher
- Docker
Name | Description |
---|---|
/data | MySQL data |
/dist | Server built |
/logs | Server logs |
/node_modules | Dependencies |
/src | Server source |
/test | Tests |
Name | Description |
---|---|
/config | Server config files such as Log and Database configurations |
/controller | Controller tier |
/entity | Database entities definition |
/enum | Server enums |
/errors | Custom server errors |
/initializer | Initializer that must run when server is being initialized |
/interface | Server interfaces |
/migration | Database migration files |
/repository* | Repository tier |
/route | Route tier |
/service | Service tier used for sharing functions that are going to be used by the server and scripts |
/type | Server types |
*Repository tier is not being used in this boilerplate since TypeORM offers a great repository tier.
There are 2 MySQL docker instance configure on docker-compose.yaml:
- mysql: used for development.
- mysql-test: used for running tests. Database data is being stored under $ROOT_DIR/data/
You can drop your schema by running:
npm run db:drop
You can reset your database by running:
npm run db:reset
Database migrations are located under /src/migration.
For applying all migrations into your current database, run:
npm run migration:apply
For reverting, run:
npm run migration:revert
This project enables out-of-the-box CRUDS. This is possible due to AbstractCrudController and AbstractCrudRoute. If you do not need this functionality or do not want to use it, you can remove these files.
In order to create a new CRUD you must do the following:
- Create your new entity (under /src/entity/)
- Add annotations for both TypeORM and class-validator.
- Create a new Response Type (under /src/type/response/entity/)
- Create a new controller (under /src/controller/)
- This controller must extend AbstractCrudController
- You must provide your new entity/response type to AbstractCrudController
- Implement responseParser.
- Check ProjectController for more details
- Create a new route (under /src/route)
- This route must extend AbstractCrudRoute
- You must provide your new entity/response type/controller to AbstractCrudRoute
CRUD will create the following endpoints: (i.e. New Route file name = UserRoute.ts)
Method | Endpoint |
---|---|
GET | /api/UserRoute/:id |
POST | /api/UserRoute/:id |
PATCH | /api/UserRoute/:id |
DELETE | /api/UserRoute/:id |
GET | /api/UserRoute/ *** |
***This endpoint has sort and pagination enabled.
If you want your route to have a custom name instead of the file name, you may use the CustomRouteName
decorator.
Example:
@CustomRouteName("customName")
class CustomRoute extends AbstractRoute<
Project,
ProjectResponseType,
ProjectController
> {
constructor() {
super(ProjectController);
}
}
Then your endpoints will look like:
Method | Endpoint |
---|---|
GET | /api/customName/:id |
POST | /api/customName/:id |
PATCH | /api/customName/:id |
DELETE | /api/customName/:id |
GET | /api/customName/ |
Whenever server could not find an element with the provided id an error 404 will be returned.
PATCH and POST will apply validation before trying to insert/update items on database. You can specify the validation that is going to be applied by adding class-validator annotations into entity objects. Whenever this validation fails, an error 400 wil be returned with information about invalid fields.
In order to paginate a CRUD endpoint you have to provide 2 parameters: pageSize and page.
Parameter | Description |
---|---|
pageSize | is the number of elements the request should return. |
page | is the page number you want to return |
Example: Let's suposse we've 50 users
Name | Description |
---|---|
Users (0 - 10) | /api/UserRoute?pageSize=10&page=0 |
Users (11 - 20) | /api/UserRoute?pageSize=10&page=1 |
Users (21 - 30) | /api/UserRoute?pageSize=10&page=2 |
Users (31 - 40) | /api/UserRoute?pageSize=10&page=3 |
Users (41 - 50) | /api/UserRoute?pageSize=10&page=4 |
Whenever pageSize, page or both parameters are missing, all* records will be returned.
*Due to performance concerns server will not return more than 1000 records.
In order to paginate a CRUD endpoint you have to provide sort parameter.
You can perform multiple sorting by using commas.
You can perform DESC sort by adding (-) in front of the parameter.
Example:
/api/UserRoute?sort=-endDate,name
Whenever the sort parameter contains an invalid field, an error 500 will be returned informing an invalid sort value was found.
Generic error handling is configured under RoutesInitializer. Any exception thrown within an express route will be captured and handled gracefully.
Pre-commit hook is configured with Prettier and Linter.
Logs are being printed in both file and console. Morgan middleware is being used for printing all incoming requests and its status. Winston is being used for custom log messages. Winston is configured with rotation so that logs can be separated on a daily basis. Log files are being generated under $ROOT_DIR/logs/
Tests are setup with Jest and Supertest. Test files are being stored under $ROOT_DIR/test/
For running all tests:
npm run test
1- Clone repository
git clone https://github.com/luis-carlos-campos/ts-node-base.git
cd ts-node-base
2- Install dependencies
npm install
3- Start docker containers
docker-compose up -d
4- Reset database
npm run db:reset
5- Start dev server
npm run start:dev
You can build the project by running:
npm run build
Compiled code will be available under $ROOT_DIR/dist/
You can also start the production version by running:
npm run start:prod
In order to remove all the examples you can run
npm run boilerplate:cleanup
If you want to remove all the examples and the Generic CRUD functionality you can run:
npm run boilerplate:crud-cleanup
Add filtering for CRUDs
You can report issues or request new features through github Issues tab.
Feel free to contribute with new features and bug fixing.