Documentar API de subida de archivos con Swagger y OpenAPI
Documentar tus API de subida y descarga de archivos es esencial para garantizar la mantenibilidad y la facilidad de uso en los servicios web. En esta publicación, exploraremos cómo documentar de forma eficaz tus API de archivos con Swagger y la OpenAPI Specification, lo que permite a los desarrolladores interactuar sin fricciones con tus servicios RESTful.
Introducción
En el desarrollo web moderno, las API de archivos son fundamentales para gestionar las subidas y descargas de archivos en los servicios web. Una documentación clara es esencial para ayudar a los desarrolladores a integrar y mantener rápidamente estos endpoints. Esta guía muestra cómo documentar tus endpoints de subida y descarga de archivos con las herramientas de Swagger y la OpenAPI Specification, lo que te ayuda a crear documentación interactiva y estandarizada para tu REST API.
Entender las API de archivos
¿Qué es una API de archivos?
Una API de archivos es un conjunto de interfaces programáticas que permiten subir y descargar archivos a través de internet. Estas API permiten que los clientes interactúen con recursos del lado del servidor para almacenar y recuperar archivos como imágenes, documentos o cualquier dato binario. Las API de archivos bien diseñadas son vitales para los servicios web que manejan transferencias de archivos, ya que garantizan una comunicación eficiente y segura entre clientes y servidores.
¿Qué son Swagger y OpenAPI?
OpenAPI es un estándar independiente del lenguaje para describir API HTTP, basado originalmente en la Swagger Specification. Swagger designa ahora un conjunto de herramientas que funcionan con OpenAPI. Este ejemplo usa OpenAPI 3.0.3 para describir endpoints, parámetros y respuestas. Swagger UI y Swagger Editor pueden usar esa definición para ofrecer documentación interactiva y simplificar las pruebas.
Beneficios de documentar las API
- Mejor experiencia para desarrolladores: una documentación clara ayuda a los desarrolladores a entender cómo usar tu API sin confusiones.
- Estandarización: usar un estándar como OpenAPI promueve la coherencia en toda la documentación de tu API.
- Generación automática de documentación: las herramientas pueden generar automáticamente documentación interactiva a partir de tu definición de OpenAPI.
- Mantenimiento simplificado: actualizar la documentación es más fácil cuando se define en un formato estructurado y legible por máquinas.
- Pruebas de API mejoradas: los desarrolladores pueden utilizar herramientas como Postman o cURL para probar de forma eficaz tus endpoints de subida y descarga de archivos.
Configurar Swagger en tu proyecto
Para este ejemplo usaremos un proyecto de Node.js con Express.
Inicializar el proyecto
mkdir file-api-swagger
cd file-api-swagger
npm init -y
Instalar dependencias
npm install express@4.22.2 swagger-ui-express@5.0.0 swagger-jsdoc@6.2.8 multer@2.3.0
Multer 2.3.0 incluye las correcciones de seguridad de agosto de 2026. Mantén parcheadas las dependencias de subida a medida que se publiquen nuevos avisos de seguridad.
Configuración básica del servidor Express
Usa Node.js 22 o una versión más reciente. Crea index.js y proporciona un FILE_API_KEY robusto a través de tu
entorno. La clave de API otorga acceso al almacén de archivos compartido de esta demostración; un
servicio multiusuario también necesita comprobaciones de propiedad por archivo. Agrega los
fragmentos de servidor posteriores antes de app.listen.
const express = require('express')
const { timingSafeEqual } = require('node:crypto')
const app = express()
const port = 3000
app.use(express.json())
const apiKey = process.env.FILE_API_KEY
if (!apiKey) throw new Error('FILE_API_KEY is required')
const expectedKey = Buffer.from(apiKey)
function requireApiKey(req, res, next) {
const suppliedKey = Buffer.from(req.get('X-API-Key') || '')
if (suppliedKey.length !== expectedKey.length || !timingSafeEqual(suppliedKey, expectedKey)) {
return res.status(401).json({ error: 'Unauthorized' })
}
next()
}
app.use(['/upload', '/uploads', '/download'], requireApiKey)
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`)
})
Documentar endpoints de subida de archivos
Configurar Multer para las subidas de archivos
const multer = require('multer')
const path = require('node:path')
const uploadsDir = path.join(__dirname, 'uploads')
const upload = multer({
dest: uploadsDir,
limits: {
fileSize: 5 * 1024 * 1024, // 5MB limit
files: 10,
fields: 0,
},
fileFilter: (req, file, cb) => {
const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf']
if (!allowedTypes.includes(file.mimetype)) {
return cb(Object.assign(new Error('Unsupported file type'), { code: 'UNSUPPORTED_FILE_TYPE' }))
}
cb(null, true)
},
})
Endpoint para subir un solo archivo
app.post('/upload', upload.single('file'), (req, res) => {
try {
if (!req.file) {
return res.status(400).json({ error: 'No file uploaded' })
}
res.json({
message: 'File uploaded successfully',
file: {
id: req.file.filename,
name: req.file.originalname,
size: req.file.size,
mimetype: req.file.mimetype,
},
})
} catch (error) {
res.status(500).json({ error: 'File upload failed' })
}
})
Documentar con Swagger
Agregar la configuración de Swagger
Crea un archivo swagger.js:
const swaggerJsDoc = require('swagger-jsdoc')
const swaggerUi = require('swagger-ui-express')
const swaggerDefinition = {
openapi: '3.0.3',
info: {
title: 'File Upload API',
version: '1.0.0',
description: 'API documentation for file upload and download endpoints',
},
servers: [
{
url: 'http://localhost:3000',
},
],
components: {
securitySchemes: {
ApiKeyAuth: {
type: 'apiKey',
in: 'header',
name: 'X-API-Key',
},
},
},
}
const options = {
swaggerDefinition,
apis: ['./index.js'],
}
const swaggerSpec = swaggerJsDoc(options)
module.exports = {
swaggerUi,
swaggerSpec,
}
Integrar Swagger UI en el servidor
En tu index.js:
const { swaggerUi, swaggerSpec } = require('./swagger')
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec))
Inicia tu servidor:
node index.js
Visita http://localhost:3000/api-docs para ver la documentación interactiva de Swagger UI.
Agregar comentarios de Swagger para documentar el endpoint
Coloca el siguiente comentario justo encima de la ruta existente de subida de un solo archivo en index.js.
No registres la ruta por segunda vez. Declarar ApiKeyAuth documenta el requisito; el middleware
requireApiKey de arriba es lo que realmente lo aplica.
/**
* @swagger
* /upload:
* post:
* security:
* - ApiKeyAuth: []
* summary: Uploads a file.
* requestBody:
* required: true
* content:
* multipart/form-data:
* schema:
* type: object
* properties:
* file:
* type: string
* format: binary
* responses:
* 200:
* description: File uploaded successfully.
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* file:
* type: object
* properties:
* id:
* type: string
* name:
* type: string
* size:
* type: number
* mimetype:
* type: string
* 400:
* description: No file uploaded
* 401:
* description: Missing or invalid API key
* 413:
* description: File exceeds the size limit
* 415:
* description: Unsupported file type
* 500:
* description: File upload failed
*/
Subidas de varios archivos
/**
* @swagger
* /uploads:
* post:
* security:
* - ApiKeyAuth: []
* summary: Uploads multiple files.
* requestBody:
* required: true
* content:
* multipart/form-data:
* schema:
* type: object
* properties:
* files:
* type: array
* items:
* type: string
* format: binary
* responses:
* 200:
* description: Files uploaded successfully.
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* files:
* type: array
* items:
* type: object
* properties:
* id:
* type: string
* name:
* type: string
* size:
* type: number
* mimetype:
* type: string
* 400:
* description: Missing files or invalid upload
* 401:
* description: Missing or invalid API key
* 413:
* description: A file exceeds the size limit
* 415:
* description: Unsupported file type
*/
app.post('/uploads', upload.array('files', 10), (req, res) => {
try {
if (!req.files || req.files.length === 0) {
return res.status(400).json({ error: 'No files uploaded' })
}
res.json({
message: 'Files uploaded successfully',
files: req.files.map((file) => ({
id: file.filename,
name: file.originalname,
size: file.size,
mimetype: file.mimetype,
})),
})
} catch (error) {
res.status(500).json({ error: 'File upload failed' })
}
})
Probar las API de subida de archivos con Postman
Postman es una herramienta popular para probar API, incluidos los endpoints de subida de archivos. Para probar tus endpoints de subida de archivos:
- Abre Postman y crea una nueva solicitud POST.
- Ingresa la URL del endpoint de tu API (por ejemplo,
http://localhost:3000/upload). - En la pestaña Body, selecciona
form-datay agrega una clave llamadafile. - Cambia el tipo de la clave
filea File y selecciona un archivo de tu sistema. - Agrega el encabezado
X-API-Keycon tu clave de API. - Envía la solicitud y observa la respuesta.
Como alternativa, puedes hacer la prueba con cURL:
curl -fsSL -F 'file=@/path/to/your/file.jpg' -H 'X-API-Key: YOUR_API_KEY' http://localhost:3000/upload
Documentar endpoints de descarga de archivos
Usa el id generado que devuelve una subida como filename, no el nombre de archivo original del cliente.
La lista de permitidos y la opción root de Express impiden que las solicitudes seleccionen archivos
fuera del directorio de subidas. El filtro MIME de Multer confía en los metadatos del cliente, por
lo que los archivos siguen siendo descargas privadas y no contenido ejecutable públicamente. Valida
el contenido con un analizador o escáner adecuado antes de procesarlo.
/**
* @swagger
* /download/{filename}:
* get:
* security:
* - ApiKeyAuth: []
* summary: Downloads a file.
* parameters:
* - in: path
* name: filename
* required: true
* schema:
* type: string
* description: Generated file ID returned by an upload.
* responses:
* 200:
* description: File downloaded successfully.
* content:
* application/octet-stream:
* schema:
* type: string
* format: binary
* 404:
* description: File not found
* 401:
* description: Missing or invalid API key
* 500:
* description: Download failed
*/
app.get('/download/:filename', (req, res, next) => {
if (!/^[a-f0-9]{32}$/.test(req.params.filename)) {
return res.status(404).json({ error: 'File not found' })
}
res.download(req.params.filename, { root: uploadsDir }, (error) => {
if (!error) return
if (res.headersSent) return next(error)
res.status(404).json({ error: 'File not found' })
})
})
// Register after all routes, including both upload routes.
app.use((error, req, res, next) => {
if (res.headersSent) return next(error)
if (error.code === 'UNSUPPORTED_FILE_TYPE') {
return res.status(415).json({ error: 'Unsupported file type' })
}
if (error instanceof multer.MulterError) {
return res.status(error.code === 'LIMIT_FILE_SIZE' ? 413 : 400).json({ error: 'Upload rejected' })
}
console.error('File API request failed')
res.status(500).json({ error: 'File request failed' })
})
Consideraciones de seguridad
Gestión de claves de API
El middleware de clave de API debe ejecutarse antes del procesamiento de la subida. La limitación de tasa agrega un control de abuso independiente; no es autenticación. Instala el middleware opcional:
npm install express-rate-limit@8 helmet@8
Registra el limitador antes de las rutas y del middleware de subida, no después de ellos:
const { rateLimit } = require('express-rate-limit')
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per window
})
app.use(limiter)
Transferencias seguras de archivos
Para garantizar transferencias seguras de archivos, sigue estas prácticas recomendadas:
- Usa HTTPS en todos los endpoints de la API para cifrar los datos en tránsito.
- Aplica middleware como Helmet para establecer encabezados HTTP seguros.
- Valida los tipos de archivo y aplica límites de tamaño de archivo, como se muestra en la configuración de Multer.
- Actualiza las dependencias con regularidad y mantente atento a los avisos de seguridad.
Por ejemplo, establece los encabezados de seguridad en la API de archivos antes de registrar sus rutas. Mantén por separado la política de página de Swagger UI y configúrala para los recursos y scripts que tu despliegue realmente utiliza:
const helmet = require('helmet')
app.use(['/upload', '/uploads', '/download'], helmet())
Conclusión
Documentar tus API de subida y descarga de archivos con Swagger y la OpenAPI Specification no solo aclara cómo interactuar con tus servicios, sino que también simplifica el mantenimiento y las pruebas. En esta guía, configuramos un servidor Express, integramos Swagger para la documentación interactiva e implementamos medidas de seguridad esenciales. Para soluciones más avanzadas de manejo de archivos, considera explorar Uppy, que ofrece enfoques modernos y modulares para las subidas de archivos.
¡Feliz programación!
