Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 84 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,91 @@
1. Inicializamos el proyecto de Node.JS:
1. Inicializar el Proyecto Node.js: Se crea el archivo package.json para gestionar metadatos y dependencias.
npm init -y
npm init -y contiene informacion basica y lleva un registro de todas las "dependencias" y paquetes del proyecto

2. Instalacion de express
2. Instalar Express: Se añade el framework Express al proyecto. Esto crea la carpeta node_modules y agrega express a las dependencias en package.json.

npm install express
Se crea una carpeta node_modules donde se guardan fisicamente los paquetes instalados y el archivo
package.json se actualiza y contiene una nueva seccion llamada dependencies para registrar que
el proyecto ahora depende de express

3. Creamos el archivo .gitignore para indicar que recursos del proyecto se deben ignorar en el proyecto

4. Inicializamos el Repositorio Local de Git con: git init

5. Añadir y Confirmar Archivos: Se añaden los archivos al área de preparación y se crea un commit inicial. (Commit): git add - git commit -m "Initial commit"

6. Conectar y subir a github Se enlaza el repositorio local con el remoto en GitHub y se suben los cambios. La autenticación se realiza con un Token de Acceso Personal (PAT) en lugar de la contraseña.

git remote add origin https://github.com/stillfreecode/backend.git
git branch -M main
git push -u origin main <- esta opcion nos pide autenticar la cuenta para ello generamos un token desde git


La url baase para todas las peticiones sera: https://localhost:3000/api/products

Prueba: GET: http://localhost:3000/api/products
Pedir solo el producto con id: 1
http://localhost:3000/api/products/1

Prueba POST: http://localhost:3000/api/products
Añadir un nuevo producto a nuestro catalogo:

{
"nombre": "Mouse Inalámbrico",
"precio": 49.99,
"stock": 200
}




PRUEBA PUT:
Cambiar el precio y stock del producto con id: 2
http://localhost:3000/api/products/2

{
"precio": 110.00,
"stock": 40
}

PRUEBA DELETE:
ELiminar el producto con id:1

http://localhost:3000/api/products/1

NOTA IMPORTANTE: Los cambios que hacemos con Postman sí afectan y modifican el array de productos, pero lo hacen únicamente en la memoria del servidor mientras este se encuentra en ejecución.


Prueba para validaciones middleware con express-validator:
{
"nombre": "",
"precio": -10,
"stock": "mucho"
}

Prueba para la estandarizacion de codigos de estado:
GET A http://localhost:3000/api/products/99 – 404 NOT FOUND
POST A http://localhost:3000/api/products – nombre que ya existe → 409 CONFLICT
GET a http://localhost:3000/api/products – nueva estructura de éxito en el campo data

Pruebas para paginacion y ordenamiento basicos

Prueba 1: Por defecto
GET:
http://localhost:3000/api/products
Solo veremos la pagina 1 con los primeros 10 productos

Prueba 2: Prueba por paginacion (segunda pag)
http://localhost:3000/api/products?page=2
Solo veremos la pagina 2

Prueba 3: Cambiando el limite:
http://localhost:3000/api/products?limit=1
Solo veremos la cantidad de productos establecidos

Prueba 4: Prueba combinada (Paginacion y ordenamiento)
http://localhost:3000/api/products?page=2&limit=5&sort=precio,desc
El servidor ordenara los 15 productos por precio, del mas caro al mas barato.
Luego devuelve el segundo bloque de 5 productos de esa lista ordenada (los productos del 6 al 10 mas caros)

File renamed without changes.
27 changes: 27 additions & 0 deletions practica1-crud/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
1. Inicializar el Proyecto Node.js: Se crea el archivo package.json para gestionar metadatos y dependencias.
npm init -y
npm init -y contiene informacion basica y lleva un registro de todas las "dependencias" y paquetes del proyecto

2. Instalar Express: Se añade el framework Express al proyecto. Esto crea la carpeta node_modules y agrega express a las dependencias en package.json.

npm install express
Se crea una carpeta node_modules donde se guardan fisicamente los paquetes instalados y el archivo
package.json se actualiza y contiene una nueva seccion llamada dependencies para registrar que
el proyecto ahora depende de express

3. Creamos el archivo .gitignore para indicar que recursos del proyecto se deben ignorar en el proyecto

4. Inicializamos el Repositorio Local de Git con: git init

5. Añadir y Confirmar Archivos: Se añaden los archivos al área de preparación y se crea un commit inicial. (Commit): git add - git commit -m "Initial commit"

6. Conectar y subir a github Se enlaza el repositorio local con el remoto en GitHub y se suben los cambios. La autenticación se realiza con un Token de Acceso Personal (PAT) en lugar de la contraseña.

git remote add origin https://github.com/stillfreecode/backend.git
git branch -M main
git push -u origin main <- esta opcion nos pide autenticar la cuenta para ello generamos un token desde git





20 changes: 20 additions & 0 deletions practica1-crud/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// index.js

const express = require('express');
const productRoutes = require('./src/routes/product.routes');

const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.json());

app.get('/', (req, res) => {
res.send('¡API funcionando!');
});

// Usamos las rutas de productos con un prefijo
app.use('/api/products', productRoutes);

app.listen(PORT, () => {
console.log(`Servidor escuchando en http://localhost:${PORT}`);
});
31 changes: 30 additions & 1 deletion package-lock.json → practica1-crud/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json → practica1-crud/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"license": "ISC",
"type": "commonjs",
"dependencies": {
"express": "^5.1.0"
"express": "^5.1.0",
"express-validator": "^7.2.1"
}
}
88 changes: 88 additions & 0 deletions practica1-crud/src/controllers/product.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// src/controllers/product.controller.js
const productService = require('../services/product.service');
const { success, error1 } = require('../utils/responseHandler');

const getAllProducts = (req, res) => {
try {
// Extraemos los query params de la URL
const { page, limit, sort } = req.query;

let sortBy;
let sortOrder;

if (sort) {
// El formato es 'campo,orden' (ej: 'precio,desc')
[sortBy, sortOrder] = sort.split(',');
}

const options = { page, limit, sortBy, sortOrder };

const result = productService.getAllProducts(options);

// Devolvemos tanto los datos como la info de paginación
return success(res, result.data, 200, result.pagination);
} catch (err) {
return error1(res, 'Error al obtener los productos.');
}
};


const getProductById = (req, res) => {
try {
const { id } = req.params;
const product = productService.getProductById(id);
if (!product) {
return error1(res, 'Producto no encontrado.', 404, 'NOT_FOUND');
}
return success(res, product);
} catch (err) {
return error1(res, 'Error interno del servidor al obtener el producto.');
}
};

const createProduct = (req, res) => {
try {
const existingProduct = productService.getAllProducts().find(p => p.nombre.toLowerCase() === req.body.nombre.toLowerCase());
if (existingProduct) {
return error1(res, `Ya existe un producto con el nombre '${req.body.nombre}'.`, 409, 'CONFLICT');
}
const newProduct = productService.createProduct(req.body);
return success(res, newProduct, 201);
} catch (err) {
return error1(res, 'Error interno del servidor al crear el producto.');
}
};

const updateProduct = (req, res) => {
try {
const { id } = req.params;
const updatedProduct = productService.updateProduct(id, req.body);
if (!updatedProduct) {
return error1(res, 'Producto no encontrado para actualizar.', 404, 'NOT_FOUND');
}
return success(res, updatedProduct);
} catch (err) {
return error1(res, 'Error interno del servidor al actualizar el producto.');
}
};

const deleteProduct = (req, res) => {
try {
const { id } = req.params;
const deletedProduct = productService.deleteProduct(id);
if (!deletedProduct) {
return error1(res, 'Producto no encontrado para eliminar.', 404, 'NOT_FOUND');
}
return success(res, { message: 'Producto eliminado exitosamente.' });
} catch (err) {
return error1(res, 'Error interno del servidor al eliminar el producto.');
}
};

module.exports = {
getAllProducts,
getProductById,
createProduct,
updateProduct,
deleteProduct,
};
30 changes: 30 additions & 0 deletions practica1-crud/src/middlewares/productValidator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// src/middlewares/productValidator.js
const { body, validationResult } = require('express-validator');

const productValidationRules = [
// El nombre no debe estar vacío y debe ser texto.
body('nombre')
.notEmpty().withMessage('El nombre es obligatorio.')
.isString().withMessage('El nombre debe ser un texto.'),

// El precio debe ser un número flotante mayor que 0.
body('precio')
.isFloat({ gt: 0 }).withMessage('El precio debe ser un número mayor que 0.'),

// El stock debe ser un número entero mayor o igual a 0.
body('stock')
.isInt({ min: 0 }).withMessage('El stock debe ser un número entero mayor o igual a 0.')
];

const handleValidationErrors = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next(); // Si no hay errores, continúa al controlador.
};

module.exports = {
productValidationRules,
handleValidationErrors
};
21 changes: 21 additions & 0 deletions practica1-crud/src/models/product.model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// src/models/product.model.js

let products = [
{ id: 1, nombre: 'Laptop Gamer Pro', precio: 2100.00, stock: 15, creadoEn: new Date() },
{ id: 2, nombre: 'Teclado Mecánico RGB', precio: 125.50, stock: 40, creadoEn: new Date() },
{ id: 3, nombre: 'Mouse Óptico', precio: 35.00, stock: 150, creadoEn: new Date() },
{ id: 4, nombre: 'Monitor Curvo 27"', precio: 450.00, stock: 25, creadoEn: new Date() },
{ id: 5, nombre: 'Silla Ergonómica', precio: 320.75, stock: 10, creadoEn: new Date() },
{ id: 6, nombre: 'Webcam HD 1080p', precio: 80.00, stock: 60, creadoEn: new Date() },
{ id: 7, nombre: 'Micrófono de Condensador', precio: 150.00, stock: 30, creadoEn: new Date() },
{ id: 8, nombre: 'Disco Duro Externo 2TB', precio: 95.99, stock: 80, creadoEn: new Date() },
{ id: 9, nombre: 'Memoria RAM 16GB DDR4', precio: 75.00, stock: 120, creadoEn: new Date() },
{ id: 10, nombre: 'Tarjeta Gráfica RTX 4070', precio: 950.00, stock: 8, creadoEn: new Date() },
{ id: 11, nombre: 'Alfombrilla XL', precio: 25.00, stock: 200, creadoEn: new Date() },
{ id: 12, nombre: 'Auriculares Inalámbricos', precio: 180.25, stock: 55, creadoEn: new Date() },
{ id: 13, nombre: 'Router Wi-Fi 6', precio: 110.00, stock: 22, creadoEn: new Date() },
{ id: 14, nombre: 'Impresora Multifuncional', precio: 230.50, stock: 18, creadoEn: new Date() },
{ id: 15, nombre: 'Tableta Gráfica', precio: 300.00, stock: 28, creadoEn: new Date() }
];

module.exports = products;
28 changes: 28 additions & 0 deletions practica1-crud/src/routes/product.routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// src/routes/product.routes.js
const express = require('express');
const router = express.Router();

// Importamos el controlador
const productController = require('../controllers/product.controller');

// Importamos nuestro middleware de validación
const { productValidationRules, handleValidationErrors } = require('../middlewares/productValidator');

// Definimos las rutas y las asociamos a las funciones del controlador

// Obtener todos los productos (GET /api/products)
router.get('/', productController.getAllProducts);

// Obtener un producto por ID (GET /api/products/1)
router.get('/:id', productController.getProductById);

// Crear un nuevo producto (POST /api/products) contiene validación middleware con productValidationRules -> expres-validator
router.post('/', productValidationRules, handleValidationErrors, productController.createProduct);

// Actualizar un producto existente (PUT /api/products/1) contiene validación middleware con productValidationRules -> expres-validator
router.put('/:id', productValidationRules, handleValidationErrors, productController.updateProduct);

// Eliminar un producto (DELETE /api/products/1)
router.delete('/:id', productController.deleteProduct);

module.exports = router;
Loading