11 KiB
🔌 ESPECIFICACIÓN API REST - SERVIDOR DE CONTENIDO TES
Versión: 1.0.0
Fecha: 2025-01-06
Base URL: https://servidor-tes.com/api (ejemplo)
📋 ÍNDICE
API PÚBLICA (APP PWA)
Endpoints de Solo Lectura
1. Health Check
GET /api/health
Descripción: Verifica estado del servidor y base de datos.
Autenticación: No requerida
Respuesta 200:
{
"status": "ok",
"timestamp": "2025-01-06T12:00:00Z",
"database": "connected",
"latest_pack_version": "1.0.0",
"latest_pack_hash": "sha256:abc123...",
"server_version": "1.0.0"
}
Respuesta 503 (si BD desconectada):
{
"status": "error",
"timestamp": "2025-01-06T12:00:00Z",
"database": "disconnected",
"message": "Base de datos no disponible"
}
2. Content Pack Latest
GET /api/content/pack/latest
Descripción: Obtiene el Content Pack más reciente (solo contenido publicado).
Autenticación: No requerida
Headers:
If-None-Match: <hash>- Si el hash coincide, retorna 304 Not Modified
Respuesta 200:
{
"metadata": {
"version": "1.0.0",
"generated_at": "2025-01-06T12:00:00Z",
"hash": "sha256:abc123...",
"total_items": 45,
"total_resources": 120
},
"content": { ... },
"media": { ... },
"links": { ... }
}
Headers de Respuesta:
ETag: <hash>- Hash del packContent-Type: application/jsonCache-Control: public, max-age=3600- Cache 1 hora
Respuesta 304: Not Modified (si If-None-Match coincide)
Respuesta 404: No hay pack disponible
3. Content Pack por Versión
GET /api/content/pack/:version
Descripción: Obtiene un Content Pack específico por versión.
Parámetros:
version(path) - Versión semántica (ej: "1.0.0")
Ejemplo:
GET /api/content/pack/1.0.0
Respuesta 200: Igual que /pack/latest
Respuesta 404: Versión no encontrada
4. Protocolo Individual
GET /api/content/protocol/:slug
Descripción: Obtiene un protocolo específico con sus recursos asociados.
Parámetros:
slug(path) - Slug del protocolo (ej: "rcp-adulto-svb")
Ejemplo:
GET /api/content/protocol/rcp-adulto-svb
Respuesta 200:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"type": "protocol",
"slug": "rcp-adulto-svb",
"title": "RCP Adulto - Soporte Vital Básico",
"short_title": "RCP Adulto SVB",
"description": "Protocolo de reanimación cardiopulmonar básica en adultos",
"clinical_context": "RCP",
"level": "operativo",
"priority": "critica",
"status": "published",
"version": "1.0.0",
"content": {
"steps": [...],
"checklist": {...},
"warnings": [...],
"key_points": [...]
},
"resources": {
"images": [
{
"id": "...",
"title": "Posición de Manos - RCP Adulto",
"url": "https://servidor-tes.com/media/images/rcp/...",
"alt_text": "...",
"section": "pasos",
"position": 7
}
],
"videos": [
{
"id": "...",
"title": "RCP Adulto SVB - Técnica Completa",
"url": "https://servidor-tes.com/media/videos/rcp/...",
"duration_seconds": 45,
"section": "pasos",
"position": 0
}
]
},
"related": {
"guide_id": "550e8400-...",
"guide_slug": "rcp-adulto-svb-formativo",
"manual_ids": ["..."],
"related_protocol_ids": ["..."]
}
}
Respuesta 404: Protocolo no encontrado o no publicado
5. Guía Individual
GET /api/content/guide/:slug
Descripción: Obtiene una guía formativa completa con sus 8 secciones.
Parámetros:
slug(path) - Slug de la guía (ej: "abcde-operativo")
Respuesta 200:
{
"id": "...",
"type": "guide",
"slug": "abcde-operativo",
"title": "ABCDE Operativo",
"level": "formativo",
"content": {
"sections": [
{
"numero": 1,
"titulo": "Introducción y Contexto",
"markdown": "# Introducción...",
"resources": {
"images": [...],
"videos": [...]
}
},
// ... 7 secciones más
],
"related_protocol_id": "...",
"related_manual_ids": [...]
},
"resources": {
"images": [...],
"videos": [...]
}
}
6. Recurso Multimedia
GET /api/content/media/:id
Descripción: Obtiene información de un recurso multimedia o redirige al archivo.
Parámetros:
id(path) - UUID del recurso
Query Params:
download(boolean) - Si true, fuerza descarga
Respuesta 200 (JSON si no download):
{
"id": "...",
"type": "image",
"title": "Posición de Manos - RCP Adulto",
"url": "https://servidor-tes.com/media/images/rcp/rcp_posicion_manos_adulto.png",
"alt_text": "...",
"width": 1200,
"height": 800,
"file_size": 245678
}
Respuesta 302 (Redirect si download):
- Redirige a URL del archivo
Respuesta 404: Recurso no encontrado
API ADMIN (PANEL ADMIN)
Autenticación
Login
POST /api/admin/auth/login
Body:
{
"email": "admin@emerges-tes.local",
"password": "Admin123!"
}
Respuesta 200:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "...",
"email": "admin@emerges-tes.local",
"username": "admin",
"role": "super_admin"
},
"expiresIn": 86400
}
Respuesta 401: Credenciales inválidas
Me (Usuario Actual)
GET /api/admin/auth/me
Autenticación: Requerida (Bearer Token)
Respuesta 200:
{
"user": {
"id": "...",
"email": "...",
"username": "...",
"role": "...",
"is_active": true
}
}
Contenido
Listar Contenido
GET /api/admin/content
Query Params:
type- Filtrar por tipo (protocol, guide, manual, drug, checklist)status- Filtrar por estado (draft, in_review, approved, published)priority- Filtrar por prioridad (critica, alta, media, baja)search- Búsqueda de textopage- Número de página (default: 1)limit- Items por página (default: 20)
Respuesta 200:
{
"items": [...],
"total": 45,
"page": 1,
"limit": 20,
"totalPages": 3
}
Obtener Contenido
GET /api/admin/content/:id
Respuesta 200: ContentItem completo
Crear Contenido
POST /api/admin/content
Body:
{
"type": "protocol",
"slug": "rcp-adulto-svb",
"title": "RCP Adulto - Soporte Vital Básico",
"clinical_context": "RCP",
"level": "operativo",
"priority": "critica",
"source_guideline": "ERC",
"content": {
"steps": [...],
"checklist": {...}
},
"tags": ["rcp", "svb", "adulto"]
}
Respuesta 201:
{
"id": "...",
"message": "Contenido creado correctamente"
}
Actualizar Contenido
PUT /api/admin/content/:id
Body: Mismo formato que crear
Respuesta 200:
{
"id": "...",
"message": "Contenido actualizado correctamente",
"version": "1.1.0"
}
Publicar Contenido
POST /api/admin/content/:id/publish
Descripción: Cambia status a 'published' y genera nueva versión.
Respuesta 200:
{
"id": "...",
"status": "published",
"version": "1.0.0",
"message": "Contenido publicado correctamente"
}
Solicitar Validación
POST /api/admin/content/:id/validate
Body:
{
"comments": "Revisado y aprobado",
"validator_role": "tes"
}
Respuesta 200:
{
"id": "...",
"status": "approved",
"validated_by": "...",
"validated_at": "2025-01-06T12:00:00Z"
}
Recursos Multimedia
Listar Recursos
GET /api/admin/media
Query Params:
type- image | videostatus- draft | approved | publishedblock- Filtrar por bloquesearch- Búsqueda
Upload Recurso
POST /api/admin/media/upload
Content-Type: multipart/form-data
Body:
file- Archivo (imagen o vídeo)title- Títuloalt_text- Texto alternativodescription- Descripcióntags- Tags (JSON array)block- Bloque temáticopriority- critica | alta | media | bajausage_type- operativo | formativo | referencia (puede ser array)
Respuesta 201:
{
"id": "...",
"filename": "rcp_posicion_manos_adulto.png",
"path": "/media/images/rcp/rcp_posicion_manos_adulto.png",
"url": "https://servidor-tes.com/media/images/rcp/...",
"file_size": 245678,
"message": "Recurso subido correctamente"
}
Asociar Recurso a Contenido
POST /api/admin/media/:id/associate
Body:
{
"content_item_id": "...",
"section": "pasos",
"position": 7,
"placement": "inline",
"caption": "Posición correcta de manos",
"is_critical": true,
"priority": "critica"
}
Content Pack
Generar Pack
POST /api/admin/pack/generate
Body:
{
"version": "1.0.0",
"include_draft": false,
"notes": "Primera versión del pack"
}
Respuesta 200:
{
"version": "1.0.0",
"file_path": "/storage/packs/pack-v1.0.0.json",
"file_url": "https://servidor-tes.com/api/content/pack/1.0.0",
"hash": "sha256:abc123...",
"size_bytes": 5242880,
"total_items": 45,
"total_resources": 120,
"generated_at": "2025-01-06T12:00:00Z"
}
Listar Versiones
GET /api/admin/pack/versions
Respuesta 200:
{
"versions": [
{
"version": "1.0.0",
"generated_at": "2025-01-06T12:00:00Z",
"size_bytes": 5242880,
"total_items": 45,
"is_latest": true
},
{
"version": "0.9.0",
"generated_at": "2025-01-05T10:00:00Z",
"size_bytes": 4890123,
"total_items": 42,
"is_latest": false
}
]
}
CÓDIGOS DE ESTADO
| Código | Significado | Uso |
|---|---|---|
| 200 | OK | Operación exitosa |
| 201 | Created | Recurso creado |
| 304 | Not Modified | Pack sin cambios (If-None-Match) |
| 400 | Bad Request | Datos inválidos |
| 401 | Unauthorized | No autenticado o token inválido |
| 403 | Forbidden | Sin permisos |
| 404 | Not Found | Recurso no encontrado |
| 409 | Conflict | Conflicto (ej: slug duplicado) |
| 422 | Unprocessable Entity | Validación fallida |
| 429 | Too Many Requests | Rate limit excedido |
| 500 | Internal Server Error | Error del servidor |
| 503 | Service Unavailable | Servicio no disponible (BD desconectada) |
FORMATO DE RESPUESTAS
Respuesta Exitosa
{
"data": { ... },
"meta": {
"timestamp": "2025-01-06T12:00:00Z"
}
}
Respuesta de Error
{
"error": {
"code": "CONTENT_NOT_FOUND",
"message": "Contenido no encontrado",
"details": {
"id": "...",
"slug": "rcp-adulto-svb"
}
},
"meta": {
"timestamp": "2025-01-06T12:00:00Z"
}
}
RATE LIMITING
API Pública (App)
- Límite: 100 requests/minuto por IP
- Headers:
X-RateLimit-Limit: 100X-RateLimit-Remaining: 95X-RateLimit-Reset: 1641475200
API Admin
- Límite: 50 requests/minuto por usuario
- Headers: Mismo formato
Respuesta 429:
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Demasiadas solicitudes. Intenta de nuevo en 60 segundos."
},
"retryAfter": 60
}
Fin de la Especificación