From 9e6c916fa98aa0652cc828b116c74deb70132e39 Mon Sep 17 00:00:00 2001 From: Avsco Date: Thu, 15 Oct 2020 11:43:31 -0400 Subject: [PATCH 1/2] refactor: add handlerWrror & remove arrow function --- src/app.ts | 9 ++-- src/database.ts | 4 +- .../users/{model.ts => busiessController.ts} | 10 +--- src/modules/users/controller.ts | 48 ++++++++----------- src/modules/users/dao.ts | 26 +++++----- src/modules/users/dto.ts | 6 +-- src/modules/users/modelSchema.ts | 25 +--------- src/modules/users/routes.ts | 8 ++-- src/services/encriptor.ts | 13 +++++ src/services/handlerError.ts | 7 +++ 10 files changed, 68 insertions(+), 88 deletions(-) rename src/modules/users/{model.ts => busiessController.ts} (71%) create mode 100644 src/services/encriptor.ts create mode 100644 src/services/handlerError.ts diff --git a/src/app.ts b/src/app.ts index 231717b..dac1dd1 100644 --- a/src/app.ts +++ b/src/app.ts @@ -14,22 +14,23 @@ class App { this.initRoutes() } - public initServer = async () => { + async initServer() { try { - this.app.listen(this.port, () => console.log(`Listening on http://${'localhost'}:${this.port}/`)) + this.app.listen(this.port, () => + console.log(`Listening on http://${'localhost'}:${this.port}/`)) } catch (error) { console.error(error) } } - private config = () => { + private config() { this.app.use(cors()) this.app.use(express.json()) this.app.use(express.urlencoded({ extended: false })) if (process.env.NODE_ENV !== 'production') this.app.use(morgan('dev')) } - private initRoutes = () => { + private initRoutes() { router(this.app) } } diff --git a/src/database.ts b/src/database.ts index ce9edf5..dcc7c4d 100644 --- a/src/database.ts +++ b/src/database.ts @@ -13,11 +13,11 @@ class Database { } } - public init = async () => { + async init () { await this.connect() } - private connect = async () => { + private async connect() { try { await mongoose.connect(this.URI, this.config) console.log('database conected') diff --git a/src/modules/users/model.ts b/src/modules/users/busiessController.ts similarity index 71% rename from src/modules/users/model.ts rename to src/modules/users/busiessController.ts index dffd45b..5ad3cac 100644 --- a/src/modules/users/model.ts +++ b/src/modules/users/busiessController.ts @@ -1,24 +1,18 @@ -/*No sabe nada del controlador y de la base de datos, solo recibe los datos del controlador -y se los manda a la capa de la base de datos (dao)*/ import Dao from "./dao"; import { Interface } from "./modelSchema"; -class Model{ +class BusniesController{ public show = async (id: string): Promise => await Dao.show(id) - public put = async (id: string, model: any): Promise => await Dao.put(id, model) - public signIn = async (username: string, password: string): Promise => await Dao.signIn(username, password) - public signUp = async (model: any): Promise => await Dao.signUp(model) } - -export default new Model() \ No newline at end of file +export default new BusniesController() diff --git a/src/modules/users/controller.ts b/src/modules/users/controller.ts index 3aa123e..df7ca44 100644 --- a/src/modules/users/controller.ts +++ b/src/modules/users/controller.ts @@ -1,44 +1,39 @@ import { Request, Response } from 'express' import Dto from "./dto"; -import Model from './model' +import busiessController from './busiessController' -class Controller{ - public show = async (req: Request, res: Response): Promise => { +import { handlerError } from "../../services/handlerError"; + +class Controller { + async show (req: Request, res: Response): Promise { try { const id = req.params.id - const model = await Model.show(id) + const model = await busiessController.show(id) if(!model) return res.status(404).json({msg: 'El recurso no existe' }) - + return res.status(200).json(Dto.single(model)) } catch (error) { - return res.status(422).json({ code: error.code, msg: error.message }) + return handlerError(error.code, error.message, res) } } - public put = async (req: Request, res: Response): Promise => { + async put (req: Request, res: Response): Promise { try { - let model: any = {} - if(req.body.name) model.name = req.body.name - if(req.body.namusernamee) model.username = req.body.username - if(req.body.password) model.password = req.body.password - - const newModel = await Model.put(req.params.id, model) + const model: any = {... req.body} + + const newModel = await busiessController.put(req.params.id, model) if(!newModel) return res.status(404).json({msg: 'El recurso no existe' }) return res.status(200).json(Dto.single(newModel)) } catch (error) { - return res.status(422).json({ code: error.code, msg: error.message }) + return handlerError(error.code, error.message, res) } } - public signUp = async (req: Request, res: Response): Promise => { + async signUp (req: Request, res: Response): Promise { try { - if(!req.body.name) return res.status(400).json({msg: 'falta el nombre'}) - if(!req.body.username) return res.status(400).json({msg: 'falta el username'}) - if(!req.body.password) return res.status(400).json({msg: 'falta el password'}) - - const newModel = await Model.signUp({ + const newModel = await busiessController.signUp({ username: req.body.username, name: req.body.name, password: req.body.password @@ -47,21 +42,20 @@ class Controller{ return res.status(201).json(Dto.single(newModel)) } catch (error) { - return res.status(422).json({ code: error.code, msg: error.message }) + return handlerError(error.code, error.message, res) } } - public signIn = async (req: Request, res: Response) => { + async signIn (req: Request, res: Response) { try { - if(!req.body.username) return res.status(400).json({msg: 'falta el username'}) - if(!req.body.password) return res.status(400).json({msg: 'falta el password'}) + if(!req.body.username) return res.status(400).json({ msg: 'Error en username o password' }) - const model = await Model.signIn(req.body.username, req.body.password) - if(!model) return res.status(404).json({msg: 'Erorr en username o password' }) + const model = await busiessController.signIn(req.body.username, req.body.password) + if(!model) return res.status(404).json({msg: 'Error en username o password' }) return res.status(200).json(Dto.single(model)) } catch (error) { - return res.status(422).json({ code: error.code, msg: error.message }) + return handlerError(error.code, error.message, res) } } } diff --git a/src/modules/users/dao.ts b/src/modules/users/dao.ts index 953c922..61a0056 100644 --- a/src/modules/users/dao.ts +++ b/src/modules/users/dao.ts @@ -1,37 +1,33 @@ -/* Recien trabajamos con las consulatas de la base de datos */ -import { response } from 'express' import ModelSchema, { Interface } from './modelSchema' +import { comparePassword, encryptPassword } from "../../services/encriptor"; class Dao{ - public show = async (id: string): Promise => { - // const model = await ModelSchema.findById(id) - // if(!model) return null - // return model - - return new Promise((resolve, reject) => ModelSchema.findById({id: id}, (err, doc) => { - if(err) return reject(err) - return resolve(doc) - })) + async show (id: string): Promise { + const model = await ModelSchema.findById(id) + if(!model) return null + return model } - public put = async (id: string, newModel: any): Promise => { + async put (id: string, newModel: Interface): Promise { + if(newModel.password) newModel.password = await encryptPassword(newModel.password) const updated = await ModelSchema.findByIdAndUpdate(id, newModel) if(!updated) return null return updated } - public signIn = async (username: string, password: string): Promise => { + async signIn (username: string, password: string): Promise { const model = await ModelSchema.findOne({username: username}) if(!model) return null - const isMatch = await model.comparePassword(password) + const isMatch = await comparePassword(password, model.password) if (isMatch) return model return null } - public signUp = async (model: Interface): Promise => { + async signUp (model: Interface): Promise { const newModel = new ModelSchema(model) + newModel.password = await encryptPassword(newModel.password) await newModel.save() return newModel } diff --git a/src/modules/users/dto.ts b/src/modules/users/dto.ts index 337b976..1657b14 100644 --- a/src/modules/users/dto.ts +++ b/src/modules/users/dto.ts @@ -1,12 +1,10 @@ -/* Los parametros que recivo del controlador despues de que vea obtenido la -respuesta de la base de datos aqui los transformo para poder mandarlos bonito*/ import { Interface } from "./modelSchema"; -class Dto { +class UserDto { public single = (model: Interface) => ({ name: model.name, usermane: model.username }) } -export default new Dto() \ No newline at end of file +export default new UserDto() \ No newline at end of file diff --git a/src/modules/users/modelSchema.ts b/src/modules/users/modelSchema.ts index c051c90..6c50e64 100644 --- a/src/modules/users/modelSchema.ts +++ b/src/modules/users/modelSchema.ts @@ -1,16 +1,12 @@ - import { model, Schema, Document } from 'mongoose' -import bcrypt from 'bcrypt' - export interface Interface extends Document { name: string username: string password: string - comparePassword: (password: string) => Promise - encryptPassword: (password: string) => Promise } +//add validators const modelSchema: Schema = new Schema( { name: { @@ -26,27 +22,8 @@ const modelSchema: Schema = new Schema( type: String, required: true, }, - }, { versionKey: false } ) -modelSchema.pre('save', async function (next) { - const schema = this - if (!schema.isModified('password')) return next() - - schema.password = await schema.encryptPassword(schema.password) - next() -}) - -modelSchema.methods.comparePassword = async function (password: string): Promise { - return await bcrypt.compare(password, this.password) -} - -modelSchema.methods.encryptPassword = async function (password: string): Promise { - const salt = await bcrypt.genSalt(10) - const hash = await bcrypt.hash(password, salt) - return hash -} - export default model('users', modelSchema) \ No newline at end of file diff --git a/src/modules/users/routes.ts b/src/modules/users/routes.ts index 84a28b3..39d3198 100644 --- a/src/modules/users/routes.ts +++ b/src/modules/users/routes.ts @@ -3,10 +3,10 @@ const router = Router() import controller from './controller' -router.get('/user/:id', controller.show) -router.put('/user/:id', controller.put) +router.get('/users/:id', controller.show) +router.put('/users/:id', controller.put) -router.post('/user/signin', controller.signIn) -router.post('/user/signup', controller.signUp) +router.post('/users/signin', controller.signIn) +router.post('/users/signup', controller.signUp) export { router as users } \ No newline at end of file diff --git a/src/services/encriptor.ts b/src/services/encriptor.ts new file mode 100644 index 0000000..1f50767 --- /dev/null +++ b/src/services/encriptor.ts @@ -0,0 +1,13 @@ +import bcrypt from 'bcrypt' + +async function comparePassword (password: string, encrytedPassword: string): Promise{ + return await bcrypt.compare(password, encrytedPassword) +} + + +async function encryptPassword (password: string): Promise { + const salt = await bcrypt.genSalt(10) + return await bcrypt.hash(password, salt) +} + +export { encryptPassword, comparePassword } \ No newline at end of file diff --git a/src/services/handlerError.ts b/src/services/handlerError.ts new file mode 100644 index 0000000..c90deb5 --- /dev/null +++ b/src/services/handlerError.ts @@ -0,0 +1,7 @@ +import { Response } from "express"; + +function handlerError(errorCode: number, errorMsg: string, res: Response){ + return res.status(500).json({code:errorCode ,msg: errorMsg}) +} + +export { handlerError } \ No newline at end of file From 501c3d38aeeac7c80b8825d23cab01597e4a2718 Mon Sep 17 00:00:00 2001 From: Avsco Date: Thu, 15 Oct 2020 21:19:54 -0400 Subject: [PATCH 2/2] feat(swagger): add swagger --- package-lock.json | 23 +++++++++++++++++ package.json | 4 ++- src/app.ts | 4 +++ src/swagger.json | 64 +++++++++++++++++++++++++++++++++++++++++++++++ tsconfig.json | 3 ++- 5 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 src/swagger.json diff --git a/package-lock.json b/package-lock.json index b883946..3adbbae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -148,6 +148,16 @@ "@types/mime": "*" } }, + "@types/swagger-ui-express": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.2.tgz", + "integrity": "sha512-t9teFTU8dKe69rX9EwL6OM2hbVquYdFM+sQ0REny4RalPlxAm+zyP04B12j4c7qEuDS6CnlwICywqWStPA3v4g==", + "dev": true, + "requires": { + "@types/express": "*", + "@types/serve-static": "*" + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -2203,6 +2213,19 @@ "has-flag": "^3.0.0" } }, + "swagger-ui-dist": { + "version": "3.35.2", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.35.2.tgz", + "integrity": "sha512-19oRW6ZVCTY7JnaMFnIUoxkqI+xhBOGzSFVQTMLDB9KTNASP82v/0SkNpY2T4zbjwZF2Y5bcty9E6rhLGAj0Gg==" + }, + "swagger-ui-express": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.1.4.tgz", + "integrity": "sha512-Ea96ecpC+Iq9GUqkeD/LFR32xSs8gYqmTW1gXCuKg81c26WV6ZC2FsBSPVExQP6WkyUuz5HEiR0sEv/HCC343g==", + "requires": { + "swagger-ui-dist": "^3.18.1" + } + }, "tar": { "version": "4.4.13", "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", diff --git a/package.json b/package.json index d458427..c79579c 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "express": "^4.17.1", "mongoose": "^5.10.9", "morgan": "^1.10.0", - "node-config-ts": "^3.1.0" + "node-config-ts": "^3.1.0", + "swagger-ui-express": "^4.1.4" }, "devDependencies": { "@types/bcrypt": "^3.0.0", @@ -26,6 +27,7 @@ "@types/express": "^4.17.8", "@types/mongoose": "^5.7.36", "@types/morgan": "^1.9.1", + "@types/swagger-ui-express": "^4.1.2", "nodemon": "^2.0.5", "rimraf": "^3.0.2", "ts-node": "^9.0.0", diff --git a/src/app.ts b/src/app.ts index dac1dd1..bc2e732 100644 --- a/src/app.ts +++ b/src/app.ts @@ -4,6 +4,8 @@ import router from "./router"; // import { config } from 'node-config-ts' import morgan from 'morgan' +import swaggerUi from 'swagger-ui-express'; +import swaggerDocument from './swagger.json' class App { private port = 5000 @@ -27,6 +29,8 @@ class App { this.app.use(cors()) this.app.use(express.json()) this.app.use(express.urlencoded({ extended: false })) + this.app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)) + if (process.env.NODE_ENV !== 'production') this.app.use(morgan('dev')) } diff --git a/src/swagger.json b/src/swagger.json new file mode 100644 index 0000000..d8fd1b4 --- /dev/null +++ b/src/swagger.json @@ -0,0 +1,64 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "My User Project CRUD" + }, + "host": "localhost:5000", + "basePath": "/", + "tags": [ + { + "name": "API", + "description": "API for users in the system" + } + ], + "schemes": [ + "http" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/users/{userId}": { + "get": { + "tags": [ + "User" + ], + "summary": "Get one user of sistem", + "parameters": [ + { + "name": "userId", + "in": "path", + "description": "ID of user to return", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Users" + } + } + } + } + } + }, + "definitions": { + "Users": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "username": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index b399153..0980a45 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,8 @@ "rootDir": "./src", "strict": true, "target": "ES2020", - "baseUrl": "." + "baseUrl": ".", + "resolveJsonModule": true, }, "exclude": ["node_modules"] } \ No newline at end of file