├── .env ├── LICENSE ├── README.md ├── docker-compose.yml ├── jest.config.js ├── package.json ├── src ├── app.ts ├── controllers │ ├── index.controller.ts │ ├── test.controller.ts │ └── users.controller.ts ├── dtos │ └── users.dto.ts ├── exceptions │ └── HttpException.ts ├── interfaces │ ├── routes.interface.ts │ └── users.interface.ts ├── middlewares │ ├── error.middleware.ts │ ├── validation.middleware.ts │ └── validationJsonResponse.middleware.ts ├── models │ └── users.model.ts ├── routes │ ├── index.route.ts │ ├── test.route.ts │ └── users.route.ts ├── server.ts ├── services │ └── users.service.ts ├── swagger-docs │ ├── pet.yaml │ ├── swagger.json │ └── user.yaml └── utils │ ├── swaggerIgnite.ts │ └── validateEnv.ts ├── tsconfig.json └── tslint.json /.env: -------------------------------------------------------------------------------- 1 | NODE_ENV=development 2 | 3 | 4 | # If this is the Mongo atlas connection string, mongodb+srv://:@instancename.oudcl.mongodb.net 5 | # then the connection string need to be set as follows 6 | 7 | MONGO_USER=mongo-db-username 8 | MONGO_PASSWORD=mongo-db-password 9 | MONGO_PATH=@instancename.oudcl.mongodb.net/ 10 | MONGO_CONNECTION_VERB=mongodb+srv 11 | PORT=8000 12 | APP_PATH= -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 vipinkavlar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-express-typescript-mongodb-swagger 2 | 3 | Environment 4 | ``` 5 | NPM: 8.19.2 6 | Node : 18.12.1 LTS 7 | 8 | ``` 9 | 10 | Please follw the below steps: 11 | 12 | ``` 13 | git clone https://github.com/vipinkavlar/node-express-typescript-mongodb-swagger.git 14 | cd node-express-typescript-mongodb-swagger 15 | npm install 16 | npm update //if required 17 | npm outdated //if required. Then update the required packages as given below; 18 | npm install ts-node@ 19 | npm install typescript@ 20 | npm install --save @types/node@18.11.15 21 | npm run dev 22 | ``` 23 | 24 | Swagger documentation sample can be found at `http://localhost:/api-docs` 25 | 26 | # Form input validation 27 | 28 | Input validation is done through class-validator. The decorators are defined in src/dtos files. 29 | Two middleware can be used to process error responses. 30 | 1. ../middlewares/validation.middleware 31 | 2. ../middlewares/validationJsonResponse.middleware 32 | 33 | validationJsonResponse will output the response in JSON format as given below: 34 | 35 | ``` 36 | { 37 | message : null, 38 | data: null, 39 | errorCode : 201 40 | errorMessages : { 41 | "email": { 42 | "isNotEmpty": "email should not be empty", 43 | "isEmail": "email must be an email" 44 | }, 45 | "password": { 46 | "isString": "password must be a string" 47 | } 48 | } 49 | } 50 | ``` 51 | 52 | validationMiddleware sends HTTP response. Usage of both middlewares can be seen in the routes/user.route.ts file -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | services: 3 | mongodb: 4 | image: mongo:latest 5 | container_name: "mongoose" 6 | environment: 7 | MONGO_INITDB_ROOT_USERNAME: root 8 | MONGO_INITDB_ROOT_PASSWORD: password 9 | MONGO_INITDB_DATABASE: mongodb 10 | ports: 11 | - 27017:27017 12 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: "ts-jest", 3 | testEnvironment: "node" 4 | }; 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "starter-templating", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "start": "ts-node --transpile-only src/server.ts", 6 | "dev": "nodemon --watch src --delay 1 --exec npx ts-node src/server.ts", 7 | "cpm": "pm2 start src/server.ts --watch ts-node src/server.ts", 8 | "test": "jest --forceExit --detectOpenHandles", 9 | "lint": "tslint -p tsconfig.json -c tslint.json", 10 | "build": "tsc -p .", 11 | "production": "ts-node --transpile-only dist/server.js" 12 | }, 13 | "dependencies": { 14 | "@types/swagger-ui-express": "^4.1.1", 15 | "class-transformer": "^0.3.1", 16 | "class-validator": "^0.13.2", 17 | "cors": "^2.8.5", 18 | "dotenv": "^8.2.0", 19 | "envalid": "^6.0.0", 20 | "express": "^4.17.1", 21 | "helmet": "^3.23.3", 22 | "hpp": "^0.2.3", 23 | "jest": "^27.5.1", 24 | "mongoose": "^6.8.0", 25 | "morgan": "^1.9.1", 26 | "swagger-jsdoc": "^3.5.0", 27 | "swagger-ui-express": "^4.1.3", 28 | "ts-jest": "^27.1.3", 29 | "ts-node": "^10.9.1", 30 | "typescript": "^4.9.4" 31 | }, 32 | "devDependencies": { 33 | "@types/cors": "^2.8.6", 34 | "@types/express": "^4.17.2", 35 | "@types/helmet": "^0.0.45", 36 | "@types/hpp": "^0.2.1", 37 | "@types/jest": "^27.4.1", 38 | "@types/mongoose": "^5.5.41", 39 | "@types/morgan": "^1.7.37", 40 | "@types/node": "^18.11.15", 41 | "@types/supertest": "^2.0.8", 42 | "@types/swagger-jsdoc": "^3.0.2", 43 | "nodemon": "^2.0.2", 44 | "supertest": "^4.0.2", 45 | "tslint": "^5.20.1", 46 | "tslint-config-airbnb": "^5.11.2" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/app.ts: -------------------------------------------------------------------------------- 1 | import * as cors from 'cors'; 2 | import * as express from 'express'; 3 | import * as helmet from 'helmet'; 4 | import * as hpp from 'hpp'; 5 | import * as mongoose from 'mongoose'; 6 | import * as logger from 'morgan'; 7 | import Routes from './interfaces/routes.interface'; 8 | import errorMiddleware from './middlewares/error.middleware'; 9 | import swaggerIgnite from './utils/swaggerIgnite'; 10 | 11 | class App { 12 | public app: express.Application; 13 | public port: (string | number); 14 | public env: boolean; 15 | 16 | constructor(routes: Routes[]) { 17 | this.app = express(); 18 | this.port = process.env.PORT || 3033; 19 | this.env = process.env.NODE_ENV === 'production' ? true : false; 20 | 21 | this.connectToDatabase(); 22 | this.initializeMiddlewares(); 23 | this.initSwaggerDocs(); 24 | this.initializeRoutes(routes); 25 | this.initializeErrorHandling(); 26 | } 27 | 28 | public listen() { 29 | this.app.listen(this.port, () => { 30 | console.log(`App listening on the port ${this.port}`); 31 | }); 32 | } 33 | 34 | public getServer() { 35 | return this.app; 36 | } 37 | 38 | public initSwaggerDocs() { 39 | swaggerIgnite(this.app); 40 | } 41 | 42 | private initializeMiddlewares() { 43 | if (this.env) { 44 | this.app.use(hpp()); 45 | this.app.use(helmet()); 46 | this.app.use(logger('combined')); 47 | this.app.use(cors({ origin: 'your.domain.com', credentials: true })); 48 | } else { 49 | this.app.use(logger('dev')); 50 | this.app.use(cors({ origin: true, credentials: true })); 51 | } 52 | 53 | this.app.use(express.json()); 54 | this.app.use(express.urlencoded({ extended: true })); 55 | } 56 | 57 | private initializeRoutes(routes: Routes[]) { 58 | routes.forEach((route) => { 59 | this.app.use('/', route.router); 60 | }); 61 | } 62 | 63 | private initializeErrorHandling() { 64 | this.app.use(errorMiddleware); 65 | } 66 | 67 | private connectToDatabase() { 68 | const { MONGO_USER, MONGO_PASSWORD, MONGO_PATH, MONGO_CONNECTION_VERB } = process.env; 69 | if (this.env) { 70 | // production database 71 | } else { 72 | mongoose.set('strictQuery', false); 73 | mongoose.connect(MONGO_CONNECTION_VERB+'://'+MONGO_USER+':'+MONGO_PASSWORD+MONGO_PATH); 74 | } 75 | } 76 | } 77 | 78 | export default App; 79 | -------------------------------------------------------------------------------- /src/controllers/index.controller.ts: -------------------------------------------------------------------------------- 1 | import { NextFunction, Request, Response } from 'express'; 2 | 3 | class IndexController { 4 | 5 | public index = (req: Request, res: Response, next: NextFunction) => { 6 | try { 7 | res.sendStatus(200); 8 | } catch (error) { 9 | next(error); 10 | } 11 | } 12 | } 13 | 14 | export default IndexController; 15 | -------------------------------------------------------------------------------- /src/controllers/test.controller.ts: -------------------------------------------------------------------------------- 1 | import { NextFunction, Request, Response } from 'express'; 2 | 3 | 4 | class TestController { 5 | public test = (req: Request, res: Response, next: NextFunction) => { 6 | try { 7 | res.status(200).json({ data: "hello world", message: 'findOne' }); 8 | } catch (error) { 9 | next(error); 10 | } 11 | } 12 | } 13 | 14 | export default TestController; 15 | -------------------------------------------------------------------------------- /src/controllers/users.controller.ts: -------------------------------------------------------------------------------- 1 | import { NextFunction, Request, Response } from 'express'; 2 | import { CreateUserDto } from '../dtos/users.dto'; 3 | import { User } from '../interfaces/users.interface'; 4 | import userService from '../services/users.service'; 5 | 6 | class UsersController { 7 | public userService = new userService(); 8 | 9 | public getUsers = async (req: Request, res: Response, next: NextFunction) => { 10 | try { 11 | const findAllUsersData: User[] = await this.userService.findAllUser(); 12 | res.status(200).json({ data: findAllUsersData, message: 'findAll' }); 13 | } catch (error) { 14 | next(error); 15 | } 16 | } 17 | 18 | public getUserById = async (req: Request, res: Response, next: NextFunction) => { 19 | const userId: string = req.params.id; 20 | 21 | try { 22 | const findOneUserData: User = await this.userService.findUserById(userId); 23 | res.status(200).json({ data: findOneUserData, message: 'findOne' }); 24 | } catch (error) { 25 | next(error); 26 | } 27 | } 28 | 29 | public createUser = async (req: Request, res: Response, next: NextFunction) => { 30 | const userData: CreateUserDto = req.body; 31 | 32 | try { 33 | const createUserData: User = await this.userService.createUser(userData); 34 | res.status(201).json({ data: createUserData, message: 'created' }); 35 | } catch (error) { 36 | next(error); 37 | } 38 | } 39 | 40 | public updateUser = async (req: Request, res: Response, next: NextFunction) => { 41 | const userId: string = req.params.id; 42 | const userData: User = req.body; 43 | 44 | try { 45 | const updateUserData: User = await this.userService.updateUser(userId, userData); 46 | res.status(200).json({ data: updateUserData, message: 'updated' }); 47 | } catch (error) { 48 | next(error); 49 | } 50 | } 51 | 52 | public deleteUser = async (req: Request, res: Response, next: NextFunction) => { 53 | const userId: string = req.params.id; 54 | 55 | try { 56 | const deleteUserData: User = await this.userService.deleteUserData(userId); 57 | res.status(200).json({ data: deleteUserData, message: 'deleted' }); 58 | } catch (error) { 59 | next(error); 60 | } 61 | } 62 | } 63 | 64 | export default UsersController; 65 | -------------------------------------------------------------------------------- /src/dtos/users.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString, IsEmail } from 'class-validator'; 2 | 3 | export class CreateUserDto { 4 | @IsEmail() 5 | public email: string; 6 | 7 | @IsString() 8 | public password: string 9 | } 10 | -------------------------------------------------------------------------------- /src/exceptions/HttpException.ts: -------------------------------------------------------------------------------- 1 | class HttpException extends Error { 2 | public status: number; 3 | public message: string; 4 | 5 | constructor(status: number, message: string) { 6 | super(message); 7 | this.status = status; 8 | this.message = message; 9 | } 10 | } 11 | 12 | export default HttpException; 13 | -------------------------------------------------------------------------------- /src/interfaces/routes.interface.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | 3 | interface Route { 4 | path: string; 5 | router: Router; 6 | } 7 | 8 | export default Route; 9 | -------------------------------------------------------------------------------- /src/interfaces/users.interface.ts: -------------------------------------------------------------------------------- 1 | export interface User { 2 | _id: string; 3 | email: string; 4 | password: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/middlewares/error.middleware.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | import HttpException from '../exceptions/HttpException'; 3 | 4 | function errorMiddleware(error: HttpException, req: Request, res: Response) { 5 | const status: number = error.status || 500; 6 | const message: string = error.message || 'Something went wrong'; 7 | 8 | console.log('[ERROR] ', status, message); 9 | 10 | res.status(status).json({ message }); 11 | } 12 | 13 | export default errorMiddleware; 14 | -------------------------------------------------------------------------------- /src/middlewares/validation.middleware.ts: -------------------------------------------------------------------------------- 1 | import { plainToClass } from 'class-transformer'; 2 | import { validate, ValidationError } from 'class-validator'; 3 | import { RequestHandler } from 'express'; 4 | import HttpException from '../exceptions/HttpException'; 5 | 6 | function validationMiddleware(type: any, skipMissingProperties = false): RequestHandler { 7 | return (req, res, next) => { 8 | validate(plainToClass(type, req.body), { skipMissingProperties }) 9 | .then((errors: ValidationError[]) => { 10 | if (errors.length > 0) { 11 | const message = errors.map((error: ValidationError) => Object.values(error.constraints)).join(', '); 12 | next(new HttpException(400, message)); 13 | } else { 14 | next(); 15 | } 16 | }); 17 | }; 18 | } 19 | 20 | export default validationMiddleware; 21 | -------------------------------------------------------------------------------- /src/middlewares/validationJsonResponse.middleware.ts: -------------------------------------------------------------------------------- 1 | import { plainToClass } from 'class-transformer'; 2 | import { validate, ValidationError } from 'class-validator'; 3 | import { RequestHandler } from 'express'; 4 | 5 | function validationJsonResponseMiddleware(type: any, skipMissingProperties = false): RequestHandler { 6 | let validationResponseArray: { [id: string]: any; } = {} 7 | return (req, res, next) => { 8 | validate(plainToClass(type, req.body), { skipMissingProperties }) 9 | .then((errors: ValidationError[]) => { 10 | if (errors.length > 0) { 11 | for (const [key, val] of Object.entries(errors)) { 12 | validationResponseArray[val.property] = val.constraints; 13 | } 14 | next(res.status(400).json(validationResponseArray)); 15 | } else { 16 | next(); 17 | } 18 | }); 19 | }; 20 | } 21 | 22 | export default validationJsonResponseMiddleware; 23 | -------------------------------------------------------------------------------- /src/models/users.model.ts: -------------------------------------------------------------------------------- 1 | import * as mongoose from 'mongoose'; 2 | import { User } from '../interfaces/users.interface'; 3 | 4 | const userSchema = new mongoose.Schema({ 5 | email: String, 6 | password: String 7 | }); 8 | 9 | const userModel = mongoose.model('User', userSchema); 10 | 11 | export default userModel; 12 | -------------------------------------------------------------------------------- /src/routes/index.route.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | import IndexController from '../controllers/index.controller'; 3 | import Route from '../interfaces/routes.interface'; 4 | 5 | class IndexRoute implements Route { 6 | public path = '/'; 7 | public router = Router(); 8 | public indexController = new IndexController(); 9 | 10 | constructor() { 11 | this.initializeRoutes(); 12 | } 13 | 14 | private initializeRoutes() { 15 | this.router.get(`${this.path}`, this.indexController.index); 16 | } 17 | } 18 | 19 | export default IndexRoute; 20 | -------------------------------------------------------------------------------- /src/routes/test.route.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | import TestController from '../controllers/test.controller'; 3 | import Route from '../interfaces/routes.interface'; 4 | 5 | class TestRoute implements Route { 6 | public path = '/test'; 7 | public router = Router(); 8 | public testController = new TestController(); 9 | 10 | constructor() { 11 | this.initializeRoutes(); 12 | } 13 | 14 | private initializeRoutes() { 15 | this.router.get(`${this.path}/das`, this.testController.test); 16 | } 17 | } 18 | 19 | export default TestRoute; 20 | -------------------------------------------------------------------------------- /src/routes/users.route.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | import UsersController from '../controllers/users.controller'; 3 | import { CreateUserDto } from '../dtos/users.dto'; 4 | import Route from '../interfaces/routes.interface'; 5 | import validationMiddleware from '../middlewares/validation.middleware'; 6 | import validationJsonResponseMiddleware from '../middlewares/validationJsonResponse.middleware'; 7 | 8 | class UsersRoute implements Route { 9 | public path = '/users'; 10 | public router = Router(); 11 | public usersController = new UsersController(); 12 | 13 | constructor() { 14 | this.initializeRoutes(); 15 | } 16 | 17 | private initializeRoutes() { 18 | this.router.get(`${this.path}`, this.usersController.getUsers); 19 | this.router.get(`${this.path}/:id`, this.usersController.getUserById); 20 | this.router.post(`${this.path}`, validationJsonResponseMiddleware(CreateUserDto), this.usersController.createUser); 21 | this.router.put(`${this.path}/:id`, validationMiddleware(CreateUserDto, true), this.usersController.updateUser); 22 | this.router.delete(`${this.path}/:id`, this.usersController.deleteUser); 23 | } 24 | } 25 | 26 | export default UsersRoute; 27 | -------------------------------------------------------------------------------- /src/server.ts: -------------------------------------------------------------------------------- 1 | import 'dotenv/config'; 2 | import App from './app'; 3 | import IndexRoute from './routes/index.route'; 4 | import UsersRoute from './routes/users.route'; 5 | import TestRoute from './routes/test.route'; 6 | import validateEnv from './utils/validateEnv'; 7 | 8 | validateEnv(); 9 | 10 | const app = new App([ 11 | new IndexRoute(), 12 | new UsersRoute(), 13 | new TestRoute(), 14 | ]); 15 | 16 | app.listen(); 17 | -------------------------------------------------------------------------------- /src/services/users.service.ts: -------------------------------------------------------------------------------- 1 | import { CreateUserDto } from '../dtos/users.dto'; 2 | import HttpException from '../exceptions/HttpException'; 3 | import { User } from '../interfaces/users.interface'; 4 | import userModel from '../models/users.model'; 5 | 6 | class UserService { 7 | public users = userModel; 8 | 9 | public async findAllUser(): Promise { 10 | const users = await this.users.find(); 11 | return users; 12 | } 13 | 14 | public async findUserById(userId: string): Promise { 15 | const user = await this.users.findById(userId); 16 | if (user) return user; 17 | throw new HttpException(409, "You're not user"); 18 | } 19 | 20 | public async createUser(userData: CreateUserDto): Promise { 21 | if (await this.users.findOne({ email: userData.email })) { 22 | throw new HttpException(400, `User with email ${userData.email} already exists`); 23 | } 24 | const user = await this.users.create(userData); 25 | 26 | return user; 27 | } 28 | 29 | public async updateUser(userId: string, userData: User): Promise { 30 | const user = await this.users.findByIdAndUpdate(userId, userData); 31 | if (user) return user; 32 | throw new HttpException(409, "You're not user"); 33 | } 34 | 35 | public async deleteUserData(userId: string): Promise { 36 | const user = await this.users.findByIdAndDelete(userId); 37 | if (user) return user; 38 | throw new HttpException(409, "You're not user"); 39 | } 40 | } 41 | 42 | export default UserService; 43 | -------------------------------------------------------------------------------- /src/swagger-docs/pet.yaml: -------------------------------------------------------------------------------- 1 | paths: 2 | /test/das: # path of the user from your endpoint 3 | get: # endpoint request type (put request) 4 | tags: 5 | - Pet 6 | summary: It updates a pet profile detail 7 | produces: 8 | - application/json 9 | parameters: # request parameters 10 | schema: 11 | $ref: '#/definitions/updatePet' 12 | responses: 13 | 200: 14 | description: An object with a user updated user profile detail 15 | 401: 16 | description: Unauthorized users 17 | definitions: # Schema definition for the request body 18 | updatePet: 19 | type: object 20 | properties: 21 | pet: 22 | type: object 23 | properties: 24 | petname: 25 | type: string 26 | petFavorite: 27 | type: string 28 | image: 29 | type: string 30 | password: 31 | type: string -------------------------------------------------------------------------------- /src/swagger-docs/swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.", 5 | "version": "1.0.0", 6 | "title": "Swagger Petstore", 7 | "termsOfService": "http://swagger.io/terms/", 8 | "contact": { 9 | "email": "apiteam@swagger.io" 10 | }, 11 | "license": { 12 | "name": "Apache 2.0", 13 | "url": "http://www.apache.org/licenses/LICENSE-2.0.html" 14 | } 15 | }, 16 | "host": "petstore.swagger.io", 17 | "basePath": "/v2", 18 | "tags": [ 19 | { 20 | "name": "pet", 21 | "description": "Everything about your Pets", 22 | "externalDocs": { 23 | "description": "Find out more", 24 | "url": "http://swagger.io" 25 | } 26 | }, 27 | { 28 | "name": "store", 29 | "description": "Access to Petstore orders" 30 | }, 31 | { 32 | "name": "user", 33 | "description": "Operations about user", 34 | "externalDocs": { 35 | "description": "Find out more about our store", 36 | "url": "http://swagger.io" 37 | } 38 | } 39 | ], 40 | "schemes": [ 41 | "https", 42 | "http" 43 | ], 44 | "paths": { 45 | "/pet": { 46 | "post": { 47 | "tags": [ 48 | "pet" 49 | ], 50 | "summary": "Add a new pet to the store", 51 | "description": "", 52 | "operationId": "addPet", 53 | "consumes": [ 54 | "application/json", 55 | "application/xml" 56 | ], 57 | "produces": [ 58 | "application/xml", 59 | "application/json" 60 | ], 61 | "parameters": [ 62 | { 63 | "in": "body", 64 | "name": "body", 65 | "description": "Pet object that needs to be added to the store", 66 | "required": true, 67 | "schema": { 68 | "$ref": "#/definitions/Pet" 69 | } 70 | } 71 | ], 72 | "responses": { 73 | "405": { 74 | "description": "Invalid input" 75 | } 76 | }, 77 | "security": [ 78 | { 79 | "petstore_auth": [ 80 | "write:pets", 81 | "read:pets" 82 | ] 83 | } 84 | ] 85 | }, 86 | "put": { 87 | "tags": [ 88 | "pet" 89 | ], 90 | "summary": "Update an existing pet", 91 | "description": "", 92 | "operationId": "updatePet", 93 | "consumes": [ 94 | "application/json", 95 | "application/xml" 96 | ], 97 | "produces": [ 98 | "application/xml", 99 | "application/json" 100 | ], 101 | "parameters": [ 102 | { 103 | "in": "body", 104 | "name": "body", 105 | "description": "Pet object that needs to be added to the store", 106 | "required": true, 107 | "schema": { 108 | "$ref": "#/definitions/Pet" 109 | } 110 | } 111 | ], 112 | "responses": { 113 | "400": { 114 | "description": "Invalid ID supplied" 115 | }, 116 | "404": { 117 | "description": "Pet not found" 118 | }, 119 | "405": { 120 | "description": "Validation exception" 121 | } 122 | }, 123 | "security": [ 124 | { 125 | "petstore_auth": [ 126 | "write:pets", 127 | "read:pets" 128 | ] 129 | } 130 | ] 131 | } 132 | }, 133 | "/pet/findByStatus": { 134 | "get": { 135 | "tags": [ 136 | "pet" 137 | ], 138 | "summary": "Finds Pets by status", 139 | "description": "Multiple status values can be provided with comma separated strings", 140 | "operationId": "findPetsByStatus", 141 | "produces": [ 142 | "application/xml", 143 | "application/json" 144 | ], 145 | "parameters": [ 146 | { 147 | "name": "status", 148 | "in": "query", 149 | "description": "Status values that need to be considered for filter", 150 | "required": true, 151 | "type": "array", 152 | "items": { 153 | "type": "string", 154 | "enum": [ 155 | "available", 156 | "pending", 157 | "sold" 158 | ], 159 | "default": "available" 160 | }, 161 | "collectionFormat": "multi" 162 | } 163 | ], 164 | "responses": { 165 | "200": { 166 | "description": "successful operation", 167 | "schema": { 168 | "type": "array", 169 | "items": { 170 | "$ref": "#/definitions/Pet" 171 | } 172 | } 173 | }, 174 | "400": { 175 | "description": "Invalid status value" 176 | } 177 | }, 178 | "security": [ 179 | { 180 | "petstore_auth": [ 181 | "write:pets", 182 | "read:pets" 183 | ] 184 | } 185 | ] 186 | } 187 | }, 188 | "/pet/findByTags": { 189 | "get": { 190 | "tags": [ 191 | "pet" 192 | ], 193 | "summary": "Finds Pets by tags", 194 | "description": "Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", 195 | "operationId": "findPetsByTags", 196 | "produces": [ 197 | "application/xml", 198 | "application/json" 199 | ], 200 | "parameters": [ 201 | { 202 | "name": "tags", 203 | "in": "query", 204 | "description": "Tags to filter by", 205 | "required": true, 206 | "type": "array", 207 | "items": { 208 | "type": "string" 209 | }, 210 | "collectionFormat": "multi" 211 | } 212 | ], 213 | "responses": { 214 | "200": { 215 | "description": "successful operation", 216 | "schema": { 217 | "type": "array", 218 | "items": { 219 | "$ref": "#/definitions/Pet" 220 | } 221 | } 222 | }, 223 | "400": { 224 | "description": "Invalid tag value" 225 | } 226 | }, 227 | "security": [ 228 | { 229 | "petstore_auth": [ 230 | "write:pets", 231 | "read:pets" 232 | ] 233 | } 234 | ], 235 | "deprecated": true 236 | } 237 | }, 238 | "/pet/{petId}": { 239 | "get": { 240 | "tags": [ 241 | "pet" 242 | ], 243 | "summary": "Find pet by ID", 244 | "description": "Returns a single pet", 245 | "operationId": "getPetById", 246 | "produces": [ 247 | "application/xml", 248 | "application/json" 249 | ], 250 | "parameters": [ 251 | { 252 | "name": "petId", 253 | "in": "path", 254 | "description": "ID of pet to return", 255 | "required": true, 256 | "type": "integer", 257 | "format": "int64" 258 | } 259 | ], 260 | "responses": { 261 | "200": { 262 | "description": "successful operation", 263 | "schema": { 264 | "$ref": "#/definitions/Pet" 265 | } 266 | }, 267 | "400": { 268 | "description": "Invalid ID supplied" 269 | }, 270 | "404": { 271 | "description": "Pet not found" 272 | } 273 | }, 274 | "security": [ 275 | { 276 | "api_key": [] 277 | } 278 | ] 279 | }, 280 | "post": { 281 | "tags": [ 282 | "pet" 283 | ], 284 | "summary": "Updates a pet in the store with form data", 285 | "description": "", 286 | "operationId": "updatePetWithForm", 287 | "consumes": [ 288 | "application/x-www-form-urlencoded" 289 | ], 290 | "produces": [ 291 | "application/xml", 292 | "application/json" 293 | ], 294 | "parameters": [ 295 | { 296 | "name": "petId", 297 | "in": "path", 298 | "description": "ID of pet that needs to be updated", 299 | "required": true, 300 | "type": "integer", 301 | "format": "int64" 302 | }, 303 | { 304 | "name": "name", 305 | "in": "formData", 306 | "description": "Updated name of the pet", 307 | "required": false, 308 | "type": "string" 309 | }, 310 | { 311 | "name": "status", 312 | "in": "formData", 313 | "description": "Updated status of the pet", 314 | "required": false, 315 | "type": "string" 316 | } 317 | ], 318 | "responses": { 319 | "405": { 320 | "description": "Invalid input" 321 | } 322 | }, 323 | "security": [ 324 | { 325 | "petstore_auth": [ 326 | "write:pets", 327 | "read:pets" 328 | ] 329 | } 330 | ] 331 | }, 332 | "delete": { 333 | "tags": [ 334 | "pet" 335 | ], 336 | "summary": "Deletes a pet", 337 | "description": "", 338 | "operationId": "deletePet", 339 | "produces": [ 340 | "application/xml", 341 | "application/json" 342 | ], 343 | "parameters": [ 344 | { 345 | "name": "api_key", 346 | "in": "header", 347 | "required": false, 348 | "type": "string" 349 | }, 350 | { 351 | "name": "petId", 352 | "in": "path", 353 | "description": "Pet id to delete", 354 | "required": true, 355 | "type": "integer", 356 | "format": "int64" 357 | } 358 | ], 359 | "responses": { 360 | "400": { 361 | "description": "Invalid ID supplied" 362 | }, 363 | "404": { 364 | "description": "Pet not found" 365 | } 366 | }, 367 | "security": [ 368 | { 369 | "petstore_auth": [ 370 | "write:pets", 371 | "read:pets" 372 | ] 373 | } 374 | ] 375 | } 376 | }, 377 | "/pet/{petId}/uploadImage": { 378 | "post": { 379 | "tags": [ 380 | "pet" 381 | ], 382 | "summary": "uploads an image", 383 | "description": "", 384 | "operationId": "uploadFile", 385 | "consumes": [ 386 | "multipart/form-data" 387 | ], 388 | "produces": [ 389 | "application/json" 390 | ], 391 | "parameters": [ 392 | { 393 | "name": "petId", 394 | "in": "path", 395 | "description": "ID of pet to update", 396 | "required": true, 397 | "type": "integer", 398 | "format": "int64" 399 | }, 400 | { 401 | "name": "additionalMetadata", 402 | "in": "formData", 403 | "description": "Additional data to pass to server", 404 | "required": false, 405 | "type": "string" 406 | }, 407 | { 408 | "name": "file", 409 | "in": "formData", 410 | "description": "file to upload", 411 | "required": false, 412 | "type": "file" 413 | } 414 | ], 415 | "responses": { 416 | "200": { 417 | "description": "successful operation", 418 | "schema": { 419 | "$ref": "#/definitions/ApiResponse" 420 | } 421 | } 422 | }, 423 | "security": [ 424 | { 425 | "petstore_auth": [ 426 | "write:pets", 427 | "read:pets" 428 | ] 429 | } 430 | ] 431 | } 432 | }, 433 | "/store/inventory": { 434 | "get": { 435 | "tags": [ 436 | "store" 437 | ], 438 | "summary": "Returns pet inventories by status", 439 | "description": "Returns a map of status codes to quantities", 440 | "operationId": "getInventory", 441 | "produces": [ 442 | "application/json" 443 | ], 444 | "parameters": [], 445 | "responses": { 446 | "200": { 447 | "description": "successful operation", 448 | "schema": { 449 | "type": "object", 450 | "additionalProperties": { 451 | "type": "integer", 452 | "format": "int32" 453 | } 454 | } 455 | } 456 | }, 457 | "security": [ 458 | { 459 | "api_key": [] 460 | } 461 | ] 462 | } 463 | }, 464 | "/store/order": { 465 | "post": { 466 | "tags": [ 467 | "store" 468 | ], 469 | "summary": "Place an order for a pet", 470 | "description": "", 471 | "operationId": "placeOrder", 472 | "produces": [ 473 | "application/xml", 474 | "application/json" 475 | ], 476 | "parameters": [ 477 | { 478 | "in": "body", 479 | "name": "body", 480 | "description": "order placed for purchasing the pet", 481 | "required": true, 482 | "schema": { 483 | "$ref": "#/definitions/Order" 484 | } 485 | } 486 | ], 487 | "responses": { 488 | "200": { 489 | "description": "successful operation", 490 | "schema": { 491 | "$ref": "#/definitions/Order" 492 | } 493 | }, 494 | "400": { 495 | "description": "Invalid Order" 496 | } 497 | } 498 | } 499 | }, 500 | "/store/order/{orderId}": { 501 | "get": { 502 | "tags": [ 503 | "store" 504 | ], 505 | "summary": "Find purchase order by ID", 506 | "description": "For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions", 507 | "operationId": "getOrderById", 508 | "produces": [ 509 | "application/xml", 510 | "application/json" 511 | ], 512 | "parameters": [ 513 | { 514 | "name": "orderId", 515 | "in": "path", 516 | "description": "ID of pet that needs to be fetched", 517 | "required": true, 518 | "type": "integer", 519 | "maximum": 10, 520 | "minimum": 1, 521 | "format": "int64" 522 | } 523 | ], 524 | "responses": { 525 | "200": { 526 | "description": "successful operation", 527 | "schema": { 528 | "$ref": "#/definitions/Order" 529 | } 530 | }, 531 | "400": { 532 | "description": "Invalid ID supplied" 533 | }, 534 | "404": { 535 | "description": "Order not found" 536 | } 537 | } 538 | }, 539 | "delete": { 540 | "tags": [ 541 | "store" 542 | ], 543 | "summary": "Delete purchase order by ID", 544 | "description": "For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors", 545 | "operationId": "deleteOrder", 546 | "produces": [ 547 | "application/xml", 548 | "application/json" 549 | ], 550 | "parameters": [ 551 | { 552 | "name": "orderId", 553 | "in": "path", 554 | "description": "ID of the order that needs to be deleted", 555 | "required": true, 556 | "type": "integer", 557 | "minimum": 1, 558 | "format": "int64" 559 | } 560 | ], 561 | "responses": { 562 | "400": { 563 | "description": "Invalid ID supplied" 564 | }, 565 | "404": { 566 | "description": "Order not found" 567 | } 568 | } 569 | } 570 | }, 571 | "/user": { 572 | "post": { 573 | "tags": [ 574 | "user" 575 | ], 576 | "summary": "Create user", 577 | "description": "This can only be done by the logged in user.", 578 | "operationId": "createUser", 579 | "produces": [ 580 | "application/xml", 581 | "application/json" 582 | ], 583 | "parameters": [ 584 | { 585 | "in": "body", 586 | "name": "body", 587 | "description": "Created user object", 588 | "required": true, 589 | "schema": { 590 | "$ref": "#/definitions/User" 591 | } 592 | } 593 | ], 594 | "responses": { 595 | "default": { 596 | "description": "successful operation" 597 | } 598 | } 599 | } 600 | }, 601 | "/user/createWithArray": { 602 | "post": { 603 | "tags": [ 604 | "user" 605 | ], 606 | "summary": "Creates list of users with given input array", 607 | "description": "", 608 | "operationId": "createUsersWithArrayInput", 609 | "produces": [ 610 | "application/xml", 611 | "application/json" 612 | ], 613 | "parameters": [ 614 | { 615 | "in": "body", 616 | "name": "body", 617 | "description": "List of user object", 618 | "required": true, 619 | "schema": { 620 | "type": "array", 621 | "items": { 622 | "$ref": "#/definitions/User" 623 | } 624 | } 625 | } 626 | ], 627 | "responses": { 628 | "default": { 629 | "description": "successful operation" 630 | } 631 | } 632 | } 633 | }, 634 | "/user/createWithList": { 635 | "post": { 636 | "tags": [ 637 | "user" 638 | ], 639 | "summary": "Creates list of users with given input array", 640 | "description": "", 641 | "operationId": "createUsersWithListInput", 642 | "produces": [ 643 | "application/xml", 644 | "application/json" 645 | ], 646 | "parameters": [ 647 | { 648 | "in": "body", 649 | "name": "body", 650 | "description": "List of user object", 651 | "required": true, 652 | "schema": { 653 | "type": "array", 654 | "items": { 655 | "$ref": "#/definitions/User" 656 | } 657 | } 658 | } 659 | ], 660 | "responses": { 661 | "default": { 662 | "description": "successful operation" 663 | } 664 | } 665 | } 666 | }, 667 | "/user/login": { 668 | "get": { 669 | "tags": [ 670 | "user" 671 | ], 672 | "summary": "Logs user into the system", 673 | "description": "", 674 | "operationId": "loginUser", 675 | "produces": [ 676 | "application/xml", 677 | "application/json" 678 | ], 679 | "parameters": [ 680 | { 681 | "name": "username", 682 | "in": "query", 683 | "description": "The user name for login", 684 | "required": true, 685 | "type": "string" 686 | }, 687 | { 688 | "name": "password", 689 | "in": "query", 690 | "description": "The password for login in clear text", 691 | "required": true, 692 | "type": "string" 693 | } 694 | ], 695 | "responses": { 696 | "200": { 697 | "description": "successful operation", 698 | "schema": { 699 | "type": "string" 700 | }, 701 | "headers": { 702 | "X-Rate-Limit": { 703 | "type": "integer", 704 | "format": "int32", 705 | "description": "calls per hour allowed by the user" 706 | }, 707 | "X-Expires-After": { 708 | "type": "string", 709 | "format": "date-time", 710 | "description": "date in UTC when token expires" 711 | } 712 | } 713 | }, 714 | "400": { 715 | "description": "Invalid username/password supplied" 716 | } 717 | } 718 | } 719 | }, 720 | "/user/logout": { 721 | "get": { 722 | "tags": [ 723 | "user" 724 | ], 725 | "summary": "Logs out current logged in user session", 726 | "description": "", 727 | "operationId": "logoutUser", 728 | "produces": [ 729 | "application/xml", 730 | "application/json" 731 | ], 732 | "parameters": [], 733 | "responses": { 734 | "default": { 735 | "description": "successful operation" 736 | } 737 | } 738 | } 739 | }, 740 | "/user/{username}": { 741 | "get": { 742 | "tags": [ 743 | "user" 744 | ], 745 | "summary": "Get user by user name", 746 | "description": "", 747 | "operationId": "getUserByName", 748 | "produces": [ 749 | "application/xml", 750 | "application/json" 751 | ], 752 | "parameters": [ 753 | { 754 | "name": "username", 755 | "in": "path", 756 | "description": "The name that needs to be fetched. Use user1 for testing. ", 757 | "required": true, 758 | "type": "string" 759 | } 760 | ], 761 | "responses": { 762 | "200": { 763 | "description": "successful operation", 764 | "schema": { 765 | "$ref": "#/definitions/User" 766 | } 767 | }, 768 | "400": { 769 | "description": "Invalid username supplied" 770 | }, 771 | "404": { 772 | "description": "User not found" 773 | } 774 | } 775 | }, 776 | "put": { 777 | "tags": [ 778 | "user" 779 | ], 780 | "summary": "Updated user", 781 | "description": "This can only be done by the logged in user.", 782 | "operationId": "updateUser", 783 | "produces": [ 784 | "application/xml", 785 | "application/json" 786 | ], 787 | "parameters": [ 788 | { 789 | "name": "username", 790 | "in": "path", 791 | "description": "name that need to be updated", 792 | "required": true, 793 | "type": "string" 794 | }, 795 | { 796 | "in": "body", 797 | "name": "body", 798 | "description": "Updated user object", 799 | "required": true, 800 | "schema": { 801 | "$ref": "#/definitions/User" 802 | } 803 | } 804 | ], 805 | "responses": { 806 | "400": { 807 | "description": "Invalid user supplied" 808 | }, 809 | "404": { 810 | "description": "User not found" 811 | } 812 | } 813 | }, 814 | "delete": { 815 | "tags": [ 816 | "user" 817 | ], 818 | "summary": "Delete user", 819 | "description": "This can only be done by the logged in user.", 820 | "operationId": "deleteUser", 821 | "produces": [ 822 | "application/xml", 823 | "application/json" 824 | ], 825 | "parameters": [ 826 | { 827 | "name": "username", 828 | "in": "path", 829 | "description": "The name that needs to be deleted", 830 | "required": true, 831 | "type": "string" 832 | } 833 | ], 834 | "responses": { 835 | "400": { 836 | "description": "Invalid username supplied" 837 | }, 838 | "404": { 839 | "description": "User not found" 840 | } 841 | } 842 | } 843 | } 844 | }, 845 | "securityDefinitions": { 846 | "petstore_auth": { 847 | "type": "oauth2", 848 | "authorizationUrl": "http://petstore.swagger.io/oauth/dialog", 849 | "flow": "implicit", 850 | "scopes": { 851 | "write:pets": "modify pets in your account", 852 | "read:pets": "read your pets" 853 | } 854 | }, 855 | "api_key": { 856 | "type": "apiKey", 857 | "name": "api_key", 858 | "in": "header" 859 | } 860 | }, 861 | "definitions": { 862 | "Order": { 863 | "type": "object", 864 | "properties": { 865 | "id": { 866 | "type": "integer", 867 | "format": "int64" 868 | }, 869 | "petId": { 870 | "type": "integer", 871 | "format": "int64" 872 | }, 873 | "quantity": { 874 | "type": "integer", 875 | "format": "int32" 876 | }, 877 | "shipDate": { 878 | "type": "string", 879 | "format": "date-time" 880 | }, 881 | "status": { 882 | "type": "string", 883 | "description": "Order Status", 884 | "enum": [ 885 | "placed", 886 | "approved", 887 | "delivered" 888 | ] 889 | }, 890 | "complete": { 891 | "type": "boolean", 892 | "default": false 893 | } 894 | }, 895 | "xml": { 896 | "name": "Order" 897 | } 898 | }, 899 | "Category": { 900 | "type": "object", 901 | "properties": { 902 | "id": { 903 | "type": "integer", 904 | "format": "int64" 905 | }, 906 | "name": { 907 | "type": "string" 908 | } 909 | }, 910 | "xml": { 911 | "name": "Category" 912 | } 913 | }, 914 | "User": { 915 | "type": "object", 916 | "properties": { 917 | "id": { 918 | "type": "integer", 919 | "format": "int64" 920 | }, 921 | "username": { 922 | "type": "string" 923 | }, 924 | "firstName": { 925 | "type": "string" 926 | }, 927 | "lastName": { 928 | "type": "string" 929 | }, 930 | "email": { 931 | "type": "string" 932 | }, 933 | "password": { 934 | "type": "string" 935 | }, 936 | "phone": { 937 | "type": "string" 938 | }, 939 | "userStatus": { 940 | "type": "integer", 941 | "format": "int32", 942 | "description": "User Status" 943 | } 944 | }, 945 | "xml": { 946 | "name": "User" 947 | } 948 | }, 949 | "Tag": { 950 | "type": "object", 951 | "properties": { 952 | "id": { 953 | "type": "integer", 954 | "format": "int64" 955 | }, 956 | "name": { 957 | "type": "string" 958 | } 959 | }, 960 | "xml": { 961 | "name": "Tag" 962 | } 963 | }, 964 | "Pet": { 965 | "type": "object", 966 | "required": [ 967 | "name", 968 | "photoUrls" 969 | ], 970 | "properties": { 971 | "id": { 972 | "type": "integer", 973 | "format": "int64" 974 | }, 975 | "category": { 976 | "$ref": "#/definitions/Category" 977 | }, 978 | "name": { 979 | "type": "string", 980 | "example": "doggie" 981 | }, 982 | "photoUrls": { 983 | "type": "array", 984 | "xml": { 985 | "name": "photoUrl", 986 | "wrapped": true 987 | }, 988 | "items": { 989 | "type": "string" 990 | } 991 | }, 992 | "tags": { 993 | "type": "array", 994 | "xml": { 995 | "name": "tag", 996 | "wrapped": true 997 | }, 998 | "items": { 999 | "$ref": "#/definitions/Tag" 1000 | } 1001 | }, 1002 | "status": { 1003 | "type": "string", 1004 | "description": "pet status in the store", 1005 | "enum": [ 1006 | "available", 1007 | "pending", 1008 | "sold" 1009 | ] 1010 | } 1011 | }, 1012 | "xml": { 1013 | "name": "Pet" 1014 | } 1015 | }, 1016 | "ApiResponse": { 1017 | "type": "object", 1018 | "properties": { 1019 | "code": { 1020 | "type": "integer", 1021 | "format": "int32" 1022 | }, 1023 | "type": { 1024 | "type": "string" 1025 | }, 1026 | "message": { 1027 | "type": "string" 1028 | } 1029 | } 1030 | } 1031 | }, 1032 | "externalDocs": { 1033 | "description": "Find out more about Swagger", 1034 | "url": "http://swagger.io" 1035 | } 1036 | } -------------------------------------------------------------------------------- /src/swagger-docs/user.yaml: -------------------------------------------------------------------------------- 1 | paths: 2 | /users/: # path of the user from your endpoint 3 | post: # endpoint request type (post request) 4 | tags: # Tag property 5 | - User # Value of the tag 6 | summary: creates a new user 7 | produces: 8 | - application/json 9 | parameters: # request parameters 10 | - in: body # request body 11 | name: sign up # name of request, can be any name 12 | description: It enables a user to create an account 13 | required: false # can also be true depending on user preference 14 | schema: # Schema definition 15 | $ref: '#/definitions/signUp' 16 | responses: # server responses 17 | 201: 18 | description: An object with user details 19 | definitions: # Schema defination for request body 20 | signUp: 21 | type: object 22 | properties: 23 | user: 24 | type: object 25 | properties: 26 | username: 27 | type: string 28 | email: 29 | type: string 30 | password: 31 | type: string 32 | -------------------------------------------------------------------------------- /src/utils/swaggerIgnite.ts: -------------------------------------------------------------------------------- 1 | import { cleanEnv, str } from 'envalid'; 2 | import * as swaggerUi from 'swagger-ui-express'; 3 | import * as swaggerJSDoc from 'swagger-jsdoc'; 4 | import {Application} from 'express'; 5 | 6 | function swaggerIgnite(applicationInstance:Application) { 7 | const { PORT, APP_PATH } = process.env; 8 | // Swagger definition 9 | const swaggerDefinition = { 10 | info: { 11 | title: 'REST API for my App', // Title of the documentation 12 | version: '1.0.0', // Version of the app 13 | description: 'This is the REST API for my product', // short description of the app 14 | }, 15 | host: APP_PATH+':'+PORT, // the host or url of the app 16 | basePath: '/', // the basepath of your endpoint 17 | schemes: [ 18 | "https", 19 | "http" 20 | ], 21 | }; 22 | 23 | // options for the swagger docs 24 | const options = { 25 | // import swaggerDefinitions 26 | swaggerDefinition, 27 | // path to the API docs 28 | apis: ["./src/swagger-docs/**/*.yaml"], 29 | }; 30 | // initialize swagger-jsdoc 31 | const swaggerSpec = swaggerJSDoc(options); 32 | 33 | // use swagger-Ui-express for your app documentation endpoint 34 | applicationInstance.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec)); 35 | } 36 | 37 | export default swaggerIgnite; 38 | -------------------------------------------------------------------------------- /src/utils/validateEnv.ts: -------------------------------------------------------------------------------- 1 | import { cleanEnv, str } from 'envalid'; 2 | 3 | function validateEnv() { 4 | cleanEnv(process.env, { 5 | NODE_ENV: str(), 6 | MONGO_USER: str(), 7 | MONGO_PASSWORD: str(), 8 | MONGO_PATH: str() 9 | }); 10 | } 11 | 12 | export default validateEnv; 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "target": "es2017", 5 | "outDir": "./dist", 6 | "baseUrl": "./src", 7 | "alwaysStrict": true, 8 | "noImplicitAny": true, 9 | "resolveJsonModule":true, 10 | "experimentalDecorators": true, 11 | "emitDecoratorMetadata": true, 12 | "allowSyntheticDefaultImports": false, 13 | "moduleResolution": "node", 14 | "typeRoots": ["./node_modules/@types"] 15 | }, 16 | "include": ["src/**/*.ts"], 17 | "exclude": ["node_modules"] 18 | } 19 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": ["tslint:recommended", "tslint-config-airbnb"], 4 | "jsRules": { 5 | "no-unused-expression": true 6 | }, 7 | "rules": { 8 | "max-line-length": [true, 150], 9 | "prefer-template": false, 10 | "interface-name": [true, "never-prefix"], 11 | "import-name": false, 12 | "no-console": false, 13 | "object-literal-sort-keys": false, 14 | "disable-next-line": ["align", "no-trailing-whitespace"], 15 | "max-classes-per-file": true, 16 | "no-parameter-reassignment": false 17 | }, 18 | "rulesDirectory": [] 19 | } 20 | --------------------------------------------------------------------------------