Un ejemplo de e-commerces orientado a demostrar habilidades como backend developer.
npm:
$ npm install
yarn:
$ yarn install
npm:
# development
$ npm run start
# watch mode
$ npm run start:dev
# production mode
$ npm run start:prod
yarn:
# development
$ yarn start
# watch mode
$ yarn start:dev
# production mode
$ yarn start:prod
npm:
# unit tests
$ npm run test
yarn:
# unit tests
$ yarn test
npm:
# database manager
$ npm run prisma -- studio
yarn:
# database manager
$ yarn prisma studio
Cree en el directorio base un archivo de nombre .env
con los siguientes datos:
JWT_SECRET="..."
DATABASE_URL="file:../db/index.db"
JWT_SECRET: Valor para generar el token de acceso JWT, este valor no debe ser público
DATABASE_URL: Ruta sobre la ubicación de la base de datos. Para este ejemplo, solo debe copiar el proporcionado por la documentación
Cada request debe contener un token que identifique al usuario que está accediendo al endpoint. Este token debe ser único para ese usuario y debe tener una vigencia máxima de 30 minutos.
Para obtener el token de un usuario, primero se debe iniciar sesión en el sistema. Luego se obtiene el token de acceso de la respuesta para utilizarlo en los demás endpoints, mediante la cabecera "Authorization". Se debe incluir la cadena "Bearer" seguido del token en la cabecera de la siguiente manera:
Authorization: Bearer <token>
Si se está utilizando POSTMAN, se puede usar las herramientas disponibles para agregar esta cabecera a sus solicitudes.
Es importante tener en cuenta que el token de acceso tiene una duración limitada. En este caso, el token expira después de 30 minutos. Se puede encontrar esta información en el archivo src/modules/auth/auth.module.ts
en la línea que contiene "expiresIn" (línea 19).
import { forwardRef, Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { UsersModule } from '../users/users.module';
import { JwtModule } from '@nestjs/jwt';
import { JwtStrategy } from './strategies/jwt.strategy';
import { PassportModule } from '@nestjs/passport';
import { ConfigService } from '@nestjs/config';
import { RolesModule } from '../roles/roles.module';
import enviroment from '@/config/enviroment';
@Module({
imports: [
forwardRef(() => UsersModule),
PassportModule,
RolesModule,
JwtModule.register({
secret: enviroment().jwt.secret,
signOptions: { expiresIn: '30m' }
}),
],
providers: [AuthService, JwtStrategy, ConfigService],
controllers: [AuthController],
exports: [AuthService, JwtStrategy],
})
export class AuthModule {}
POST - http://localhost:3000/api/auth/login
En el cuerpo de la solicitud, se debe incluir el correo electrónico y la contraseña del usuario. Si la solicitud es exitosa, se recibirá una respuesta que contiene los datos generales del usuario (excepto la contraseña) y el token de acceso.
GET - http://localhost:3000/api/roles
La respuesta contendrá un arreglo de roles, cada uno compuesto por su id y su nombre.
POST - http://localhost:3000/api/auth/register
En el cuerpo de la solicitud, se debe incluir el correo electrónico, el nombre y la contraseña del usuario. También se puede incluir el id del rol del usuario si es necesario. Si la solicitud es exitosa, se recibirá un mensaje de confirmación. Tenga en cuenta que existen validaciones para los campos de correo electrónico, nombre y contraseña.
GET - http://localhost:3000/api/auth/me
Todos los usuarios pueden ver productos por su sku (identificador) pero solo los administradores y editores pueden crear, editar y eliminar artículos, el resto de los usuarios solo pueden consultar. Cada producto debe tener: ● Nombre o título ● Precio. ● Cantidad en stock. ● Categoría. ● Tags. ● Descripción. ● Información adicional. ● Valoración. ● Sku (identificador único). ● Imágenes asociadas (solo urls).
En el sistema, cada usuario tiene asignado un rol que está compuesto por diversos permisos, tal como se puede observar en el siguiente ejemplo:
Los roles y permisos se agregan al sistema mediante el servicio "launcher"
src/core/launcher/launcher.service.ts
para facilitar la resolución de problemas.
Esto significa que cualquier usuario puede obtener un producto utilizando su "sku", pero para crear, actualizar o eliminar un producto, el usuario debe tener el permiso correspondiente en su rol, como se muestra en los siguientes ejemplos.
Para obtener un producto por su sku, se debe consultar el siguiente endpoint
GET - localhost:3000/api/products/:sku
.
Para crear un producto, es necesario enviar una solicitud POST al endpoint http://localhost:3000/api/products
con las siguientes propiedades en el cuerpo de la solicitud:
- name: el nombre del producto.
- price: el precio del producto.
- stockQuantity: la cantidad de stock disponible del producto.
- category: la categoría a la que pertenece el producto.
- tagIds: un arreglo de ids de los tags asociados al producto.
- additionalInformation: información adicional sobre el producto.
- assessment: la valoración del producto.
- description: una descripción detallada del producto.
- urlAssociatedImages: un arreglo de URLs de imágenes asociadas al productos
si los ids de los tags no existen, se producirá un error. Para poder obtener los tags existentes, se puede auxiliar del siguiente enpoint: GET - http://localhost:3000/api/tags
Para actualizar un producto, es necesario enviar una solicitud PUT al endpoint http://localhost:3000/api/products con las siguientes propiedades en el cuerpo de la solicitud:
- name: el nombre del producto.
- price: el precio del producto.
- stockQuantity: la cantidad de stock disponible del producto.
- category: la categoría a la que pertenece el producto.
- tagIds: un arreglo de ids de los tags asociados al producto.
- additionalInformation: información adicional sobre el producto.
- assessment: la valoración del producto.
- description: una descripción detallada del producto.
- urlAssociatedImages: un arreglo de URLs de imágenes asociadas al producto.
Es importante tener en cuenta que, al actualizar un producto mediante las url de imágenes, se eliminarán todas las url asociadas y se asignarán las nuevas url proporcionadas.
Si los ids de los tags proporcionados no existen en la base de datos, se generará un error.
Si se desea eliminar un producto específico, se debe enviar una solicitud DELETE al endpoint http://localhost:3000/api/products/:sku
, donde :sku es el sku del producto que desea eliminar. Si el sku proporcionado no se encuentra en la base de datos, se generará un error.
Endpoint que entregue resultados de una búsqueda enviando cualquiera de las características del producto, una o varias (permitir paginación en base de 10 resultados). Si no se envía ninguna característica el resultado debe ser la lista de artículos paginada.
POST -http://localhost:3000/api/products/fecth
QUERY -page: pagina actual
BODY -name: busca productos por su nombre.
-price: busca por el precio del producto.
-stockQuantity: busca por la cantidad de stock disponible.
-category: busca por la categoría del producto.
-tagIds: busca por las ids de sus tags.
-additionalInformation: busca por la información adicional del producto.
-assessment: busca por la valoración del producto.
-description: busca por la descripción del producto.
-associatedImage: busca por la url guardada de la imagen asociada al producto.
RESPONSE -products: total de productos filtrados
-page: página actual,
-totalElement: total de productos,
-totalPage: total de páginas,
-perPage: total de productos por página
Endpoint que entregue sólo la cantidad de resultados de una búsqueda enviando cualquiera de las características del producto.
POST -http://localhost:3000/api/products/total-element
BODY -name: busca productos por su nombre.
-price: busca por el precio del producto.
-stockQuantity: busca por la cantidad de stock disponible.
-category: busca por la categoría del producto.
-tagIds: busca por las ids de sus tags.
-additionalInformation: busca por la información adicional del producto.
-assessment: busca por la valoración del producto.
-description: busca por la descripción del producto.
-associatedImage: busca por la url guardada de la imagen asociada al producto.
RESPONSE totalElement: total de productos
Esta funcionalidad debe eliminar un (1) artículo del stock. No se puede vender más de un (1) tipo de artículo a la vez y no se puede vender más de un (1) artículo del mismo tipo a la vez.
Para poder vender un producto, el usuario necesita tener el permiso "sell_product" incluido en su rol correspondiente.
POST -http://localhost:3000/api/products/sell/:sku
RESPONSE -message: mensaje de confirmación
ERRORS -si el campo stockQuantity es 0, no permite vender
-el producto debe existir en la base de datos
Para mostrar la lista de articulos vendidos, el usuario necesita tener el permiso "get_items_sold" incluido en su rol correspondiente.
GET -http://localhost:3000/api/sales
QUERY -page: pagina actual
RESPONSE -sales: total de ventas filtradas
-page: página actual,
-totalElement: total de ventas,
-totalPage: total de páginas,
-perPage: total de ventas por página
Para poder ver la ganancia total de ventas, el usuario necesita tener el permiso "get_total_amount" incluido en su rol correspondiente.
GET -http://localhost:3000/api/sales/total_amount
RESPONSE -totalAmount: monto total de ventas
GET -http://localhost:3000/api/products/without-stock-quantity
QUERY -page: pagina actual
RESPONSE -products: total de productos filtrados con 0 stock
-page: página actual,
-totalElement: total de productos,
-totalPage: total de páginas,
-perPage: total de productos por página
- db: esta carpeta almacena la base de datos del proyecto, que en este caso es SQLite.
- docs: se utiliza para almacenar recursos que se emplean en el archivo "readme.md"
- postman: en esta carpeta, se encuentra el archivo
doc.postman.json
que se utiliza para ayudar en la consulta de endpoints. - prisma: esta carpeta contiene el archivo de configuración y el esquema de Prisma.
- src: esta carpeta contiene la lógica de negocio de la aplicación.
- common: en esta carpeta, se encuentran los servicios comunes del proyecto, como guards, mocks, utils, interfaces, libs, entre otros.
- shared: aquí se encuentran los módulos auxiliares reutilizables.
- config: esta carpeta contiene el módulo de configuración.
- modules: aquí se encuentran los módulos que manejan la lógica de negocio.
- core: esta carpeta contiene los módulos principales del sistema.
- test: contiene las pruebas end-to-end (e2e) de la aplicación.
El archivo launcher.service.ts, que se encuentra en la ruta src/core/launcher/launcher.service.ts
, es responsable de inicializar la base de datos si se detecta que está vacía. Este servicio se activa automáticamente cuando se inicia el servidor y se encarga de guardar los datos necesarios para el funcionamiento de la aplicación, incluso aquellos que no tienen endpoints asociados.
Para utilizar Postman, se puede importar el archivo doc.postman.json
que se encuentra en la ruta postman/doc.postman.json
. Se debe asegurar seguir las instrucciones adecuadas al importar el archivo para que se pueda aprovechar todas las funcionalidades de manera efectiva en su proyecto. A continuación, algunas características sobre su uso:
- Se puede utilizar el conjunto de
helpers
de Postman y agilizar las consultas a los endpoints ya creados. - En el endpoint
http://localhost:3000/api/auth/login
, existe un script que se encarga de establecer automáticamente el accessToken, lo cual evita la necesidad de manejarlo manualmente.