From dfc7574f7e395c21416e008a844cffccd5785f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cort=C3=A9s?= Date: Sat, 15 May 2021 15:01:13 -0400 Subject: [PATCH 01/15] se crea libreria de conexion de mongo --- src/lib/mongo.js | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/lib/mongo.js diff --git a/src/lib/mongo.js b/src/lib/mongo.js new file mode 100644 index 00000000..e1cb4dc3 --- /dev/null +++ b/src/lib/mongo.js @@ -0,0 +1,65 @@ +const { MongoClient, ObjectId } = require("mongodb"); +const { config } = require("../config"); + +const USER = encodeURIComponent(config.dbUser); +const PASSWORD = encodeURIComponent(config.dbPassword); +const DB_NAME = config.dbName; + +const MONGO_URI = `${config.dbConnection}://${USER}:${PASSWORD}@${config.dbHost}:${config.dbPort}/${config.dbName}?retryWrites=true&w=majority`; + +class MongoLib { + constructor() { + this.client = new MongoClient(MONGO_URI, { + useNewUrlParser: true, + }); + this.dbName = DB_NAME; + } + connect() { + if (!MongoLib.connection) { + MongoLib.connection = new Promise((resolve, reject) => { + this.client.connect((err) => { + if (err) { + reject(err); + } + console.log("Connected Succesfully"); + resolve(this.client.db(this.dbName)); + }); + }); + } + return MongoLib.connection; + } + getAll(collection, query) { + return this.connect().then((db) => { + return db.collection(collection).find(query).toArray(); + }); + } + get(collection, id) { + return this.connect().then((db) => { + return db.collection(collection).findOne({ _id: ObjectId(id) }); + }); + } + create(collection, data) { + return this.connect() + .then((db) => { + return db.collection(collection).insertOne(data); + }) + .then((result) => result.insertedId); + } + update(collection, data, id) { + return this.connect() + .then((db) => { + return db + .collection(collection) + .updateOne({ _id: ObjectId(id) }, { $set: data }, { upsert: true }); + }) + .then((result) => result.upsertedId || id); + } + delete(collection, id) { + return this.connect() + .then((db) => { + return db.collection(collection).deleteOne({ _id: ObjectId(id) }); + }) + .then(() => id); + } +} +module.exports = MongoLib; From f8876747e8c69b93f6cfe3b1f15af1700dc5feb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cort=C3=A9s?= Date: Sat, 15 May 2021 15:01:24 -0400 Subject: [PATCH 02/15] se instalan las dependencias --- package-lock.json | 39 +++++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 40 insertions(+) diff --git a/package-lock.json b/package-lock.json index 76a7fcef..cad404d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "mongodb": "^3.6.6" }, "devDependencies": { + "@types/mongodb": "^3.6.12", "jest": "^26.6.3", "nodemon": "^1.19.4", "supertest": "^6.1.3" @@ -1349,6 +1350,15 @@ "@babel/types": "^7.3.0" } }, + "node_modules/@types/bson": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.3.tgz", + "integrity": "sha512-mVRvYnTOZJz3ccpxhr3wgxVmSeiYinW+zlzQz3SXWaJmD1DuL05Jeq7nKw3SnbKmbleW5qrLG5vdyWe/A9sXhw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -1382,6 +1392,16 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/mongodb": { + "version": "3.6.12", + "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.12.tgz", + "integrity": "sha512-49aEzQD5VdHPxyd5dRyQdqEveAg9LanwrH8RQipnMuulwzKmODXIZRp0umtxi1eBUfEusRkoy8AVOMr+kVuFog==", + "dev": true, + "dependencies": { + "@types/bson": "*", + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "14.14.41", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.41.tgz", @@ -10832,6 +10852,15 @@ "@babel/types": "^7.3.0" } }, + "@types/bson": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.3.tgz", + "integrity": "sha512-mVRvYnTOZJz3ccpxhr3wgxVmSeiYinW+zlzQz3SXWaJmD1DuL05Jeq7nKw3SnbKmbleW5qrLG5vdyWe/A9sXhw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -10865,6 +10894,16 @@ "@types/istanbul-lib-report": "*" } }, + "@types/mongodb": { + "version": "3.6.12", + "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.12.tgz", + "integrity": "sha512-49aEzQD5VdHPxyd5dRyQdqEveAg9LanwrH8RQipnMuulwzKmODXIZRp0umtxi1eBUfEusRkoy8AVOMr+kVuFog==", + "dev": true, + "requires": { + "@types/bson": "*", + "@types/node": "*" + } + }, "@types/node": { "version": "14.14.41", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.41.tgz", diff --git a/package.json b/package.json index 279a5416..8bbbde62 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "mongodb": "^3.6.6" }, "devDependencies": { + "@types/mongodb": "^3.6.12", "jest": "^26.6.3", "nodemon": "^1.19.4", "supertest": "^6.1.3" From 862266c0eceae20462b516fc0230e4757f25da32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cort=C3=A9s?= Date: Sat, 15 May 2021 21:46:30 -0400 Subject: [PATCH 03/15] entidad producto con su controller y servicios funcionando --- src/Entities/Product/index.js | 14 +++++ src/Entities/Product/product.controller.js | 69 ++++++++++++++++++++++ src/Entities/Product/product.service.js | 34 +++++++++++ 3 files changed, 117 insertions(+) create mode 100644 src/Entities/Product/index.js create mode 100644 src/Entities/Product/product.controller.js create mode 100644 src/Entities/Product/product.service.js diff --git a/src/Entities/Product/index.js b/src/Entities/Product/index.js new file mode 100644 index 00000000..7713fa91 --- /dev/null +++ b/src/Entities/Product/index.js @@ -0,0 +1,14 @@ +const router = require("express").Router(); +const controller = require("./product.controller"); + +//get products +router.get("/", controller.getAll); +//get product by id +router.get("/:id", controller.getById); +//create Product +router.post("/", controller.createProduct); +//update Product +router.put("/:id", controller.updateProduct); +//delete Product +router.delete(":id", controller.deleteProduct); +module.exports = router; diff --git a/src/Entities/Product/product.controller.js b/src/Entities/Product/product.controller.js new file mode 100644 index 00000000..93c615b3 --- /dev/null +++ b/src/Entities/Product/product.controller.js @@ -0,0 +1,69 @@ +const ProductService = require("./product.service"); +const controller = {}; +const productsService = new ProductService(); +controller.getAll = async (req, res) => { + const { tags } = req.query; + try { + const products = await productsService.getAll({ tags }); + return res.status(200).json({ + data: products, + message: "Products Listed", + }); + } catch (error) { + console.error(error); + } +}; +controller.getById = async (req, res) => { + const { id } = req.params; + try { + const product = await productsService.getById({ id }); + return res.status(200).json({ + data: product, + message: "Video reatrived", + }); + } catch (error) { + console.log(error); + } +}; +controller.createProduct = async (req, res) => { + const { body: product } = req; + try { + const createProduct = await productsService.createProduct({ product }); + return res.status(201).json({ + data: createProduct, + message: "Product Created", + }); + } catch (error) { + console.log(error); + } +}; +controller.updateProduct = async (req, res) => { + const { body: product } = req; + const { id } = req.params; + try { + const updateProductId = await productsService.updateProduct({ + id, + product, + }); + return res.status(200).json({ + data: updateProductId, + message: "product updated", + }); + } catch (error) { + console.log(error); + } +}; +controller.deleteProduct = async (req, res) => { + const { id } = req.params; + try { + const deleteProductId = await productsService.deleteProduct({ id }); + return res.status(200).json({ + data: deleteProductId, + message: "Product deleted", + }); + } catch (error) { + console.log(error); + } +}; + +module.exports = controller; diff --git a/src/Entities/Product/product.service.js b/src/Entities/Product/product.service.js new file mode 100644 index 00000000..9abb127e --- /dev/null +++ b/src/Entities/Product/product.service.js @@ -0,0 +1,34 @@ +const MongoLib = require("../../lib/mongo"); + +class ProductService { + constructor() { + this.collection = "product"; + this.mongoDB = new MongoLib(); + } + async getAll({ tags }) { + const query = tags && { tags: { $in: tags } }; + const products = await this.mongoDB.getAll(this.collection, query); + return products || []; + } + async getById({ id }) { + const product = await this.mongoDB.get(this.collection, id); + return product || {}; + } + async createProduct({ product }) { + const createProductId = await this.mongoDB.create(this.collection, product); + return createProductId; + } + async updateProduct({ productId, product }) { + const updatedProductId = await this.mongoDB.update( + this.collection, + product, + productId + ); + return updatedProductId; + } + async deleteProduct({ id }) { + const deleteProductId = await this.mongoDB.delete(this.collection, id); + return deleteProductId; + } +} +module.exports = ProductService; From 2db700b3fd37f2705bf614492e2535d6eb9cbc1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cort=C3=A9s?= Date: Sat, 15 May 2021 21:47:13 -0400 Subject: [PATCH 04/15] se agrega el router de la api --- src/app.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/app.js b/src/app.js index 62a46b5e..09371590 100644 --- a/src/app.js +++ b/src/app.js @@ -1,12 +1,13 @@ -const express = require('express'); -const cors = require('cors'); +const express = require("express"); +const cors = require("cors"); +const apiRouter = require("./routes"); -function createApp() { +function createApp() { const app = express(); app.use(cors()); app.use(express.json()); - // ADD YOUR ROUTES + app.use("/api", apiRouter); return app; } From bccb6eb233de3293956c419db54a3b7dcc7372a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cort=C3=A9s?= Date: Sat, 15 May 2021 21:47:52 -0400 Subject: [PATCH 05/15] carpeta que contendra los routers de cada entidad --- src/routes/index.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/routes/index.js diff --git a/src/routes/index.js b/src/routes/index.js new file mode 100644 index 00000000..8ba76c11 --- /dev/null +++ b/src/routes/index.js @@ -0,0 +1,5 @@ +const router = require("express").Router(); +const apiProductRouter = require("../Entities/Product/index"); + +router.use("/product", apiProductRouter); +module.exports = router; From 3f71194480248de331dacf5f7720a8a228e8d389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cort=C3=A9s?= Date: Sat, 15 May 2021 23:36:14 -0400 Subject: [PATCH 06/15] crud de categorias --- src/Entities/Category/category.controller.js | 68 ++++++++++++++++++++ src/Entities/Category/category.service.js | 37 +++++++++++ src/Entities/Category/index.js | 15 +++++ 3 files changed, 120 insertions(+) create mode 100644 src/Entities/Category/category.controller.js create mode 100644 src/Entities/Category/category.service.js create mode 100644 src/Entities/Category/index.js diff --git a/src/Entities/Category/category.controller.js b/src/Entities/Category/category.controller.js new file mode 100644 index 00000000..875d07bb --- /dev/null +++ b/src/Entities/Category/category.controller.js @@ -0,0 +1,68 @@ +const controller = {}; +const CategoryService = require("./category.service"); +const categoryService = new CategoryService(); +controller.getAll = async (req, res) => { + const { tags } = req.query; + try { + const categories = await categoryService.getAll({ tags }); + return res.status(200).json({ + data: categories, + message: "Categories Listed", + }); + } catch (error) { + console.log(error); + } +}; +controller.getById = async (req, res) => { + const { id } = req.params; + try { + const category = await categoryService.getById({ id }); + return res.status(200).json({ + data: category, + message: "category reatrived", + }); + } catch (error) { + console.log(error); + } +}; +controller.createCategory = async (req, res) => { + const { body: category } = req; + try { + const createCategory = await categoryService.createCategory({ category }); + return res.status(201).json({ + data: createCategory, + message: "category Created", + }); + } catch (error) { + console.log(error); + } +}; +controller.updateCategory = async (req, res) => { + const { body: category } = req; + const { id } = req.params; + try { + const updateCategoryId = await categoryService.updateCategory({ + id, + category, + }); + return res.status(200).json({ + data: updateCategoryId, + message: "category updated", + }); + } catch (error) { + console.log(error); + } +}; +controller.deleteCategory = async (req, res) => { + const { id } = req.params; + try { + const deleteCategoryId = await categoryService.deleteCategory({ id }); + return res.status(200).json({ + data: deleteCategoryId, + message: "Category deleted", + }); + } catch (error) { + console.log(error); + } +}; +module.exports = controller; diff --git a/src/Entities/Category/category.service.js b/src/Entities/Category/category.service.js new file mode 100644 index 00000000..07911429 --- /dev/null +++ b/src/Entities/Category/category.service.js @@ -0,0 +1,37 @@ +const MongoLib = require("../../lib/mongo"); +class CategoryService { + constructor() { + this.collection = "categories"; + this.mongoDB = new MongoLib(); + } + async getAll({ tags }) { + const query = tags && { tags: { $in: tags } }; + const categories = await this.mongoDB.getAll(this.collection, query); + return categories || []; + } + async getById({ id }) { + const category = await this.mongoDB.get(this.collection, id); + return category || {}; + } + async createCategory({ category }) { + console.log({ category }); + const createCategoryId = await this.mongoDB.create( + this.collection, + category + ); + return createCategoryId; + } + async updateCategory({ id, category }) { + const updatedCategoryId = await this.mongoDB.update( + this.collection, + category, + id + ); + return updatedCategoryId; + } + async deleteCategory({ id }) { + const deleteCategoryId = await this.mongoDB.delete(this.collection, id); + return deleteCategoryId; + } +} +module.exports = CategoryService; diff --git a/src/Entities/Category/index.js b/src/Entities/Category/index.js new file mode 100644 index 00000000..57a4b7bb --- /dev/null +++ b/src/Entities/Category/index.js @@ -0,0 +1,15 @@ +const controller = require("./category.controller"); + +const router = require("express").Router(); + +//get categories +router.get("/", controller.getAll); +//get category by id +router.get("/:id", controller.getById); +//create category +router.post("/", controller.createCategory); +//update category +router.put("/:id", controller.updateCategory); +//delete category +router.delete("/:id", controller.deleteCategory); +module.exports = router; From 9aa7617f1b3987dd71a27a454bb9ba1287216a4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cort=C3=A9s?= Date: Sat, 15 May 2021 23:36:34 -0400 Subject: [PATCH 07/15] se modifica uri --- e2e/categories.e2e.js | 25 +++++++++++++------------ e2e/product.e2e.js | 14 ++++++++------ 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/e2e/categories.e2e.js b/e2e/categories.e2e.js index 3f1fc277..ed07b162 100644 --- a/e2e/categories.e2e.js +++ b/e2e/categories.e2e.js @@ -8,8 +8,8 @@ const USER = encodeURIComponent(config.dbUser); const PASSWORD = encodeURIComponent(config.dbPassword); const DB_NAME = config.dbName; -const MONGO_URI = `${config.dbConnection}://${USER}:${PASSWORD}@${config.dbHost}:${config.dbPort}?retryWrites=true&w=majority`; -const collection = 'categories'; +const MONGO_URI = `${config.dbConnection}://${USER}:${PASSWORD}@${config.dbHost}?retryWrites=true&w=majority`; +const collection = "categories"; describe("Tests to categories", () => { let app; @@ -37,14 +37,16 @@ describe("Tests to categories", () => { it("should create a new category", async (done) => { const newCategory = { name: "Category 1", - image: 'https://via.placeholder.com/150', + image: "https://via.placeholder.com/150", }; return request(app) .post("/api/categories") .send(newCategory) .expect(201) .then(async ({ body }) => { - const rta = await database.collection(collection).findOne({ _id: ObjectId(body._id) }); + const rta = await database + .collection(collection) + .findOne({ _id: ObjectId(body._id) }); expect(body.name).toBe(rta.name); expect(body.image).toBe(rta.image); done(); @@ -61,7 +63,9 @@ describe("Tests to categories", () => { .then(async ({ body }) => { expect(body.length).toBe(1); const model = body[0]; - const rta = await database.collection(collection).findOne({ _id: ObjectId(model._id) }); + const rta = await database + .collection(collection) + .findOne({ _id: ObjectId(model._id) }); expect(model.name).toBe(rta.name); expect(model.image).toBe(rta.image); done(); @@ -76,7 +80,7 @@ describe("Tests to categories", () => { expect(categories.length > 0).toBe(true); const category = categories[0]; const changes = { - name: 'change', + name: "change", }; return request(app) .put(`/api/categories/${category._id}`) @@ -109,17 +113,16 @@ describe("Tests to categories", () => { }); describe("GET /api/categories/{id}/products", () => { - it("should return a list products by category", async (done) => { const categories = await database.collection(collection).find().toArray(); expect(categories.length > 0).toBe(true); const category = categories[0]; const products = [ - { name: "Red", price: 200, categoryId: `${category._id}` }, + { name: "Red", price: 200, categoryId: `${category._id}` }, { name: "Blue", price: 300, categoryId: `${category._id}` }, - { name: "Leon", price: 400 } + { name: "Leon", price: 400 }, ]; - await database.collection('products').insertMany(products); + await database.collection("products").insertMany(products); return request(app) .get(`/api/categories/${category._id}/products`) .expect(200) @@ -148,6 +151,4 @@ describe("Tests to categories", () => { .catch((err) => done(err)); }); }); - - }); diff --git a/e2e/product.e2e.js b/e2e/product.e2e.js index dc94f0fc..61e72bf0 100644 --- a/e2e/product.e2e.js +++ b/e2e/product.e2e.js @@ -8,8 +8,8 @@ const USER = encodeURIComponent(config.dbUser); const PASSWORD = encodeURIComponent(config.dbPassword); const DB_NAME = config.dbName; -const MONGO_URI = `${config.dbConnection}://${USER}:${PASSWORD}@${config.dbHost}:${config.dbPort}?retryWrites=true&w=majority`; -const collection = 'products'; +const MONGO_URI = `${config.dbConnection}://${USER}:${PASSWORD}@${config.dbHost}?retryWrites=true&w=majority`; +const collection = "products"; describe("Tests to products", () => { let app; @@ -44,7 +44,9 @@ describe("Tests to products", () => { .send(newProduct) .expect(201) .then(async ({ body }) => { - const rta = await database.collection(collection).findOne({ _id: ObjectId(body._id) }); + const rta = await database + .collection(collection) + .findOne({ _id: ObjectId(body._id) }); expect(body.name).toBe(rta.name); expect(body.price).toBe(rta.price); done(); @@ -61,7 +63,9 @@ describe("Tests to products", () => { .then(async ({ body }) => { expect(body.length).toBe(1); const product = body[0]; - const rta = await database.collection(collection).findOne({ _id: ObjectId(product._id) }); + const rta = await database + .collection(collection) + .findOne({ _id: ObjectId(product._id) }); expect(product.name).toBe(rta.name); expect(product.price).toBe(rta.price); done(); @@ -123,6 +127,4 @@ describe("Tests to products", () => { .catch((err) => done(err)); }); }); - - }); From 08ba8ad5e26f1bef9da9b3aefc94682ce3b21119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cort=C3=A9s?= Date: Mon, 17 May 2021 21:36:03 -0400 Subject: [PATCH 08/15] se finaliza con ultimo endpoind para trear caterias con sus productos --- .vscode/launch.json | 15 +++++++++++++ package.json | 3 ++- src/Entities/Category/category.controller.js | 22 ++++++++++++++------ src/Entities/Category/category.service.js | 11 ++++++---- src/Entities/Category/index.js | 2 ++ src/Entities/Product/index.js | 2 +- src/Entities/Product/product.controller.js | 2 +- src/Entities/Product/product.service.js | 6 +++--- src/lib/mongo.js | 10 +++++---- src/routes/index.js | 5 +++-- 10 files changed, 56 insertions(+), 22 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..7a9dfa04 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "pwa-chrome", + "request": "launch", + "name": "Launch Chrome against localhost", + "url": "http://localhost:8080", + "webRoot": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/package.json b/package.json index 8bbbde62..b730cb49 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "scripts": { "dev": "DEBUG=app:* nodemon src/index.js", "start": "NODE_ENV=production node src/index.js", - "test:e2e": "jest --forceExit --config ./e2e/jest-e2e.json" + "test:e2e": "jest --forceExit --config ./e2e/jest-e2e.json", + "test": "jest" }, "repository": { "type": "git", diff --git a/src/Entities/Category/category.controller.js b/src/Entities/Category/category.controller.js index 875d07bb..9d8e7e56 100644 --- a/src/Entities/Category/category.controller.js +++ b/src/Entities/Category/category.controller.js @@ -2,9 +2,8 @@ const controller = {}; const CategoryService = require("./category.service"); const categoryService = new CategoryService(); controller.getAll = async (req, res) => { - const { tags } = req.query; try { - const categories = await categoryService.getAll({ tags }); + const categories = await categoryService.getAll(); return res.status(200).json({ data: categories, message: "Categories Listed", @@ -29,10 +28,7 @@ controller.createCategory = async (req, res) => { const { body: category } = req; try { const createCategory = await categoryService.createCategory({ category }); - return res.status(201).json({ - data: createCategory, - message: "category Created", - }); + return res.status(201).json(createCategory); } catch (error) { console.log(error); } @@ -65,4 +61,18 @@ controller.deleteCategory = async (req, res) => { console.log(error); } }; +controller.productsByCategory = async (req, res) => { + const { id } = req.params; + try { + const productsByCategory = await categoryService.getProductsByCategory({ + id, + }); + return res.status(200).json({ + data: productsByCategory, + message: "Products by category Listed", + }); + } catch (error) { + console.log(error); + } +}; module.exports = controller; diff --git a/src/Entities/Category/category.service.js b/src/Entities/Category/category.service.js index 07911429..6830c2d9 100644 --- a/src/Entities/Category/category.service.js +++ b/src/Entities/Category/category.service.js @@ -4,9 +4,8 @@ class CategoryService { this.collection = "categories"; this.mongoDB = new MongoLib(); } - async getAll({ tags }) { - const query = tags && { tags: { $in: tags } }; - const categories = await this.mongoDB.getAll(this.collection, query); + async getAll() { + const categories = await this.mongoDB.getAll(this.collection); return categories || []; } async getById({ id }) { @@ -14,7 +13,6 @@ class CategoryService { return category || {}; } async createCategory({ category }) { - console.log({ category }); const createCategoryId = await this.mongoDB.create( this.collection, category @@ -33,5 +31,10 @@ class CategoryService { const deleteCategoryId = await this.mongoDB.delete(this.collection, id); return deleteCategoryId; } + async getProductsByCategory({ id }) { + const query = { categoryId: id }; + const productsByCategory = await this.mongoDB.getAll("products", query); + return productsByCategory || []; + } } module.exports = CategoryService; diff --git a/src/Entities/Category/index.js b/src/Entities/Category/index.js index 57a4b7bb..5f6f4663 100644 --- a/src/Entities/Category/index.js +++ b/src/Entities/Category/index.js @@ -12,4 +12,6 @@ router.post("/", controller.createCategory); router.put("/:id", controller.updateCategory); //delete category router.delete("/:id", controller.deleteCategory); +//products byCategory +router.get("/:id/products", controller.productsByCategory); module.exports = router; diff --git a/src/Entities/Product/index.js b/src/Entities/Product/index.js index 7713fa91..3a129df8 100644 --- a/src/Entities/Product/index.js +++ b/src/Entities/Product/index.js @@ -10,5 +10,5 @@ router.post("/", controller.createProduct); //update Product router.put("/:id", controller.updateProduct); //delete Product -router.delete(":id", controller.deleteProduct); +router.delete("/:id", controller.deleteProduct); module.exports = router; diff --git a/src/Entities/Product/product.controller.js b/src/Entities/Product/product.controller.js index 93c615b3..36ef9852 100644 --- a/src/Entities/Product/product.controller.js +++ b/src/Entities/Product/product.controller.js @@ -19,7 +19,7 @@ controller.getById = async (req, res) => { const product = await productsService.getById({ id }); return res.status(200).json({ data: product, - message: "Video reatrived", + message: "Product reatrived", }); } catch (error) { console.log(error); diff --git a/src/Entities/Product/product.service.js b/src/Entities/Product/product.service.js index 9abb127e..cb4747df 100644 --- a/src/Entities/Product/product.service.js +++ b/src/Entities/Product/product.service.js @@ -2,7 +2,7 @@ const MongoLib = require("../../lib/mongo"); class ProductService { constructor() { - this.collection = "product"; + this.collection = "products"; this.mongoDB = new MongoLib(); } async getAll({ tags }) { @@ -18,11 +18,11 @@ class ProductService { const createProductId = await this.mongoDB.create(this.collection, product); return createProductId; } - async updateProduct({ productId, product }) { + async updateProduct({ id, product }) { const updatedProductId = await this.mongoDB.update( this.collection, product, - productId + id ); return updatedProductId; } diff --git a/src/lib/mongo.js b/src/lib/mongo.js index e1cb4dc3..b760987f 100644 --- a/src/lib/mongo.js +++ b/src/lib/mongo.js @@ -5,12 +5,13 @@ const USER = encodeURIComponent(config.dbUser); const PASSWORD = encodeURIComponent(config.dbPassword); const DB_NAME = config.dbName; -const MONGO_URI = `${config.dbConnection}://${USER}:${PASSWORD}@${config.dbHost}:${config.dbPort}/${config.dbName}?retryWrites=true&w=majority`; +const MONGO_URI = `${config.dbConnection}://${USER}:${PASSWORD}@${config.dbHost}/${config.dbName}?retryWrites=true&w=majority`; class MongoLib { constructor() { this.client = new MongoClient(MONGO_URI, { useNewUrlParser: true, + useUnifiedTopology: true, }); this.dbName = DB_NAME; } @@ -28,11 +29,12 @@ class MongoLib { } return MongoLib.connection; } - getAll(collection, query) { + getAll(collection) { return this.connect().then((db) => { - return db.collection(collection).find(query).toArray(); + return db.collection(collection).find().toArray(); }); } + get(collection, id) { return this.connect().then((db) => { return db.collection(collection).findOne({ _id: ObjectId(id) }); @@ -43,7 +45,7 @@ class MongoLib { .then((db) => { return db.collection(collection).insertOne(data); }) - .then((result) => result.insertedId); + .then(() => data); } update(collection, data, id) { return this.connect() diff --git a/src/routes/index.js b/src/routes/index.js index 8ba76c11..1a2c2f8c 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -1,5 +1,6 @@ const router = require("express").Router(); const apiProductRouter = require("../Entities/Product/index"); - -router.use("/product", apiProductRouter); +const apiCategoriesRouter = require("../Entities/Category/index"); +router.use("/products", apiProductRouter); +router.use("/categories", apiCategoriesRouter); module.exports = router; From 50b3e739ce903bf280f96b50664a91ba159e74eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cort=C3=A9s?= Date: Tue, 18 May 2021 00:13:58 -0400 Subject: [PATCH 09/15] se agregan schemas con joi y se cambia la estructura del proyecto --- package-lock.json | 104 ++++++++++++++++++ package.json | 2 + src/Entities/Category/index.js | 17 --- src/Entities/Product/index.js | 14 --- src/app.js | 4 +- .../category.controller.js | 33 ++---- .../product.controller.js | 30 ++--- src/lib/mongo.js | 20 ++-- src/middlewares/notFoundHandler.js | 8 ++ src/middlewares/validationHandler.js | 20 ++++ src/routes/category.routes.js | 39 +++++++ src/routes/index.js | 4 +- src/routes/product.routes.js | 36 ++++++ src/schemas/category.schema.js | 18 +++ src/schemas/product.schema.js | 27 +++++ .../Category => services}/category.service.js | 17 +-- .../Product => services}/product.service.js | 12 +- 17 files changed, 300 insertions(+), 105 deletions(-) delete mode 100644 src/Entities/Category/index.js delete mode 100644 src/Entities/Product/index.js rename src/{Entities/Category => controllers}/category.controller.js (66%) rename src/{Entities/Product => controllers}/product.controller.js (62%) create mode 100644 src/middlewares/notFoundHandler.js create mode 100644 src/middlewares/validationHandler.js create mode 100644 src/routes/category.routes.js create mode 100644 src/routes/product.routes.js create mode 100644 src/schemas/category.schema.js create mode 100644 src/schemas/product.schema.js rename src/{Entities/Category => services}/category.service.js (75%) rename src/{Entities/Product => services}/product.service.js (76%) diff --git a/package-lock.json b/package-lock.json index cad404d1..ecf1eeef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,11 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@hapi/boom": "^9.1.2", "cors": "^2.8.5", "dotenv": "^8.2.0", "express": "^4.17.1", + "joi": "^17.4.0", "mongodb": "^3.6.6" }, "devDependencies": { @@ -504,6 +506,27 @@ "node": ">=0.1.95" } }, + "node_modules/@hapi/boom": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.2.tgz", + "integrity": "sha512-uJEJtiNHzKw80JpngDGBCGAmWjBtzxDCz17A9NO2zCi8LLBlb5Frpq4pXwyN+2JQMod4pKz5BALwyneCgDg89Q==", + "dependencies": { + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.0.tgz", + "integrity": "sha512-sqKVVVOe5ivCaXDWivIJYVSaEgdQK9ul7a4Kity5Iw7u9+wBAPbX1RMSnLLmp7O4Vzj0WOWwMAJsTL00xwaNug==" + }, + "node_modules/@hapi/topo": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.0.0.tgz", + "integrity": "sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -1291,6 +1314,24 @@ "node": ">=8" } }, + "node_modules/@sideway/address": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.2.tgz", + "integrity": "sha512-idTz8ibqWFrPU8kMirL0CoPH/A29XOzzAzpyN3zQ4kAWnzmNfFmRaoMNN6VI8ske5M73HZyhIaW4OuSFIdM4oA==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", + "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, "node_modules/@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -6244,6 +6285,18 @@ "node": ">=8" } }, + "node_modules/joi": { + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.4.0.tgz", + "integrity": "sha512-F4WiW2xaV6wc1jxete70Rw4V/VuMd6IN+a5ilZsxG4uYtUXWu2kq9W5P2dz30e7Gmw8RCbY/u/uk+dMPma9tAg==", + "dependencies": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.0", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.0.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -10186,6 +10239,27 @@ "minimist": "^1.2.0" } }, + "@hapi/boom": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.2.tgz", + "integrity": "sha512-uJEJtiNHzKw80JpngDGBCGAmWjBtzxDCz17A9NO2zCi8LLBlb5Frpq4pXwyN+2JQMod4pKz5BALwyneCgDg89Q==", + "requires": { + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/hoek": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.0.tgz", + "integrity": "sha512-sqKVVVOe5ivCaXDWivIJYVSaEgdQK9ul7a4Kity5Iw7u9+wBAPbX1RMSnLLmp7O4Vzj0WOWwMAJsTL00xwaNug==" + }, + "@hapi/topo": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.0.0.tgz", + "integrity": "sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==", + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -10793,6 +10867,24 @@ } } }, + "@sideway/address": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.2.tgz", + "integrity": "sha512-idTz8ibqWFrPU8kMirL0CoPH/A29XOzzAzpyN3zQ4kAWnzmNfFmRaoMNN6VI8ske5M73HZyhIaW4OuSFIdM4oA==", + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@sideway/formula": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", + "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" + }, + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, "@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -14644,6 +14736,18 @@ } } }, + "joi": { + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.4.0.tgz", + "integrity": "sha512-F4WiW2xaV6wc1jxete70Rw4V/VuMd6IN+a5ilZsxG4uYtUXWu2kq9W5P2dz30e7Gmw8RCbY/u/uk+dMPma9tAg==", + "requires": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.0", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.0.0" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", diff --git a/package.json b/package.json index b730cb49..ca583d70 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,11 @@ "description": "Reto 9 Octubre 26: Curso de Backend con Node", "main": "index.js", "dependencies": { + "@hapi/boom": "^9.1.2", "cors": "^2.8.5", "dotenv": "^8.2.0", "express": "^4.17.1", + "joi": "^17.4.0", "mongodb": "^3.6.6" }, "devDependencies": { diff --git a/src/Entities/Category/index.js b/src/Entities/Category/index.js deleted file mode 100644 index 5f6f4663..00000000 --- a/src/Entities/Category/index.js +++ /dev/null @@ -1,17 +0,0 @@ -const controller = require("./category.controller"); - -const router = require("express").Router(); - -//get categories -router.get("/", controller.getAll); -//get category by id -router.get("/:id", controller.getById); -//create category -router.post("/", controller.createCategory); -//update category -router.put("/:id", controller.updateCategory); -//delete category -router.delete("/:id", controller.deleteCategory); -//products byCategory -router.get("/:id/products", controller.productsByCategory); -module.exports = router; diff --git a/src/Entities/Product/index.js b/src/Entities/Product/index.js deleted file mode 100644 index 3a129df8..00000000 --- a/src/Entities/Product/index.js +++ /dev/null @@ -1,14 +0,0 @@ -const router = require("express").Router(); -const controller = require("./product.controller"); - -//get products -router.get("/", controller.getAll); -//get product by id -router.get("/:id", controller.getById); -//create Product -router.post("/", controller.createProduct); -//update Product -router.put("/:id", controller.updateProduct); -//delete Product -router.delete("/:id", controller.deleteProduct); -module.exports = router; diff --git a/src/app.js b/src/app.js index 09371590..2f0d4847 100644 --- a/src/app.js +++ b/src/app.js @@ -1,13 +1,15 @@ const express = require("express"); const cors = require("cors"); const apiRouter = require("./routes"); - +const notFoundHandler = require("./middlewares/notFoundHandler"); function createApp() { const app = express(); app.use(cors()); app.use(express.json()); app.use("/api", apiRouter); + //catch 404 + app.use(notFoundHandler); return app; } diff --git a/src/Entities/Category/category.controller.js b/src/controllers/category.controller.js similarity index 66% rename from src/Entities/Category/category.controller.js rename to src/controllers/category.controller.js index 9d8e7e56..b67c9829 100644 --- a/src/Entities/Category/category.controller.js +++ b/src/controllers/category.controller.js @@ -1,13 +1,10 @@ const controller = {}; -const CategoryService = require("./category.service"); +const CategoryService = require("./../services/category.service"); const categoryService = new CategoryService(); controller.getAll = async (req, res) => { try { const categories = await categoryService.getAll(); - return res.status(200).json({ - data: categories, - message: "Categories Listed", - }); + return res.status(200).json(categories); } catch (error) { console.log(error); } @@ -15,11 +12,8 @@ controller.getAll = async (req, res) => { controller.getById = async (req, res) => { const { id } = req.params; try { - const category = await categoryService.getById({ id }); - return res.status(200).json({ - data: category, - message: "category reatrived", - }); + const category = await categoryService.getById(id); + return res.status(200).json(category); } catch (error) { console.log(error); } @@ -41,10 +35,7 @@ controller.updateCategory = async (req, res) => { id, category, }); - return res.status(200).json({ - data: updateCategoryId, - message: "category updated", - }); + return res.status(200).json(updateCategoryId); } catch (error) { console.log(error); } @@ -53,10 +44,7 @@ controller.deleteCategory = async (req, res) => { const { id } = req.params; try { const deleteCategoryId = await categoryService.deleteCategory({ id }); - return res.status(200).json({ - data: deleteCategoryId, - message: "Category deleted", - }); + return res.status(200).json(true); } catch (error) { console.log(error); } @@ -64,13 +52,8 @@ controller.deleteCategory = async (req, res) => { controller.productsByCategory = async (req, res) => { const { id } = req.params; try { - const productsByCategory = await categoryService.getProductsByCategory({ - id, - }); - return res.status(200).json({ - data: productsByCategory, - message: "Products by category Listed", - }); + const productsByCategory = await categoryService.getProductsByCategory(id); + return res.status(200).json(productsByCategory); } catch (error) { console.log(error); } diff --git a/src/Entities/Product/product.controller.js b/src/controllers/product.controller.js similarity index 62% rename from src/Entities/Product/product.controller.js rename to src/controllers/product.controller.js index 36ef9852..65d59ce5 100644 --- a/src/Entities/Product/product.controller.js +++ b/src/controllers/product.controller.js @@ -1,14 +1,10 @@ -const ProductService = require("./product.service"); +const ProductService = require("./../services/product.service"); const controller = {}; const productsService = new ProductService(); controller.getAll = async (req, res) => { - const { tags } = req.query; try { - const products = await productsService.getAll({ tags }); - return res.status(200).json({ - data: products, - message: "Products Listed", - }); + const products = await productsService.getAll(); + return res.status(200).json(products); } catch (error) { console.error(error); } @@ -17,10 +13,7 @@ controller.getById = async (req, res) => { const { id } = req.params; try { const product = await productsService.getById({ id }); - return res.status(200).json({ - data: product, - message: "Product reatrived", - }); + return res.status(200).json(product); } catch (error) { console.log(error); } @@ -29,10 +22,7 @@ controller.createProduct = async (req, res) => { const { body: product } = req; try { const createProduct = await productsService.createProduct({ product }); - return res.status(201).json({ - data: createProduct, - message: "Product Created", - }); + return res.status(201).json(createProduct); } catch (error) { console.log(error); } @@ -45,10 +35,7 @@ controller.updateProduct = async (req, res) => { id, product, }); - return res.status(200).json({ - data: updateProductId, - message: "product updated", - }); + return res.status(200).json(updateProductId); } catch (error) { console.log(error); } @@ -57,10 +44,7 @@ controller.deleteProduct = async (req, res) => { const { id } = req.params; try { const deleteProductId = await productsService.deleteProduct({ id }); - return res.status(200).json({ - data: deleteProductId, - message: "Product deleted", - }); + return res.status(200).json(true); } catch (error) { console.log(error); } diff --git a/src/lib/mongo.js b/src/lib/mongo.js index b760987f..31ac8ec8 100644 --- a/src/lib/mongo.js +++ b/src/lib/mongo.js @@ -29,9 +29,10 @@ class MongoLib { } return MongoLib.connection; } - getAll(collection) { + getAll(collection, query) { + return this.connect().then((db) => { - return db.collection(collection).find().toArray(); + return db.collection(collection).find(query).toArray(); }); } @@ -48,13 +49,14 @@ class MongoLib { .then(() => data); } update(collection, data, id) { - return this.connect() - .then((db) => { - return db - .collection(collection) - .updateOne({ _id: ObjectId(id) }, { $set: data }, { upsert: true }); - }) - .then((result) => result.upsertedId || id); + return this.connect().then((db) => { + db.collection(collection).updateOne( + { _id: ObjectId(id) }, + { $set: data }, + { upsert: true } + ); + return db.collection(collection).findOne({ _id: ObjectId(id) }); + }); } delete(collection, id) { return this.connect() diff --git a/src/middlewares/notFoundHandler.js b/src/middlewares/notFoundHandler.js new file mode 100644 index 00000000..227196fa --- /dev/null +++ b/src/middlewares/notFoundHandler.js @@ -0,0 +1,8 @@ +const boom = require("@hapi/boom"); +function notFoundHandler(req, res) { + const { + output: { statusCode, payload }, + } = boom.notFound(); + res.status(statusCode).json(payload); +} +module.exports = notFoundHandler; diff --git a/src/middlewares/validationHandler.js b/src/middlewares/validationHandler.js new file mode 100644 index 00000000..ee452f65 --- /dev/null +++ b/src/middlewares/validationHandler.js @@ -0,0 +1,20 @@ +const boom = require("@hapi/boom"); +const joi = require("joi"); +/*function validate(data, schema) { + const {error} = joi.valid + return false; +}*/ +function validate(data, schema) { + // If schema is not a joi schema convert to a joi schema object otherwise return schema + schema = !joi.isSchema(schema) ? joi.object(schema) : schema; + const { error } = schema.validate(data); + return error; +} + +function validationHandler(schema, data = "body") { + return function (req, res, next) { + const error = validate(req[data], schema); + error ? next(boom.badRequest(error)) : next(); + }; +} +module.exports = validationHandler; diff --git a/src/routes/category.routes.js b/src/routes/category.routes.js new file mode 100644 index 00000000..972f4717 --- /dev/null +++ b/src/routes/category.routes.js @@ -0,0 +1,39 @@ +const controller = require("../controllers/category.controller"); +const router = require("express").Router(); +const { + categoryIdSchema, + createCategorySchema, + updateCategorySchema, +} = require("../schemas/category.schema"); + +const validationHandler = require("../middlewares/validationHandler"); +//get categories +router.get("/", controller.getAll); +//get category by id +router.get( + "/:id", + validationHandler({ id: categoryIdSchema }, "params"), + controller.getById +); +//create category +router.post( + "/", + validationHandler(createCategorySchema), + controller.createCategory +); +//update category +router.put( + "/:id", + validationHandler({ id: categoryIdSchema }, "params"), + validationHandler(updateCategorySchema), + controller.updateCategory +); +//delete category +router.delete( + "/:id", + validationHandler({ id: categoryIdSchema }, "params"), + controller.deleteCategory +); +//products byCategory +router.get("/:id/products", controller.productsByCategory); +module.exports = router; diff --git a/src/routes/index.js b/src/routes/index.js index 1a2c2f8c..8af6fdbf 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -1,6 +1,6 @@ const router = require("express").Router(); -const apiProductRouter = require("../Entities/Product/index"); -const apiCategoriesRouter = require("../Entities/Category/index"); +const apiProductRouter = require("./product.routes"); +const apiCategoriesRouter = require("./category.routes"); router.use("/products", apiProductRouter); router.use("/categories", apiCategoriesRouter); module.exports = router; diff --git a/src/routes/product.routes.js b/src/routes/product.routes.js new file mode 100644 index 00000000..5edd9665 --- /dev/null +++ b/src/routes/product.routes.js @@ -0,0 +1,36 @@ +const router = require("express").Router(); +const controller = require("../controllers/product.controller"); +const { + productIdSchema, + createProductSchema, + updateProductSchema, +} = require("../schemas/product.schema"); +const validationHandler = require("../middlewares/validationHandler"); +//get products +router.get("/", controller.getAll); +//get product by id +router.get( + "/:id", + validationHandler({ id: productIdSchema }, "params"), + controller.getById +); +//create Product +router.post( + "/", + validationHandler(createProductSchema), + controller.createProduct +); +//update Product +router.put( + "/:id", + validationHandler({ id: productIdSchema }, "params"), + validationHandler(updateProductSchema), + controller.updateProduct +); +//delete Product +router.delete( + "/:id", + validationHandler({ id: productIdSchema }, "params"), + controller.deleteProduct +); +module.exports = router; diff --git a/src/schemas/category.schema.js b/src/schemas/category.schema.js new file mode 100644 index 00000000..eb3bd960 --- /dev/null +++ b/src/schemas/category.schema.js @@ -0,0 +1,18 @@ +const joi = require("joi"); +const categoryIdSchema = joi.string().regex(/^[0-9a-fA-F]{24}$/); +const categoryNameSchema = joi.string().max(80); +const categoryImage = joi.string().max(300); + +const createCategorySchema = { + name: categoryNameSchema.required(), + image: categoryImage, +}; +const updateCategorySchema = { + name: categoryNameSchema, + image: categoryImage, +}; +module.exports = { + categoryIdSchema, + createCategorySchema, + updateCategorySchema, +}; diff --git a/src/schemas/product.schema.js b/src/schemas/product.schema.js new file mode 100644 index 00000000..2c7e0b8a --- /dev/null +++ b/src/schemas/product.schema.js @@ -0,0 +1,27 @@ +const joi = require("joi"); +const productIdSchema = joi.string().regex(/^[0-9a-fA-F]{24}$/); +const productNameSchema = joi.string().max(80); +const productPriceSchema = joi.number().min(1).max(100000); +const productDescription = joi.string().max(80); +const productCategoryId = joi.string().regex(/^[0-9a-fA-F]{24}$/); +const productImage = joi.string().max(300); + +const createProductSchema = { + name: productNameSchema.required(), + price: productPriceSchema, + description: productDescription, + categoryId: productCategoryId, + image: productImage, +}; +const updateProductSchema = { + name: productNameSchema, + price: productPriceSchema, + description: productDescription, + categoryId: productCategoryId, + image: productImage, +}; +module.exports = { + productIdSchema, + createProductSchema, + updateProductSchema, +}; diff --git a/src/Entities/Category/category.service.js b/src/services/category.service.js similarity index 75% rename from src/Entities/Category/category.service.js rename to src/services/category.service.js index 6830c2d9..930eeb13 100644 --- a/src/Entities/Category/category.service.js +++ b/src/services/category.service.js @@ -1,14 +1,15 @@ -const MongoLib = require("../../lib/mongo"); +const MongoLib = require("../lib/mongo"); class CategoryService { constructor() { this.collection = "categories"; this.mongoDB = new MongoLib(); } - async getAll() { - const categories = await this.mongoDB.getAll(this.collection); + async getAll(query) { + query = query || {}; + const categories = await this.mongoDB.getAll(this.collection, query); return categories || []; } - async getById({ id }) { + async getById(id) { const category = await this.mongoDB.get(this.collection, id); return category || {}; } @@ -20,10 +21,10 @@ class CategoryService { return createCategoryId; } async updateCategory({ id, category }) { - const updatedCategoryId = await this.mongoDB.update( + const update = await this.mongoDB.update(this.collection, category, id); + const updatedCategoryId = await this.mongoDB.get( this.collection, - category, - id + update._id ); return updatedCategoryId; } @@ -31,7 +32,7 @@ class CategoryService { const deleteCategoryId = await this.mongoDB.delete(this.collection, id); return deleteCategoryId; } - async getProductsByCategory({ id }) { + async getProductsByCategory(id) { const query = { categoryId: id }; const productsByCategory = await this.mongoDB.getAll("products", query); return productsByCategory || []; diff --git a/src/Entities/Product/product.service.js b/src/services/product.service.js similarity index 76% rename from src/Entities/Product/product.service.js rename to src/services/product.service.js index cb4747df..4de51997 100644 --- a/src/Entities/Product/product.service.js +++ b/src/services/product.service.js @@ -1,12 +1,12 @@ -const MongoLib = require("../../lib/mongo"); +const MongoLib = require("../lib/mongo"); class ProductService { constructor() { this.collection = "products"; this.mongoDB = new MongoLib(); } - async getAll({ tags }) { - const query = tags && { tags: { $in: tags } }; + async getAll(query) { + query = query || {}; const products = await this.mongoDB.getAll(this.collection, query); return products || []; } @@ -19,10 +19,10 @@ class ProductService { return createProductId; } async updateProduct({ id, product }) { - const updatedProductId = await this.mongoDB.update( + const update = await this.mongoDB.update(this.collection, product, id); + const updatedProductId = await this.mongoDB.get( this.collection, - product, - id + update._id ); return updatedProductId; } From b3a5545e26058e2d2bb9606814a3722b740ab521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cort=C3=A9s?= Date: Tue, 18 May 2021 00:42:41 -0400 Subject: [PATCH 10/15] add db port in uri --- src/lib/mongo.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/mongo.js b/src/lib/mongo.js index 31ac8ec8..290c3b7c 100644 --- a/src/lib/mongo.js +++ b/src/lib/mongo.js @@ -5,7 +5,7 @@ const USER = encodeURIComponent(config.dbUser); const PASSWORD = encodeURIComponent(config.dbPassword); const DB_NAME = config.dbName; -const MONGO_URI = `${config.dbConnection}://${USER}:${PASSWORD}@${config.dbHost}/${config.dbName}?retryWrites=true&w=majority`; +const MONGO_URI = `${config.dbConnection}://${USER}:${PASSWORD}@${config.dbHost}:${config.dbPort}/${config.dbName}?retryWrites=true&w=majority`; class MongoLib { constructor() { @@ -30,7 +30,6 @@ class MongoLib { return MongoLib.connection; } getAll(collection, query) { - return this.connect().then((db) => { return db.collection(collection).find(query).toArray(); }); From 590f6297721a4248f6f3368b10c5523fab868f2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cort=C3=A9s?= Date: Tue, 18 May 2021 00:56:26 -0400 Subject: [PATCH 11/15] change port in mongo uri --- src/lib/mongo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/mongo.js b/src/lib/mongo.js index 290c3b7c..10357d8e 100644 --- a/src/lib/mongo.js +++ b/src/lib/mongo.js @@ -5,7 +5,7 @@ const USER = encodeURIComponent(config.dbUser); const PASSWORD = encodeURIComponent(config.dbPassword); const DB_NAME = config.dbName; -const MONGO_URI = `${config.dbConnection}://${USER}:${PASSWORD}@${config.dbHost}:${config.dbPort}/${config.dbName}?retryWrites=true&w=majority`; +const MONGO_URI = `${config.dbConnection}://${USER}:${PASSWORD}@${config.dbHost}/${config.dbName}?retryWrites=true&w=majority`; class MongoLib { constructor() { From 723d7ffee35a026f84dec43833c73a7b49b6175f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cort=C3=A9s?= Date: Tue, 18 May 2021 01:22:29 -0400 Subject: [PATCH 12/15] ... --- src/lib/mongo.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/mongo.js b/src/lib/mongo.js index 10357d8e..2b12005c 100644 --- a/src/lib/mongo.js +++ b/src/lib/mongo.js @@ -20,6 +20,7 @@ class MongoLib { MongoLib.connection = new Promise((resolve, reject) => { this.client.connect((err) => { if (err) { + console.log({ err }); reject(err); } console.log("Connected Succesfully"); From e3ecde5682df208fa713e14ebf567e61811df7b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cort=C3=A9s?= Date: Tue, 18 May 2021 01:24:56 -0400 Subject: [PATCH 13/15] ... --- src/lib/mongo.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/mongo.js b/src/lib/mongo.js index 2b12005c..f1ff7087 100644 --- a/src/lib/mongo.js +++ b/src/lib/mongo.js @@ -16,6 +16,7 @@ class MongoLib { this.dbName = DB_NAME; } connect() { + console.log({ MONGO_URI }); if (!MongoLib.connection) { MongoLib.connection = new Promise((resolve, reject) => { this.client.connect((err) => { From bc06e9ff1eb06bd4a410e5eb95561ae4d7874ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cort=C3=A9s?= Date: Tue, 18 May 2021 01:28:23 -0400 Subject: [PATCH 14/15] ... --- src/lib/mongo.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/mongo.js b/src/lib/mongo.js index f1ff7087..2b12005c 100644 --- a/src/lib/mongo.js +++ b/src/lib/mongo.js @@ -16,7 +16,6 @@ class MongoLib { this.dbName = DB_NAME; } connect() { - console.log({ MONGO_URI }); if (!MongoLib.connection) { MongoLib.connection = new Promise((resolve, reject) => { this.client.connect((err) => { From 665907ebf031ef30c3435767846dda22bbd4948c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cort=C3=A9s?= Date: Tue, 18 May 2021 01:29:43 -0400 Subject: [PATCH 15/15] add url produccion in readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f1ebbc43..86e74fe5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Prueba de Backend NodeJS Crear un CRUD para crear productos conectado a MongoDB. +# URL PRODUCCION +https://backend-node-evaluation-2021.herokuapp.com/ ### Instalación ``` npm install