Ir al contenido
HexaTransfer
Volver al blog
Analisis tecnicos

Diseño de API de transferencia de archivos: prácticas RESTful

Diseña API robustas de transferencia de archivos siguiendo las mejores prácticas RESTful. Autenticación, limitación de tasa, cargas multipart y manejo de errores.

Una API REST de transferencia de archivos bien diseñada expone cinco o seis recursos (sesiones, partes, comparticiones, descargas, revocaciones), usa la semántica HTTP de forma honesta (POST para crear, PUT para fragmentos idempotentes, DELETE para revocaciones), y delega el movimiento real de bytes a URLs de almacenamiento prefirmadas para que tu servidor nunca se convierta en el cuello de botella de ancho de banda. La autenticación usa tokens bearer de corta duración sobre TLS 1.3, los límites de tasa diferencian creación de lecturas de metadatos, las subidas fragmentadas siguen el patrón reanudable de tus.io o la semántica multipart de S3, y los errores siguen RFC 7807 Problem Details para que los clientes puedan actuar sobre ellos de forma programática.

Modelar el recurso en torno a acciones, no a archivos

Un error habitual es modelar la API como un árbol de archivos. Los servicios de transferencia se modelan mejor como tres recursos:

  • /sessions — una subida en curso, creada por POST, poblada mediante PUTs de fragmentos
  • /shares — una transferencia completada y direccionable con una caducidad y un presupuesto de descargas
  • /downloads — manejadores de acceso firmados y de corta duración para recuperar bytes

Las sesiones se convierten en comparticiones mediante una acción complete; las comparticiones caducan por tiempo o presupuesto de descargas. Las revocaciones son PATCH en una compartición o DELETE con un token de revocación. Sin sustantivos para "archivo" o "carpeta": esos son detalles de implementación del almacenamiento, no tu contrato público.

Esta forma mantiene la superficie de la API pequeña (menos de 10 endpoints), se mapea limpiamente al caché HTTP (las comparticiones son Cache-Control: private, max-age=60; las descargas son no-store), y te permite cambiar backends de almacenamiento sin romper clientes.

Patrones de autenticación y autorización

Para APIs orientadas a usuario, emite JWTs de corta duración (TTL de 15 minutos) firmados con EdDSA, y renuévalos mediante una cookie segura HttpOnly. Pon el token en Authorization: Bearer, nunca en cadenas de consulta donde queda en los registros.

Para comunicación máquina a máquina, la firma de petición HMAC-SHA256 supera a los tokens bearer porque demuestra la posesión de una clave sin enviarla. AWS SigV4 es el diseño de referencia:

Authorization: HEX4-HMAC-SHA256 
  Credential=AKIA.../20261202/eu/transfer/hex4_request,
  SignedHeaders=host;x-hex-date;x-hex-content-sha256,
  Signature=...

Para las URLs de descarga prefirmadas, los TTL deben ser de minutos, no de horas. Una ventana de 15 minutos equilibra la usabilidad frente al riesgo de que una URL filtrada sea reenviada. Incluye un bloqueo por IP solo si puedes tolerar romper usuarios detrás de CGNAT, cosa que generalmente no puedes.

Subidas fragmentadas y semántica multipart

Existen dos protocolos serios para subidas fragmentadas reanudables: tus.io (borrador IETF, cabeceras Upload-Offset y Upload-Length) y S3 multipart (PartNumber, UploadId, ETag). Elige uno y comprométete con él. Inventar tu propio protocolo parece tentador y acaba mal cuando te das cuenta de que necesitas manejar escrituras parciales, fragmentos fuera de orden y sesiones abandonadas.

El patrón tus en forma REST:

POST   /sessions              -> 201, Location: /sessions/abc
HEAD   /sessions/abc          -> 200, Upload-Offset: 104857600
PATCH  /sessions/abc          -> 204, body = siguiente fragmento
POST   /sessions/abc/complete -> 201, Location: /shares/xyz
DELETE /sessions/abc          -> 204

Límites de tamaño de fragmento: mínimo 5 MB para coincidir con S3 multipart, máximo 100 MB para mantener acotado el coste de reintento, predeterminado 8 MB. Rechaza fragmentos que no se alineen con el offset anunciado con HTTP 409 Conflict más un documento Problem explicando el offset esperado.

Limitación de tasa que refleja el abuso real

Los límites de tasa deben variar según el coste del endpoint:

  • POST /sessions: 20 por IP por hora (costoso: asigna almacenamiento)
  • PATCH /sessions/:id: 10.000 por hora por sesión (barato: escribe bytes)
  • GET /shares/:id: 1.000 por IP por hora (consulta de metadatos)
  • GET /shares/:id/download: 100 por IP por hora (coste de egreso)

Aplica límites en el borde (Cloudflare, Fastly) para protección de base, y una segunda capa en la aplicación (express-rate-limit, @fastify/rate-limit) para control de ráfagas. Devuelve 429 con Retry-After en segundos. Incluye cabeceras de límite de tasa también en respuestas exitosas:

RateLimit-Limit: 20
RateLimit-Remaining: 17
RateLimit-Reset: 2843

Seguir el borrador IETF RateLimit permite que los clientes bien comportados se ritmen solos en lugar de ser bloqueados.

Respuestas de error sobre las que los clientes pueden actuar

RFC 7807 Problem Details es el estándar. Cada error devuelve Content-Type: application/problem+json:

{
  "type": "https://api.example.com/errors/chunk-offset-mismatch",
  "title": "Desajuste de offset de fragmento",
  "status": 409,
  "detail": "El servidor esperaba el offset 5242880, recibió 4194304.",
  "expected_offset": 5242880,
  "session_id": "abc123"
}

El URI de type debe estar documentado y ser estable: es lo que los clientes usan para hacer coincidir patrones. title es genérico; detail es específico. Los campos personalizados añaden contexto accionable por máquina. Nunca filtres trazas de pila, rutas de archivo o IDs internos en los errores.

Mapea los códigos de estado HTTP honestamente: 400 para entrada malformada, 401 para autenticación faltante, 403 para autenticado-pero-no-autorizado, 404 solo cuando el recurso nunca existió (usa 410 Gone para comparticiones caducadas), 413 para cargas que exceden la cuota, 429 para límites de tasa, 500 para bugs, 503 para mantenimiento.

Negociación de contenido y streaming

Los endpoints de subida deben aceptar application/octet-stream y requerir Content-Length. Rechaza multipart/form-data para subidas de fragmentos: añade sobrecarga de análisis y no ayuda a nadie. Acepta Content-Range para escrituras parciales al estilo tus.

Los endpoints de descarga deben soportar peticiones HTTP Range (RFC 7233) para descargas reanudables:

GET /shares/xyz/blob
Range: bytes=104857600-209715199
-> 206 Partial Content
   Content-Range: bytes 104857600-209715199/2147483648

Esto es lo que permite a los navegadores reanudar una descarga de 2 GB después de un corte de Wi-Fi. La mayoría de almacenes compatibles con S3 sirven peticiones Range de forma nativa: tu API solo tiene que redirigir o prefirmar.

Versionado sin acumular deuda

Versiona mediante la ruta URL (/v1/sessions), no mediante cabeceras. El versionado por ruta es visible en los registros, cacheable y más fácil de depurar que Accept: application/vnd.example.v1+json. Mantén v1 soportado durante al menos 24 meses después de que v2 se lance. Añade campos libremente (los clientes deben ignorar los campos desconocidos); nunca elimines ni renombres campos en una versión estable.

Cuando los cambios de ruptura sean necesarios, ejecuta v1 y v2 en paralelo durante 12 meses, expón una cabecera Sunset en las respuestas v1 según RFC 8594 y publica guías de migración con ejemplos reales de antes y después.

Observabilidad y depurabilidad

Cada respuesta debe incluir un ID de correlación (X-Request-ID) tomado de la petición o generado. Registra el ID, IP del cliente (hasheada si es sensible a la privacidad), endpoint, estado y duración en JSON estructurado. No registres cuerpos de petición: así es como las claves de cifrado acaban en Datadog.

Emite métricas por endpoint: recuento de peticiones, latencia p50/p95/p99, tasa de error, bytes de entrada, bytes de salida. Alerta sobre picos de latencia p99 y tasa de 5xx por encima de la línea base. Las trazas mediante OpenTelemetry dan flujo de petición a través de API, almacenamiento y base de datos.

La AEPD y el RGPD exigen registros de actividad de tratamiento adecuados. Un sistema de correlación bien diseñado satisface este requisito sin registrar datos personales en crudo.

La API de HexaTransfer sigue los patrones anteriores: recursos cortos, subidas fragmentadas al estilo tus, errores Problem Details, descargas prefirmadas de 15 minutos, cabeceras RateLimit. Pruébalo en https://hexatransfer.com — gratuito, sin cuenta, hasta 10 GB.

Documentación que coincide con la realidad

Publica una especificación OpenAPI 3.1 junto a la API y mantenla en el mismo repositorio que el código del servidor para que la deriva de esquema sea un problema de revisión de PR y no una sorpresa en producción. Genera al menos un SDK (TypeScript o Python) a partir de la especificación y úsalo en tus propios ejemplos: los bugs del SDK sacan a la luz bugs de la especificación rápidamente. Incluye ejemplos de curl para cada endpoint, un inicio rápido que suba un archivo real en menos de 20 líneas y una página que documente específicamente cada URI de type de error.

Envía archivos grandes de forma segura con cifrado de extremo a extremo

Transfiere archivos de hasta 10 GB gratis con cifrado de extremo a extremo. Sin necesidad de cuenta. Tus archivos se cifran en tu navegador antes de subirlos: nadie más puede leerlos.

Enviar un archivo