You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Mar 31, 2021. It is now read-only.
dev:yarn startbuild tsoa routes, swagger definitions and starts the server on development mode listening to file changes (swagger definition changes will require a manual restart)
test:yarn testunit and integration tests
build:yarn buildproduction build
prod:yarn start:prodstarts the server on production mode
Scaffolding
config express server, DB connection, Logger, etc
env .env files
controllers routes configuration
models classes and interfaces representing entities. They are also used to normalize data
respositories data abstraction layers
services business logic to be used primary by controllers
import{Route,Controller,Get}from'tsoa';import{ProvideSingleton}from'../ioc';
@Route('ping')
@ProvideSingleton(PingController)exportclassPingControllerextendsController{/** The service containing business logic is passed through dependency injection */constructor(@inject(UserService)privateuserService: UserService){super();}/** Simple GET */
@Get()publicasyncping(): Promise<string>{return'pong';}/** Error response definition for swagger */
@Response(400,'Bad request')
@Post()/** Type of security needed to access the method */
@Security('adminUser')/** The request's body is accessed through a decorator *//** The interface "IUserModel" is also used to build swagger specs and to perform run time validations */publicasynccreate(@Body()userParams: IUserModel): Promise<IUserModel>{constuser=newUserModel(userParams);returnthis.userService.create(user);}}
Models and Formatters
Models and Formatters are used for 4 reasons:
Model
Swagger definition file
Run time validations performed by tsoa
Static typing advantages
/** An interface used for swagger, run time validations and standar typescript advantages */exportinterfaceIUserModel{id?: string;username: string;firstName: string;lastName: string;}
Formatter
Data normalization
/** A class used to normalize data */exportclassUserFormatterextendsBaseFormatterimplementsIUserModel{publicusername: string=undefined;publicfirstName: string=undefined;publiclastName: string=undefined;constructor(args: any){super();this.format(args);}}
Auth
A simple tsoa middleware to handle authentication by decorators.
exportasyncfunctionexpressAuthentication(request: Request,securityName: string,scopes?: string[]): Promise<AuthData>{/** Switch to handle security decorators on controllers - @Security('adminUser') */switch(securityName){case'authRole':
/** If auth is valid, returns data that might be used on controllers (maybe logged user's data) */returnnull;}/** Throws an exception if auth is invalid */thrownewApiError('auth',403,'invalid credentials');}
Service
Services encapsulate buisness logic to be used by controllers. This allows the code to stay DRY if several controllers rely on similar logic and help to make testing easier.
@ProvideSingleton(UserService)exportclassUserService{/** The repository to access the data persistance layer is passed through dependency injection */constructor(@inject(UserRepository)privateuserRepository: UserRepository){}/** Business logic to get a single item */publicasyncgetById(_id: string): Promise<IUserModel>{returnnewUserModel(awaitthis.userRepository.findOne({ _id }));}/** Business logic to get paginated data */publicasyncgetPaginated(query: IUserModel,pageNumber: number,perPage: number): Promise<PaginationModel>{constskip: number=(Math.max(1,pageNumber)-1)*perPage;const[count,list]=awaitPromise.all([this.userRepository.count(query),this.userRepository.find(query,skip,perPage)]);returnnewPaginationModel({
count,
pageNumber,
perPage,list: list.map(item=>newUserModel(item))});}}
When an update on a model is needed, the Entity on src/repositories/sql/entities will have to be updated and a migration file created and run with the provided npm script migrate:<env> to update the already created table.
To sync all entities when the server/tests start, tou will have to inject their dependencies into SQLSetupHelper class localted at src/config/SQLSetupHelper
Tests include unit tests(utils and services) and integration tests.
import{expect}from'chai';import*assupertestfrom'supertest';import{Server}from'../../config/Server';describe('PingController',()=>{constapp=supertest(newServer().app);it('HTTP GET /api/ping | should return pong',async()=>{constres=awaitapp.get('/api/ping');expect(res.status).to.equal(200);expect(res.body).to.equal('pong');});});