Saltar al contenidoPedro Farbo
Lección 23 / 2560 min

Proyecto E-commerce - Parte 1

Proyecto E-commerce - Parte 1

Vamos a construir la API completa del e-commerce. Esta primera parte cubre la estructura inicial y módulo de autenticación.

Estructura del Proyecto

ecommerce-api/
├── prisma/
│   └── schema.prisma
├── src/
│   ├── @types/
│   │   └── express.d.ts
│   ├── config/
│   │   ├── auth.ts
│   │   ├── database.ts
│   │   ├── redis.ts
│   │   └── upload.ts
│   ├── controllers/
│   │   ├── auth.controller.ts
│   │   ├── product.controller.ts
│   │   ├── category.controller.ts
│   │   ├── order.controller.ts
│   │   └── user.controller.ts
│   ├── errors/
│   │   └── AppError.ts
│   ├── middlewares/
│   │   ├── auth.middleware.ts
│   │   ├── authorize.middleware.ts
│   │   ├── error.middleware.ts
│   │   └── validate.middleware.ts
│   ├── routes/
│   │   ├── index.ts
│   │   ├── auth.routes.ts
│   │   ├── product.routes.ts
│   │   ├── category.routes.ts
│   │   ├── order.routes.ts
│   │   └── user.routes.ts
│   ├── schemas/
│   │   ├── auth.schema.ts
│   │   ├── product.schema.ts
│   │   └── order.schema.ts
│   ├── services/
│   │   ├── auth.service.ts
│   │   ├── product.service.ts
│   │   ├── category.service.ts
│   │   ├── order.service.ts
│   │   └── mail.service.ts
│   ├── utils/
│   │   └── async-handler.ts
│   ├── app.ts
│   └── server.ts
├── .env
├── .env.example
├── docker-compose.yml
├── package.json
└── tsconfig.json

Inicialización

bash
mkdir ecommerce-api && cd ecommerce-apinpm init -ynpm install express cors helmet compression dotenvnpm install @prisma/client ioredis jsonwebtoken bcryptjs zodnpm install -D typescript ts-node-dev @types/node @types/expressnpm install -D @types/cors @types/jsonwebtoken @types/bcryptjsnpm install -D prismanpx tsc --initnpx prisma init

App Principal

typescript
// src/app.tsimport express from 'express';import cors from 'cors';import helmet from 'helmet';import compression from 'compression';import { routes } from './routes';import { errorHandler } from './middlewares/error.middleware'; const app = express(); // Middlewaresapp.use(helmet());app.use(cors());app.use(compression());app.use(express.json()); // Rutasapp.use('/api', routes); // Error handlerapp.use(errorHandler); export { app };

Servidor

typescript
// src/server.tsimport 'dotenv/config';import { app } from './app';import { prisma } from './config/database'; const PORT = process.env.PORT || 3000; async function bootstrap() {  await prisma.$connect();  console.log('📦 Base de datos conectada');   app.listen(PORT, () => {    console.log(`🚀 Servidor en http://localhost:${PORT}`);  });} bootstrap().catch(console.error);

Módulo de Auth

typescript
// src/services/auth.service.tsimport bcrypt from 'bcryptjs';import jwt from 'jsonwebtoken';import { prisma } from '../config/database';import { AppError } from '../errors/AppError'; export class AuthService {  async register(data: RegisterDTO) {    const exists = await prisma.user.findUnique({      where: { email: data.email },    });     if (exists) {      throw new AppError('Email ya registrado', 409);    }     const user = await prisma.user.create({      data: {        ...data,        password: await bcrypt.hash(data.password, 10),      },      select: { id: true, name: true, email: true, role: true },    });     return {      user,      token: this.generateToken(user.id),    };  }   async login(email: string, password: string) {    const user = await prisma.user.findUnique({ where: { email } });     if (!user || !(await bcrypt.compare(password, user.password))) {      throw new AppError('Credenciales inválidas', 401);    }     return {      user: { id: user.id, name: user.name, email: user.email, role: user.role },      token: this.generateToken(user.id),    };  }   private generateToken(userId: string) {    return jwt.sign({ sub: userId }, process.env.JWT_SECRET!, {      expiresIn: '7d',    });  }}

Controller de Auth

typescript
// src/controllers/auth.controller.tsimport { Request, Response } from 'express';import { AuthService } from '../services/auth.service'; const authService = new AuthService(); export class AuthController {  async register(req: Request, res: Response) {    const result = await authService.register(req.body);    return res.status(201).json(result);  }   async login(req: Request, res: Response) {    const { email, password } = req.body;    const result = await authService.login(email, password);    return res.json(result);  }   async me(req: Request, res: Response) {    return res.json(req.user);  }}

Schemas de Validación

typescript
// src/schemas/auth.schema.tsimport { z } from 'zod'; export const registerSchema = z.object({  body: z.object({    name: z.string().min(2).max(100),    email: z.string().email(),    password: z.string().min(6),  }),}); export const loginSchema = z.object({  body: z.object({    email: z.string().email(),    password: z.string().min(1),  }),});

Rutas de Auth

typescript
// src/routes/auth.routes.tsimport { Router } from 'express';import { AuthController } from '../controllers/auth.controller';import { validate } from '../middlewares/validate.middleware';import { authenticate } from '../middlewares/auth.middleware';import { registerSchema, loginSchema } from '../schemas/auth.schema'; const router = Router();const controller = new AuthController(); router.post('/register', validate(registerSchema), controller.register);router.post('/login', validate(loginSchema), controller.login);router.get('/me', authenticate, controller.me); export { router as authRoutes };

Resumen Parte 1

  • ✅ Estructura del proyecto
  • ✅ Configuración inicial
  • ✅ Módulo de autenticación completo
  • ✅ Validación con Zod

Próxima parte: Módulo de Productos y Categorías! 🚀

¿Te gustó el contenido? ¡Tu contribución ayuda a mantener todo online y gratuito!

PIX:0737160d-e98f-4a65-8392-5dba70e7ff3e