{
"message": "Welcome to bs20-back API application."
}
- Descripción y contexto
- Guía de usuario
- Peticiones a la API
- Guía de instalación
- Información adicional
💻📱 Bsale Test - Backend 💻📱 es una API que atiende las peticiones de datos que provienen desde el lado del cliente (Frontend) 💻💻💻
La API realiza consultas a las tablas "product" y "category" de la Base de Datos y envia las respuestas al cliente, respecto a la busqueda de productos diversos a adquirir.
Puedes acceder a la API a traves de: https://bs20-back.vercel.app/
Al iniciar la plataforma web de 🛍 🛒 Bsale Test - Frontend 🛍 🛒; desde el lado del cliente se realizarán 02 peticiones
a la API del backend
para solicitar los datos de los productos
y los datos de las categorias
La API establece una conexion hacia la Base de Datos suministrada por la empresa
Nota:
Los productos
estan alojados en la tabla product
de la base de datos suministrados por la empresa
🔭Tabla |
⚡"product" |
---|---|
id | Identificador unicod del producto (int) |
name | Nombre del producto (varchar) |
url_image | URL de la imagen asociada al producto (varchar) |
price | Precio de venta del producto (float) |
discount | Porcentaje de descuento del producto (int) |
category | Identificador de la categoria (int) |
Nota:
Las categorias
estan alojadas en la tabla category
de la base de datos suministrados por la empresa
🔭Tabla |
⚡"category" |
---|---|
id | Identificador unicod del producto (int) |
name | Nombre del producto (varchar) |
Nota:
La ruta del API del backend
es: https://bs20-back.vercel.app/
Nota:
Las peticiones
son de tipo GET
// routes/product.routes.js
module.exports = app => {
const products = require("../controllers/product.controller.js");
var router = require("express").Router();
// Create a new Product
//router.post("/", products.create);
// Retrieve all Products
router.get("/", products.findAll);
//Retrieve a single Product with id
router.get("/:id", products.findOne);
// Retrieve a single Product with category
router.get("/cat/:cat", products.findOneCat);
// Retrieve a single Product with search bar
router.get("/search/:text", products.findSearch);
app.use('/api/products', router);
};
Nota:
Esta peticion GET accede a la tabla product
de la Base de Datos
Nota:
URL = https://bs20-back.vercel.app/
- Si la ruta de peticion es:
"URL/api/products"
, podrá visualizar todos losproductos
- Si la ruta de peticion es:
"URL/api/products/2"
, podrá visualizar el producto con el campoid
igual a2
- Si la ruta de peticion es:
"URL/api/products/cat/4"
podrá visualizar los productos con el campocategory
igual a4
- Si la ruta de peticion es:
"URL/api/products/search/ener"
podrá visualizar los productos con el camponame
que contiene en su contenido la palabraener
// routes/category.routes.js
module.exports = app => {
const categories = require("../controllers/category.controller.js");
var router = require("express").Router();
// Create a new Category
//router.post("/", categories.create);
// Retrieve all Categories
router.get("/", categories.findAll);
// Retrieve a single Category with id
router.get("/:id", categories.findOne);
app.use('/api/categories', router);
};
Nota:
Esta peticion GET accede a la tabla category
de la Base de Datos
Nota:
URL = https://bs20-back.vercel.app/
- Si la ruta de peticion es:
"URL/api/categories"
, podrá visualizar todas lascategorias
- Si la ruta de peticion es:
"URL/api/categories/2"
, podrá visualizar la categoria con el campoid
igual a2
Nota:
Retorna todos los productos
- GET /api/products desde el cliente (Frontend)
- Por medio de
AXIOS
se envia la solicitud GET, desde el cliente (Frontend) - URL de peticion: https://bs20-back.vercel.app/api/products
- La API recibe la
peticion
tipoGET
y la procesa
// routes/product.routes.js
...
// Retrieve all Products
router.get("/", products.findAll);
...
app.use('/api/products', router);
};
- La URL de peticion desde el cliente es: https://bs20-back.vercel.app/api/products
- Esto enruta hacia
findAll
encontrollers/product.controller.js
findAll
direcciona agetAll
// controllers/product.controller.js
// Retrieve all Products from the database (with condition).
exports.findAll = (req, res) => {
const title = req.query.title;
Product.getAll(title, (err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Error de conexion. Intente de nuevo"
});
else res.send(data);
});
};
- La API realiza la
consulta
depeticion
a la Base de Datos - Se ordena de modo que el campo
price
sea de forma ASCENDENTE - Este pedido se encuentra en
models/product.model.js
// models/product.model.js
...
Product.getAll = (title, result) => {
let query = "SELECT * FROM product ORDER BY price ASC";
if (title) {
query += ` WHERE title LIKE '%${title}%'`;
}
sql.query(query, (err, res) => {
if (err) {
console.log("error: ", err);
result(null, err);
return;
}
console.log("products: ", res);
result(null, res);
});
};
module.exports = Product;
- La API obtiene como
respuesta
todos losproductos
si es que, la solicitud fue exitosa - Caso contrario, se obtendra el
error 500
el cual, es error de conexion en el servidor - De momento, se obtiene un total de 57 productos
- La API envia la
respuesta
al cliente (Frontend)
[
{
"id": 53,
"name": "Mani Sin Sal",
"url_image": "https://dojiw2m9tvv09.cloudfront.net/11132/product/manisinsalmp6988.jpg",
"price": 500,
"discount": 0,
"category": 5
},
{
"id": 55,
"name": "Papas Fritas Bolsa Pequeña",
"url_image": "https://dojiw2m9tvv09.cloudfront.net/11132/product/papaslisas7271.jpg",
"price": 500,
"discount": 0,
"category": 5
},
...
{
"id": 33,
"name": "RON PAMPERO ANIVERSARIO",
"url_image": "https://dojiw2m9tvv09.cloudfront.net/11132/product/ron_pampero_aniversario0311.jpg",
"price": 20000,
"discount": 15,
"category": 3
}
]
- Finalmente, los
productos
son renderizados en el frontend
Nota:
Retorna todas las categorias
- GET /api/categories desde el cliente (Frontend)
- Por medio de
AXIOS
se envia la solicitud GET, desde el cliente (Frontend) - URL de peticion: https://bs20-back.vercel.app/api/categories
- La API recibe la
peticion
tipoGET
y la procesa
// routes/category.routes.js
...
// Retrieve all Categories
router.get("/", categories.findAll);
...
app.use('/api/categories', router);
};
- La URL de peticion desde el cliente es: https://bs20-back.vercel.app/api/categories
- Esto enruta hacia
findAll
encontrollers/category.controller.js
findAll
direcciona agetAll
// controllers/category.controller.js
...
// Retrieve all Categories from the database (with condition).
exports.findAll = (req, res) => {
const title = req.query.title;
Category.getAll(title, (err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Some error occurred while retrieving Categories."
});
else res.send(data);
});
};
...
- La API realiza la
consulta
depeticion
a la Base de Datos - Se ordena de modo que el campo
price
sea de forma ASCENDENTE - Este pedido se encuentra en
models/category.model.js
// models/category.model.js
...
Category.getAll = (title, result) => {
let query = "SELECT * FROM category";
if (title) {
query += ` WHERE title LIKE '%${title}%'`;
}
sql.query(query, (err, res) => {
if (err) {
console.log("error: ", err);
result(null, err);
return;
}
console.log("categories: ", res);
result(null, res);
});
};
module.exports = Category;
- La API obtiene como
respuesta
todas loscategorias
si es que, la solicitud fue exitosa - Caso contrario, se obtendra el
error 500
el cual, es error de conexion en el servidor - De momento, se obtiene un total de 7 categorias
- La API envia la
respuesta
al cliente (Frontend)
[
{
"id": 1,
"name": "bebida energetica"
},
{
"id": 2,
"name": "pisco"
},
...
{
"id": 7,
"name": "vodka"
}
]
- Finalmente, las
categorias
son renderizadas en elSidebar
y en elSelect-option
del Navbar
Nota:
Cada producto
tiene un campo de category
con un numero asignado entre 1 y 7.
Nota:
Estos numeros estan relacionados con cada categoria
obtenida.
Nota:
Esto servirá para realizar el filtrado de los productos
y ordenarlos por categorias
Ahora veamos acerca del filtrado de productos
por medio de las categorias
Al dar click sobre una de las categorias
ya sea del SIDEBAR
o del SELECT-OPTION
, se enviará 01 peticion
a la API del backend
para solicitar los datos de los productos
filtrados por la categoria
seleccionada
Nota:
Retornara los productos
filtrados por la categoria
seleccionada
- GET /api/products/cat/:cat
- Por medio de
AXIOS
se envia la solicitud GET, desde el cliente (Frontend) - URL de peticion:
https://bs20-back.vercel.app/api/products/cat/:cat
- La API recibe la peticion GET y la procesa
Nota:
En la URL https://bs20-back.vercel.app/api/products/cat/:cat
el valor de :cat
debe ser reemplazado por el id
de la categoria
seleccionada
Nota:
Por ejemplo, si selecciono pisco
su id
es 2
Entonces la URL será https://bs20-back.vercel.app/api/products/cat/2
Nota:
Se obtendran los productos
que tengan el campo category: 2
// routes/product.routes.js
...
// Retrieve a single Product with category
router.get("/cat/:cat", products.findOneCat);
...
app.use('/api/products', router);
};
- La URL de peticion desde el cliente es:
https://bs20-back.vercel.app/api/products/cat/:cat
- Esto enruta hacia
findOneCat
encontrollers/product.controller.js
findOneCat
direcciona afindByCat
// controllers/product.controller.js
...
// Find a single Product by Category
exports.findOneCat = (req, res) => {
Product.findByCat(req.params.cat, (err, data) => {
if (err) {
if (err.kind === "not_found") {
res.status(404).send({
message: `No hay coincidencias para: "${req.params.cat}".`
});
} else {
res.status(500).send({
/* message: "Error retrieving Product with CAT " + req.params.cat */
message: "Error de conexion. Intente de nuevo"
});
}
} else res.send(data);
});
};
...
- La API realiza la consulta de peticion a la Base de Datos
- Se ordena de modo que el campo
price
sea de forma ASCENDENTE - Este pedido se encuentra en
models/product.model.js
// models/product.controller.js
...
Product.findByCat = (cat, result) => {
sql.query(`SELECT * FROM product WHERE category = ${cat} ORDER BY price ASC`, (err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
if (res.length) {
console.log("found product: ", res);
result(null, res);
return;
}
// not found Product with the id
result({ kind: "not_found" }, null);
});
};
...
- La API obtiene como respuesta los
productos
filtrados por lacategoria
seleccionada; si es que, la solicitud fue exitosa - Caso contrario, se obtendra el
error 500
; el cual, es error de conexion en el servidor - La API envia la respuesta al cliente (Frontend)
Nota:
- Si se hubiese seleccionado
pisco
elid
de lacategoria
seria2
- Para este caso particular, la respuesta de la API sería la siguiente:
[
{
"id": 12,
"name": "PISCO CAMPANARIO 35º",
"url_image": "https://dojiw2m9tvv09.cloudfront.net/11132/product/campanario8845.jpg",
"price": 2990,
"discount": 20,
"category": 2
},
{
"id": 10,
"name": "PISCO ARTESANOS 35º ",
"url_image": "https://dojiw2m9tvv09.cloudfront.net/11132/product/artesanos8818.jpg",
"price": 3990,
"discount": 0,
"category": 2
},
...
{
"id": 91,
"name": "PISCO MISTRAL NOBEL 40°",
"url_image": "https://dojiw2m9tvv09.cloudfront.net/11132/product/nobel409551.jpg",
"price": 19990,
"discount": 0,
"category": 2
}
]
Nota:
- Si se hubiese seleccionado
snack
el "id" de lacategoria
seria5
- Para este caso particular, la respuesta de la API sería la siguiente:
[
{
"id": 53,
"name": "Mani Sin Sal",
"url_image": "https://dojiw2m9tvv09.cloudfront.net/11132/product/manisinsalmp6988.jpg",
"price": 500,
"discount": 0,
"category": 5
},
{
"id": 55,
"name": "Papas Fritas Bolsa Pequeña",
"url_image": "https://dojiw2m9tvv09.cloudfront.net/11132/product/papaslisas7271.jpg",
"price": 500,
"discount": 0,
"category": 5
},
...
{
"id": 56,
"name": "Papas Fritas Tarro",
"url_image": "https://dojiw2m9tvv09.cloudfront.net/11132/product/78028005335657432.jpg",
"price": 1990,
"discount": 0,
"category": 5
}
]
- Finalmente, los
productos
filtrados por lacategoria
seleccionada, son renderizados en el frontend
Ahora veamos acerca del filtrado de productos
por medio de los nombres
de producto desde el buscador
o search bar
del Navbar
Al ingresar un nombre
en el buscador
o search bar
del Navbar y dar click sobre el boton search
o presionar Enter
, se enviará 01 peticion
a la API del backend
para solicitar los datos de los productos
filtrados por el nombre
ingresado
Nota:
Retornara los productos
filtrados por nombre
ingresado
- GET /api/products/search/:text
- Por medio de
AXIOS
se envia la solicitud GET, desde el cliente (Frontend) - URL de peticion:
https://bs20-back.vercel.app/api/products/search/:text
Nota:
En la URL https://bs20-back.vercel.app/api/products/search/:text
el valor de :text
debe ser reemplazado por el nombre
ingresado en el buscador
o search bar
del Navbar
Nota:
Por ejemplo, si selecciono ener
entonces :text
es reemplazado por ener
. Entonces la URL será https://bs20-back.vercel.app/api/products/search/ener
Nota:
Se obtendran los productos
que contengan la palabra ener
en el campo name
de cada producto
// routes/product.routes.js
...
// Retrieve a single Product with search bar
router.get("/search/:text", products.findSearch);
app.use('/api/products', router);
};
- La URL de peticion desde el cliente es:
https://bs20-back.vercel.app/api/products/search/:text
- Esto enruta hacia
findSearch
encontrollers/product.controller.js
findSearch
direcciona afindBySearch
// controllers/product.controller.js
// Find a single Product by Search bar
exports.findSearch = (req, res) => {
Product.findBySearch(req.params.text, (err, data) => {
if (err) {
if (err.kind === "not_found") {
res.status(404).send({
message: `No hay coincidencias para: "${req.params.text}".`
});
/* res.send(data); */
} else {
res.status(500).send({
/* message: "Error retrieving Product with TEXT " + req.params.text */
message: "Error de conexion. Intente de nuevo"
});
}
} else res.send(data);
});
};
- La API realiza la consulta de peticion a la Base de Datos
- Se ordena de modo que el campo
price
sea de forma ASCENDENTE - Este pedido se encuentra en
models/product.model.js
// models/product.model.js
Product.findBySearch = (text, result) => {
sql.query(`SELECT * FROM product WHERE name LIKE '%${text}%' ORDER BY price ASC`, (err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
if (res.length) {
console.log("found product: ", res);
result(null, res);
return;
}
// not found Product with the TEXT
result({ kind: "not_found" }, null);
});
};
- La API obtiene como respuesta los
productos
filtrados por lacategoria
seleccionada; si es que, la solicitud fue exitosa - Caso contrario, se obtendra el
error 500
; el cual, es error de conexion en el servidor - La API envia la respuesta al cliente (Frontend)
Nota:
- Si se hubiese ingreso en el
buscador
el nombreener
se hubiera buscado en el camponame
los productos que contengan la palabraener
- Para este caso particular, la respuesta de la API sería la siguiente:
[
{
"id": 35,
"name": "ENERGETICA MAKKA DRINKS",
"url_image": "https://dojiw2m9tvv09.cloudfront.net/11132/product/makka-drinks-250ml0455.jpg",
"price": 1190,
"discount": 0,
"category": 1
},
{
"id": 7,
"name": "ENERGETICA SCORE",
"url_image": "https://dojiw2m9tvv09.cloudfront.net/11132/product/logo7698.png",
"price": 1290,
"discount": 0,
"category": 1
},
...
{
"id": 79,
"name": "ENERGETICA MONSTER VERDE",
"url_image": "",
"price": 1990,
"discount": 0,
"category": 1
}
]
- Finalmente, los
productos
filtrados por el nombreener
ingresado, son renderizados en el frontend
1er Error:
Se da cuando el nombre ingresado por medio del buscador
o search bar
del Navbar, no coincide con algun nombre de un producto de la Base de datos
- GET /api/products/search/:text
- Por medio de
AXIOS
se envia la solicitud GET, desde el cliente (Frontend) - URL de peticion:
https://bs20-back.vercel.app/api/products/search/:text
Nota:
En la URL https://bs20-back.vercel.app/api/products/search/:text
el valor de :text
debe ser reemplazado por el nombre
ingresado en el buscador
o search bar
del Navbar
Nota:
Por ejemplo, si selecciono asdasd
, entonces :text
es reemplazado por asdasd
. Entonces la URL será https://bs20-back.vercel.app/api/products/search/asdasd
Nota:
Se obtendran los productos
que contengan la palabra asdasd
en el campo name
de cada producto
// routes/product.routes.js
...
// Retrieve a single Product with search bar
router.get("/search/:text", products.findSearch);
app.use('/api/products', router);
};
- La URL de peticion desde el cliente es:
https://bs20-back.vercel.app/api/products/search/:text
- Esto enruta hacia
findSearch
encontrollers/product.controller.js
findSearch
direcciona afindBySearch
// controllers/product.controller.js
// Find a single Product by Search bar
exports.findSearch = (req, res) => {
Product.findBySearch(req.params.text, (err, data) => {
if (err) {
if (err.kind === "not_found") {
res.status(404).send({
message: `No hay coincidencias para: "${req.params.text}".`
});
/* res.send(data); */
} else {
res.status(500).send({
/* message: "Error retrieving Product with TEXT " + req.params.text */
message: "Error de conexion. Intente de nuevo"
});
}
} else res.send(data);
});
};
- Al continuar con la peticion a
findBySearch
delmodels
, se sabrá que no existen coincidencias para el nombreasdasd
- Para este caso, el "controllers" devolverá en respuesta el Error 404 con el mensaje
"No hay coincidencias para: "asdasd".
Solucion:
Intentar con ingresar otro nombre
2do Error:
Se da cuando se interrumpe la conexion de internet o cuando no hay conexion con el servidor
- GET /api/products
- En este caso, para los diferentes tipos de PETICIONES predefinidos en la presente API
- Por medio de
AXIOS
se envia la solicitud GET, desde el cliente (Frontend) - URL de peticion:
https://bs20-back.vercel.app/api/products/...
// routes/product.routes.js
...
...
app.use('/api/products', router);
};
- La URL de peticion desde el cliente es:
https://bs20-back.vercel.app/api/products/...
- Esto enruta hacia
findSearch
encontrollers/product.controller.js
// controllers/product.controller.js
...
if (err) {
if (err.kind === "not_found") {
res.status(404).send({
message: `No hay coincidencias para: "${req.params.text}".`
});
} else {
res.status(500).send({
message: "Error de conexion. Intente de nuevo"
});
}
} else res.send(data);
...
- En caso se pierda la conexion con la Base de Datos, la API responderá con el
Error 500
y con el mensaje"Error de conexion. Intente de nuevo"
Solucion:
Recargar la pagina web o reiniciar la conexion a internet
-
El proyecto está basado en las tecnologias:
- HTML, CSS, Javascript para el Frontend
- Nodejs, Express para el Backend
- Mysql para la Base de Datos
- Boostrap 5 para los Estilos
-
Para el Software de gestion de paquetes del Backend se está usando NPM
-
Para la instalacion en LOCAL:
- Clonar el repositorio
- En la terminal ejecutar el comando
npm install
- Para levantar el servidor en local, ejecutar el comando
nodemon index.js
Tecnologias utilizadas
🔭Frontend |
⚡Backend |
📫Database |
---|---|---|
CSS | Node js | Mysql |
Bootstrap | Express | |
Javascript |
- Frontend: https://bs20-front.netlify.app/
- Backend: https://bs20-back.vercel.app/