Saltar al contenidoPedro Farbo
Lección 14 / 2550 min

Subida de Archivos

Subida de Archivos

Aprende a manejar uploads de imágenes con Multer.

Instalación

bash
npm install multernpm install -D @types/multer

Configuración de Multer

typescript
// src/config/upload.tsimport multer, { FileFilterCallback } from 'multer';import path from 'path';import crypto from 'crypto';import { Request } from 'express';import { AppError } from '../errors/AppError'; const uploadFolder = path.resolve(__dirname, '..', '..', 'uploads'); const storage = multer.diskStorage({  destination: (req, file, cb) => {    cb(null, uploadFolder);  },  filename: (req, file, cb) => {    const hash = crypto.randomBytes(16).toString('hex');    const extension = path.extname(file.originalname);    const filename = `${hash}${extension}`;    cb(null, filename);  },}); const fileFilter = (  req: Request,  file: Express.Multer.File,  cb: FileFilterCallback) => {  const allowedMimes = ['image/jpeg', 'image/png', 'image/webp'];   if (allowedMimes.includes(file.mimetype)) {    cb(null, true);  } else {    cb(new AppError('Tipo de archivo no permitido', 400));  }}; export const upload = multer({  storage,  fileFilter,  limits: {    fileSize: 5 * 1024 * 1024, // 5MB  },});

Ruta de Upload

typescript
// src/routes/upload.routes.tsimport { Router } from 'express';import { upload } from '../config/upload';import { authenticate, authorize } from '../middlewares'; const router = Router(); // Subir imagen de productorouter.post('/products/:id/images',  authenticate,  authorize('ADMIN'),  upload.array('images', 5),  async (req, res) => {    const files = req.files as Express.Multer.File[];     const images = files.map(file => ({      filename: file.filename,      url: `/uploads/${file.filename}`,    }));     // Guardar URLs en el producto    await prisma.product.update({      where: { id: req.params.id },      data: {        images: {          push: images.map(img => img.url),        },      },    });     res.json({ images });  });

Servir Archivos Estáticos

typescript
// src/app.tsimport express from 'express';import path from 'path'; app.use('/uploads', express.static(path.resolve(__dirname, '..', 'uploads')));

Upload a AWS S3

typescript
// src/config/s3.tsimport { S3Client, PutObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3';import multer from 'multer';import multerS3 from 'multer-s3'; const s3 = new S3Client({  region: process.env.AWS_REGION,  credentials: {    accessKeyId: process.env.AWS_ACCESS_KEY_ID!,    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,  },}); export const uploadS3 = multer({  storage: multerS3({    s3,    bucket: process.env.AWS_BUCKET_NAME!,    contentType: multerS3.AUTO_CONTENT_TYPE,    key: (req, file, cb) => {      const filename = `${Date.now()}-${file.originalname}`;      cb(null, `products/${filename}`);    },  }),  limits: { fileSize: 5 * 1024 * 1024 },}); // Eliminar de S3export const deleteFromS3 = async (key: string) => {  await s3.send(new DeleteObjectCommand({    Bucket: process.env.AWS_BUCKET_NAME!,    Key: key,  }));};

Resumen

  • ✅ Upload local con Multer
  • ✅ Validación de tipo y tamaño
  • ✅ Archivos estáticos
  • ✅ Upload a S3 (producción)

Próxima clase: Envío de Emails! 🚀

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

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