node >=14.0.0 npm >=6.0.0
npm install
npm run build
npm run start
Aplicación de E Commerce con Node Js, Typescript y Mongo DB. Se usaron los patrones MVC y DAO
Las variables de ambiente se ingresan en el archivo .env. El archivo .envExample contiene las diferentes variables utilizadas en la aplicación
-
Descripción: Devuelve el carrito del usuario. Necesita estar loggeado
-
Response:
-
'200': Respuesta exitosa:
{
_id: string,
userId: string,
productos: [{
_id: string,
itemId: string,
cantidad: number,
timestamp: Date
}],
timestamp: Date, // fecha de creación y update
direccion: {
calle: string,
altura: number,
codigoPostal: string,
piso?: number,
departamento?: string|number,
}
}
- 400: No se encuentra loggeado el usuario
- Descripción: Agrega un producto al carrito del usuario. Necesita estar loggeado como usuario
- Request body:
{
prodId: string,
cantidad: number
}
- Response:
- '200': Respuesta exitosa
{
_id: string,
userId: string,
productos: [{
_id: string,
itemId: string,
cantidad: number,
timestamp: Date
}],
timestamp: Date, // fecha de creación y update
direccion: {
calle: string,
altura: number,
codigoPostal: string,
piso?: number,
departamento?: string|number,
}
}
- 400: El parámetro cantidad no es válido. Debe ser de tipo number y mayor a 0
{
error: 'Cantidad inválida'
}
- 400: No existe el prodId
{
error: 'Producto no existente por id'
}
- 400: No hay suficiente stock
{
error: 'Stock insuficiente para la cantidad pedida'
}
- 400: No se encuentra loggeado el usuario
{
error: 'No se encuentra loggeado el usuario'
}
- Descripción: Elimina productos del carrito del usuario. Necesita estar loggeado como usuario
- Request body:
{
prodId: string,
cantidad: number
}
- Response:
- '200': Respuesta exitosa
{
_id: string,
userId: string,
productos: [{
_id: string,
itemId: string,
cantidad: number,
timestamp: Date
}],
timestamp: Date, // fecha de creación y update
direccion: {
calle: string,
altura: number,
codigoPostal: string,
piso?: number,
departamento?: string|number,
}
}
- 400: Cantidad inválida
{
error: 'Cantidad inválida'
}
- 400: Producto no existente por id
{
error: 'Producto no existente por id'
}
- 400: No se encuentra loggeado el usuario
{
error: 'No se encuentra loggeado el usuario'
}
-
Descripción: Cierra la orden
-
Response:
-
'200': Respuesta exitosa
{
_id: string,
userId: string,
items: [{
itemId: string,
cantidad: number,
precio: number
}],
timestamp: Date,
estado: string,
total: number
}
- 400: No se encuentra loggeado el usuario
{
error: 'No se encuentra loggeado el usuario'
}
- 400: carrito vacío
{
error: 'Carrito vacío'
}
-
Descripción: Devuelve las órdenes del usuario loggeado
-
Response:
-
'200': Respuesta exitosa
{
_id: string,
userId: string,
items: [{
itemId: string,
cantidad: number,
precio: number
}],
timestamp: Date,
estado: string,
total: number
}
- 400: No se encuentra loggeado el usuario
{
error: 'No se encuentra loggeado el usuario'
}
-
Descripción: lista las órdenes con el id pedido del usuario loggeado
-
Request param: orderId
-
Response:
-
'200': Respuesta exitosa
{
_id: string,
userId: string,
items: [{
itemId: string,
cantidad: number,
precio: number
}],
timestamp: Date,
estado: string,
total: number
}
- 400: No se encuentra loggeado el usuario
- 400: No se encuentra la orden por id
{
error: 'No se encuentra la orden por id'
}
- Descripción: completa la orden del usuario
- Request body:
{
orderId: string,
}
- Response:
- '200': Respuesta exitosa
{
_id: string,
userId: string,
items: [{
itemId: string,
cantidad: number,
precio: number
}],
timestamp: Date,
estado: string,
total: number
}
- 400: No se encuentra loggeado el usuario
{
error: 'No se encuentra loggeado el usuario'
}
- 400: No se encuentra la orden por id
{
error: 'No se encuentra la orden por id'
}
- 400: Carrito vacío, no se puede completar la orden
{
error: 'Carrito vacío, no se puede completar la orden'
}
- Descripción: No necesita una autenticación previa. Devuelve todos los productos
- Response:
- '200': Respuesta exitosa
{
_id: string|number,
nombre: string,
descripcion: string,
codigo: string,
fotos: string[],
precio: number,
stock: number,
timestamp: Date,
idCategoria: string
}
- '400': No se encuentran productos
{
error: 'No se encuentran productos'
}
- Descripción: No necesita una autenticación previa. Devuelve los productos de la categoría pedida (id de categoría)
- Request param: id de categoría
- Response:
- '200': Respuesta exitosa
{
_id: string|number,
nombre: string,
descripcion: string,
codigo: string,
fotos: string[],
precio: number,
stock: number,
timestamp: Date,
idCategoria: string
}
- '400': No se encuentra el id de categoría
{
error: 'No se encuentra el id de categoría'
}
- Descripción: Necesita de autenticación previa. Debe ser admin. Agrega un producto a la lista de productos
- Request body:
{
nombre: string,
descripcion: string,
codigo: string,
fotos: string[],
precio: number,
stock: number,
idCategoria: string
}
- Response:
- '200': Respuesta exitosa
{
_id: string|number,
nombre: string,
descripcion: string,
codigo: string,
fotos: string[],
precio: number,
stock: number,
timestamp: Date,
idCategoria: string
}
- '400': Errores de validación. Ver
Modelos
{
error: 'El código debe contener 3 caracteres mínimo'
}
- '400': No se enviaron los datos del producto
{
error: 'No hay datos'
}
- Descripción: Necesita de autenticación previa. Debe ser admin. Modifica los datos del producto
- Request param: id del producto
- Request body:
{
nombre: string,
descripcion: string,
codigo: string,
fotos: string[],
precio: number,
stock: number,
timestamp: Date
idCategoria: string
}
- Response:
- '200': Respuesta exitosa
{
msg: 'Producto modificado ${id}'
}
- '400': Errores de validación. Ver
Modelos
{
error: 'El código debe contener 3 caracteres mínimo'
}
- Descripción: Necesita de autenticación previa. Debe ser admin. Modifica los datos del producto
- Request param: id del producto
- Request body:
{
nombre: string,
descripcion: string,
codigo: string,
fotos: string[],
precio: number,
stock: number,
timestamp: Date
idCategoria: string
}
- Response:
- '200': Respuesta exitosa
{
msg: 'Producto modificado ${id}'
}
- '400': Errores de validación. Ver
Modelos
{
error: 'El código debe contener 3 caracteres mínimo'
}
- Descripción: Necesita de autenticación previa. Debe ser admin. Modifica los datos del producto
- Request param: id del producto
- Request body:
{
nombre: string,
descripcion: string,
codigo: string,
fotos: string[],
precio: number,
stock: number,
timestamp: Date
idCategoria: string
}
- Response:
- '200': Respuesta exitosa
{
msg: 'Producto modificado ${id}'
}
- '400': Errores de validación. Ver
Modelos
{
error: 'El código debe contener 3 caracteres mínimo'
}
-
Descripción: Necesita de autenticación previa. Debe ser admin. Elimina el producto
-
Request param: id del producto
-
Response:
-
'200': Respuesta exitosa
{
msg: 'Producto eliminado'
}
- '400': No se encuentra el producto con ese id
{
error: 'No existe el producto'
}
- Descripción: Genera un token de sesión para acceder a las rutas segurizadas
- Request body:
{
username: string,
password: string
}
- Response:
- '200': Respuesta exitosa
{
username: string,
token: string
admin: boolean
}
- '401': No autorizado
{
error: 'Error en usuario o contraseña'
}
- '400': Error en validación de los datos
{
error: 'Password debe contener 8 caracteres'
}
- Descripción: Da de alta un usuario para el posterior login. Crea el carrito por default del usuario
- Request body:
{
name: string,
surname: string,
username: string,
password: string,
passwordConfirmation: string,
tel: number,
direccion: {
calle: string,
altura: number,
codigoPostal: string,
piso?: number,
departamento?: string|number,
},
admin: boolean
}
- Response:
- '201': Respuesta exitosa
{
name: string,
surname: string,
username: string,
password: string,
passwordConfirmation: string,
tel: number,
direccion: {
calle: string,
altura: number,
codigoPostal: string,
piso: number,
departamento: string|number,
},
admin: boolean
}
- '400': Error en validación de los datos
{
error: 'Password debe contener 8 caracteres'
}
- Descripción: Da de alta un usuario para el posterior login. Crea el carrito por default del usuario
- Request body:
{
name: string,
surname: string,
username: string,
password: string,
passwordConfirmation: string,
tel: number,
direccion: {
calle: string,
altura: number,
codigoPostal: string,
piso?: number,
departamento?: string|number,
},
admin: boolean
}
- Response:
- '201': Respuesta exitosa
{
name: string,
surname: string,
username: string,
password: string,
passwordConfirmation: string,
tel: number,
direccion: {
calle: string,
altura: number,
codigoPostal: string,
piso: number,
departamento: string|number,
},
admin: boolean
}
- '400': Error en validación de los datos
{
error: 'Password debe contener 8 caracteres'
}
- Descripción: Da de alta las imágenes (máximo 2 archivos) del producto. Debe estar loggeado y ser admin
- Request files: archivos de imágen (png, jpg, etc.)
- Request body:
{
prodId: string,
}
- Response:
- '201': Respuesta exitosa
- '400': No se encuentra el/los file/s
{
error: 'No subió archivos'
}
- '400': Falta el prodId del body
{
error: 'Falta prodId'
}
-
Descripción: Permite acceder a una imagenes
-
Request param: nombre del archivo de la imagen. El nombre se encuentra en el array productos.fotos
-
Response:
-
'200': URL de la imagen
-
'404': No se encuentra el/los file/s
{
error: 'No se encuentra'
}
- Descripción: Debe ser admin y estar autenticado.
- Request param: nombre del archivo de la imagen. El nombre se encuentra en el array productos.fotos
- Response:
- '200': Respuesta exitosa
- '404': No se encuentra el/los file/s
{
error: 'No se encuentra'
}
Campo/variable | Tipo | Longitud máx | Requerido | Observaciones |
---|---|---|---|---|
id | string o number | 50 | true | id dentro de la BD |
name | string | 50 | true | |
surname | string | 50 | true | |
username | string | 50 | true | email del usuario. No puede ser duplicado |
password | string | 20 | true | hasheado con bcrypt en la BD |
tel | number | - | true | |
admin | bool | - | true | por default, false |
direccion | objeto | 50 | true | ver Direccion |
Campo/variable | Tipo | Longitud máx | Requerido | Observaciones |
---|---|---|---|---|
id | string o number | 50 | true | id dentro de la BD |
calle | string | 50 | true | |
altura | number | - | true | |
codigoPostal | string | 50 | true | |
piso | number | - | false | por default |
departamento | string | - | false | por default '' |
Campo/variable | Tipo | Longitud máx | Requerido | Observaciones |
---|---|---|---|---|
id | string o number | 50 | true | id dentro de la BD |
nombre | string | 50 | true | |
descripcion | string | 50 | true | |
codigo | string | 4 | true | |
fotos | array | - | true | array de strings. El string es el nombre del archivo |
precio | number | - | true | |
stock | number | - | true | |
timestamp | date | - | true | autogenerado |
Campo/variable | Tipo | Longitud máx | Requerido | Observaciones |
---|---|---|---|---|
id | string o number | 50 | true | id dentro de la BD |
userId | string | - | true | |
items | array | - | true | array de items. Ver items |
timestamp | date | - | true | timestamp de creación y modificación de estado |
estado | string | true | true | 'Generado', 'Pagado', 'Enviado', 'Finalizado |
total | number | - | true | total de $ de la orden. Sumatoria de items.precio * items.cantidad |
Campo/variable | Tipo | Longitud máx | Requerido | Observaciones |
---|---|---|---|---|
id | string o number | 50 | true | id dentro de la BD |
itemId | string | - | true | |
cantidad | number | - | true | |
precio | number | - | true |
Campo/variable | Tipo | Longitud máx | Requerido | Observaciones |
---|---|---|---|---|
id | string o number | 50 | true | id dentro de la BD |
userId | string | - | true | id dentro de la BD |
productos | array | - | true | array de productos. Ver productos |
direccion | array | - | true | direccion del usuario. Ver direccion en 'User' |
Campo/variable | Tipo | Longitud máx | Requerido | Observaciones |
---|---|---|---|---|
id | string o number | 50 | true | id dentro de la BD |
itemId | string | - | true | |
cantidad | number | - | true | |
timestamp | date | - | true | timestamp de agregado o modificado |
Campo/variable | Tipo | Longitud máx | Requerido | Observaciones |
---|---|---|---|---|
id | string o number | 50 | true | id dentro de la BD |
userId | string | - | true | id del usuario |
tipo | bool | - | true | origen del mensaje. false para sistema. true para usuario |
mensaje | array | - | true | mensaje entregado |
Agrega el carrito nuevo. Este método es utilizado en el alta de usuario (registración) Recibe el username (o email)
Agrega un producto al carrito del usuario. Recibe del body el prodId y la cantidad. Actualiza la BD de productos con el stock no disponible por sumarse al carrito
Response:
- 400: Cantidad inválida
- 400: Producto no existente por id
- 400: Stock insuficiente para el producto
- 200: {
}
Quita productos del carrito. Recibe del body el prodId y la cantidad. Actualiza la BD de productos con el stock recuperado por quitarse del carrito
Response:
- 400: Cantidad inválida
- 400: Producto no existente por id
- 400: No existe el producto en el carrito
- 400: La cantidad del carrito es insuficiente
- 200: {carrito}
Devuelve el carrito del usuario. No recibe ningún parámetro ya que utiliza la variable tokenJWT (descripta en el controlador Login) para recuperar el username
Response:
- 400: No se encuentra loggeado el usuario
- 200:
{
_id: string,
userId: string,
productos: [{
_id: string,
itemId: string,
cantidad: number,
timestamp: Date
}],
timestamp: Date, // fecha de creación y update
direccion: {
calle: string,
altura: number,
codigoPostal: string,
piso?: number,
departamento?: string|number,
}
}
Da por completada la orden. Para ello, totaliza la factura. Utiliza el método createOrder de la clase Orden No recibe ningún parámetro ya que utiliza la variable tokenJWT (descripta en el controlador Login) para recuperar el username
Response:
- 400: No se encuentra loggeado el usuario
- 200: {orden}
Controlador del chat implementado con websocket.
Corrobora si el token del usuario es válido. Se pudo haber hecho con tokenJWT Responderá: A) “Stock” => Se responderá con el stock actual de todos los productos B) “Orden” => Se responderá con los datos de la ultima orden del usuario C) “Carrito” => Se responderá con los datos del carrito del usuario. D) Cualquier otro mensaje se responderá con el siguiente mensaje:
{msg: `Hola! No he podido comprender tu mensaje.
Por favor ingresa una de las siguientes opciones.
* Stock: para conocer nuestro stock actual
* Orden: Para conocer la información de tu última orden
* Carrito: para conocer el estado actual de tu carrito`}
Utilizada para lo relativo al usuario. Contiene una variable de nombre tokenJWT que, a lo largo de la aplicación, sirve para validar el token generado con JsonWebToken.
tokenJWT {
username: 'email',
token: 'string',
admin: 'boolean'
}
Utilizada para la registración del usuario. Recibe del body:
- name
- surname
- username
- password
- passwordConfirmation
- tel
- direccion (calle, altura, codigoPostal, piso , departamento )
- admin
Valida:
- Los datos enviados con Joi
- Confirmación del password
- Email (variable username en el código) no repetido
En el alta del usuario se encripta la contraseña con bcrypt. Agrega el timestamp
A su vez, se setea el carrito para el usuario, haciendo uso del método Carrito.setCarritoNuevo (ver en Carrito
)
Utilizada para autenticar al usuario. Recibe del body:
- username
- password
Valida:
- Los datos enviados con Joi
- Que username se encuentre en la BD users.
- Que el password sea correcto
Luego, ingresa los valores en el objeto tokenJWT (username, admin y token).
Método utilizado para devolver el userId por Email. Recibe un string (username o email)
getOrderByUserId
Obtiene la orden del usuario. Para ello utiliza la variable tokenJWT (ver la clase Login
)
Interfaz: ordenI)
Recibe por param la orderId. Devuelve la orden.
Interfaz: ordenI)
Recibe por el body la orderId. Pasa a estado "Completada la orden" Devuelve error en el caso de que no se encuentre la orden o no esté en estado "GENERADO" A su vez, envía un email al usuario con la orden y un sms Devuelve la orden guardada
Response:
- 400: No se encuentra la orden con el id orderId
- 400: La orden no está en estado generada
- 200: { _id: userId timestamp total items }
Recibe el carrito y crea la orden
Devuelve todos los productos como un array de objetos.
InterfazI ProductosI
Response:
- 400: Error
- 400: No hay productos en la base
- 200: { }
Obtiene el id de categoría por param y devuelve todos los productos de la categoría, como un array de objetos
InterfazI ProductosI
Response:
- 400: Error
- 400: No se recibió el id de la categoría
- 200: { }
Obtiene el id de producto por param y devuelve el producto
Response:
- 400: Error
- 400: No se recibió el id de la categoría
- 200: { }
Obtiene el producto nuevo a través del body del Request. Inserta el producto
Response:
- 400: Error
- 200: { }
Recibe el id de Producto por param y borra el producto
Response:
- 404: No existe el id de producto
- 200: Producto eliminado
Actualiza el producto. Recibe el producto por el body
Response:
- 404: No existe el id de producto
- 200: Producto modificado
Hace una búsqueda por string en el nombre del producto Recibe el string por param
Response:
- 400: Error
- 200: Array de productos que cumplen con la condición
Middleware hecho en Joi para la validación de los tipos y requisitos del objeto Producto
Generadas con handlebars
Logger creado con Log4JS. El archivo del log se encuentra en el root
Socket-io para el chat
Utilizado para enviar SMS con la orden (clase Orden)
Utilizado para la documentación de los endpoints. Es posible consultarlo desde http://localhost:8080/api-docs
NodeMailer para enviar mails con la orden (clase Orden)
Corrobora que el usuario se encuentre loggeado
Corrobora que el usuario sea Admin para la carga de productos
Middleware de Multer para la subida de archivos al servidor