REST API
API REST publica con autenticacion por API Key para integraciones programaticas.
Ubicacion: api_gateway/rest_api.py
Autenticacion
Requiere dos headers en cada request:
| Header |
Descripcion |
Ejemplo |
X-API-Key |
API Key del sistema externo |
sk-gdi-abc123... |
X-User-ID |
UUID del usuario que ejecuta |
550e8400-e29b-41d4-... |
curl -H "X-API-Key: sk-gdi-abc123" \
-H "X-User-ID: 550e8400-e29b-41d4-a716-446655440000" \
https://mcp.tu-dominio.com/api/v1/cases/search
Validacion (auth_rest.py)
async def validate_rest_api_key(api_key: str, user_id: str) -> MCPContext:
"""
1. Buscar api_key en public.api_keys (activa, no expirada)
2. Verificar que user_id esta en public.api_key_users para esa key
3. Obtener datos del usuario (municipalidad, sector)
4. Construir MCPContext
"""
Errores:
| Error |
Causa |
| 401 "X-API-Key header requerido" |
Falta header |
| 401 "X-User-ID header requerido" |
Falta header |
| 401 "API Key invalida o expirada" |
Key no encontrada o expirada |
| 401 "Usuario no autorizado" |
user_id no asociado a la API Key |
Tablas de BD
-- Tabla de API Keys (schema: public)
public.api_keys (
id UUID PRIMARY KEY,
key_hash VARCHAR, -- Hash de la API Key
name VARCHAR, -- Nombre descriptivo
is_active BOOLEAN,
expires_at TIMESTAMP,
created_at TIMESTAMP
)
-- Usuarios autorizados por API Key
public.api_key_users (
api_key_id UUID REFERENCES public.api_keys,
user_id UUID,
municipality_id UUID
)
Endpoints
Expedientes
| Metodo |
Endpoint |
Descripcion |
| GET |
/api/v1/cases/search |
Buscar expedientes |
| GET |
/api/v1/cases/{case_id} |
Detalle de expediente |
| GET |
/api/v1/cases/{case_id}/history |
Historial de movimientos |
| GET |
/api/v1/cases/{case_id}/documents |
Documentos del expediente |
| GET |
/api/v1/cases/{case_id}/permissions |
Permisos del usuario |
Documentos
| Metodo |
Endpoint |
Descripcion |
| GET |
/api/v1/documents/search |
Buscar documentos |
| GET |
/api/v1/documents/pending-signatures |
Firmas pendientes |
| GET |
/api/v1/documents/{document_id} |
Detalle de documento |
| GET |
/api/v1/documents/{document_id}/content |
Contenido HTML |
Sistema
| Metodo |
Endpoint |
Descripcion |
| GET |
/api/v1/system/document-types |
Tipos de documentos |
| GET |
/api/v1/system/sectors |
Sectores y departamentos |
| GET |
/api/v1/system/users/{user_id} |
Info de usuario |
| GET |
/api/v1/system/case-templates |
Templates de expedientes |
Implementacion de Handlers
Cada handler valida auth, extrae parametros y llama al tool correspondiente:
async def api_search_cases(request: Request) -> JSONResponse:
"""GET /api/v1/cases/search"""
# 1. Extraer headers
api_key = request.headers.get("X-API-Key")
user_id = request.headers.get("X-User-ID")
# 2. Validar autenticacion
if not api_key:
return _error_response("X-API-Key header requerido", 401)
if not user_id:
return _error_response("X-User-ID header requerido para REST API", 401)
ctx = await validate_rest_api_key(api_key, user_id)
# 3. Extraer query params
params = dict(request.query_params)
page = int(params.get("page", 1))
search = params.get("search", "")
# 4. Llamar al tool (misma logica que MCP)
result = await cases.search_cases(ctx, search=search, page=page, ...)
# 5. Retornar respuesta
return _success_response(result)
Serializacion
Los handlers usan un serializador custom para datetime y UUID:
def _json_serializer(obj):
if isinstance(obj, (datetime, date)):
return obj.isoformat()
if isinstance(obj, UUID):
return str(obj)
raise TypeError(f"Object of type {type(obj).__name__} is not JSON serializable")
Query Parameters Comunes
Busqueda de Expedientes
| Parametro |
Tipo |
Default |
Descripcion |
page |
int |
1 |
Numero de pagina |
page_size |
int |
20 |
Items por pagina (max 100) |
search |
string |
"" |
Buscar por numero o referencia |
status |
string |
null |
active, inactive, archived |
date_filter |
string |
null |
today, week, month, year |
sector_filter |
string |
null |
Acronimo del sector |
Busqueda de Documentos
| Parametro |
Tipo |
Default |
Descripcion |
page |
int |
1 |
Numero de pagina |
page_size |
int |
20 |
Items por pagina |
search |
string |
"" |
Buscar por referencia o numero |
status |
string |
null |
draft, sent_to_sign, signed |
doc_type |
string |
null |
Acronimo de tipo (INF, DICT, etc.) |
Ejemplo Completo
# Buscar expedientes de habilitacion
curl -s \
-H "X-API-Key: sk-gdi-abc123" \
-H "X-User-ID: 550e8400-e29b-41d4-a716-446655440000" \
"https://mcp.tu-dominio.com/api/v1/cases/search?search=habilitacion&status=active&page=1"
# Respuesta
{
"cases": [
{
"case_id": "uuid",
"case_number": "EE-2025-00001-SMG-ADGEN",
"reference": "Habilitacion comercial - Panaderia",
"status": "active",
"admin_sector": "ADGEN",
"last_modified_at": "2025-01-15T10:30:00"
}
],
"total": 1,
"page": 1,
"page_size": 20
}