Gestionando Tablas Managed
Esta guia muestra los flujos completos de la API de Managed Tables: provisionamiento del banco, creacion manual, upload de archivos con inferencia de schema, y CRUD de filas.
Cuando usar: cuando tu aplicacion necesita almacenar datos estructurados propios de la company (planillas, datos de calculo, listas operacionales) sin depender de un banco externo. Cuando no usar: si quieres exponer una visualizacion guardada como API (usa Data API).
Pre-requisitos
- JWT del console (login normal — no usa API key).
- Permisos IAM asignados:
managed-tables:list,managed-tables:create,managed-tables:update,managed-tables:deletemanaged-tables:upload,managed-tables:data-read,managed-tables:data-write
- Roles managed que ya agregan todo:
ConnectionManager,DataEngineer.
Vision general de los flujos
Workflow 1: Provisionamiento
Cada company debe provisionar su area de almacenamiento una unica vez. Idempotente — llamadas subsiguientes devuelven el estado existente.
export TOKEN="eyJ..."
export API_BASE_URL="http://localhost:3100"
# 1. Verifica estado
curl "$API_BASE_URL/api/v1/managed-tables/status" \
-H "Authorization: Bearer $TOKEN"
# → { "provisioned": false, "connection_id": null }
# 2. Provisiona (idempotente)
curl -X POST "$API_BASE_URL/api/v1/managed-tables/provision" \
-H "Authorization: Bearer $TOKEN"
# → { "provisioned": true, "connection_id": "507f..." }
Workflow 2: Creacion manual de tabla
Usalo cuando ya conoces el schema. No requiere archivo.
# 1. Crear tabla
curl -X POST "$API_BASE_URL/api/v1/managed-tables" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"display_name": "ventas_mensuales",
"columns": [
{ "name": "producto", "display_name": "Producto", "type": "text", "nullable": false },
{ "name": "valor", "display_name": "Valor", "type": "decimal", "nullable": true },
{ "name": "fecha_venta", "display_name": "Fecha", "type": "date", "nullable": false }
]
}'
# Respuesta:
# { "_id": "507f...", "display_name": "ventas_mensuales", "columns": [...], ... }
# 2. Insertar filas
curl -X POST "$API_BASE_URL/api/v1/managed-tables/507f.../data" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"rows": [
{ "producto": "Camisa", "valor": 89.90, "fecha_venta": "2026-01-15" },
{ "producto": "Pantalon", "valor": 159.90, "fecha_venta": "2026-01-15" }
]
}'
# → 201 { "inserted": 2 }
display_namey nombre de columna coinciden con^[a-z_][a-z0-9_]*$.display_namees unico por company entre tablas activas.- Conflicto devuelve
400conerror_code: MANAGED_TABLE_DUPLICATE_NAME.
Workflow 3: Upload de archivo (CSV/Excel/ZIP)
Flujo de 2 pasos con inferencia de schema. La API procesa el archivo de forma asincrona y el cliente confirma el schema antes de la insercion final.
Etapa 1 — upload
curl -X POST "$API_BASE_URL/api/v1/managed-tables/upload" \
-H "Authorization: Bearer $TOKEN" \
-F "files=@ventas_2026.csv"
# → 201 { "job_id": "abc123", "status": "queued" }
Limites: hasta 10 archivos por llamada, 100MB total. Acepta .csv, .xlsx, .xls, .zip (zip es descomprimido automaticamente).
Etapa 2 — polling del estado
curl "$API_BASE_URL/api/v1/managed-tables/upload-jobs/abc123" \
-H "Authorization: Bearer $TOKEN"
Estados que vas a observar (en orden):
| Estado | Significado | Accion del cliente |
|---|---|---|
queued | Esperando procesamiento | Continuar polling |
analisando | API procesando archivo | Mostrar spinner |
waiting_confirm | Schema inferido listo | Renderizar UI de confirmacion con inferred_schema |
inserting | Insercion en curso | Mostrar progreso (progress.processed_rows) |
done | Tabla creada/actualizada | Redirigir a user_table_id |
failed | Error | Mostrar error |
Cuando status === "waiting_confirm", el body contiene:
{
"status": "waiting_confirm",
"inferred_schema": {
"suggested_table_name": "ventas_2026",
"columns": [
{ "name": "producto", "display_name": "Producto", "type": "text", "nullable": false },
{ "name": "valor", "display_name": "Valor", "type": "decimal", "nullable": true }
],
"sample_rows": [{ "producto": "Camisa", "valor": "89.90" }],
"total_row_count_estimate": 1500
}
}
Etapa 3 — confirmar schema
El usuario puede editar nombres de columna, tipos y display_name de la tabla antes de confirmar:
curl -X POST "$API_BASE_URL/api/v1/managed-tables/upload-jobs/abc123/confirm" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"display_name": "ventas_2026",
"columns": [
{ "name": "producto", "display_name": "Producto", "type": "text", "nullable": false },
{ "name": "valor", "display_name": "Valor", "type": "decimal", "nullable": true }
]
}'
# → 200 { "status": "inserting" }
Continua polling hasta status === "done". El user_table_id en el job apunta a la tabla creada.
Workflow 4: Append/Replace en tabla existente
Anexa nuevas filas a una tabla ya creada (o sustituye todo el contenido).
# Append en tabla existente
curl -X POST "$API_BASE_URL/api/v1/managed-tables/507f.../upload" \
-H "Authorization: Bearer $TOKEN" \
-F "files=@ventas_febrero.csv" \
-F "mode=append"
# Replace (sustituye todo)
curl -X POST "$API_BASE_URL/api/v1/managed-tables/507f.../upload" \
-H "Authorization: Bearer $TOKEN" \
-F "files=@ventas_completo.csv" \
-F "mode=replace"
display_namede la tabla existente es reusado — el regex^[a-z_][a-z0-9_]*$no se aplica (soporta tablas legacy).- Schema confirmado debe coincidir con el schema de la tabla existente — columnas extras causan falla en el insert.
replacees atomico — todo el contenido es sustituido en una unica operacion (sin estado parcial visible).
Workflow 5: CRUD de filas
Operaciones punto-a-punto sobre las filas de una tabla.
# Listar (paginado)
curl "$API_BASE_URL/api/v1/managed-tables/507f.../data?page=1&per_page=50&sort_by=-fecha_venta" \
-H "Authorization: Bearer $TOKEN"
# → { "total": 1500, "quantity": 50, "records": [{ "id": "uuid", "producto": "X", ... }] }
# Insertar
curl -X POST "$API_BASE_URL/api/v1/managed-tables/507f.../data" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "rows": [{ "producto": "Z", "valor": 50 }] }'
# Actualizar fila
curl -X PUT "$API_BASE_URL/api/v1/managed-tables/507f.../data/<rowId>" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "valor": 99.90 }'
# Eliminar
curl -X DELETE "$API_BASE_URL/api/v1/managed-tables/507f.../data/<rowId>" \
-H "Authorization: Bearer $TOKEN"
# → 204 No Content
rowId es el identificador interno de la fila (generalmente UUID generado en el insert). Aparece como id en cada item de records.
Workflow 6: Soft-delete de la tabla
Listados (GET /v1/managed-tables) ya excluyen tablas archivadas, asi que la tabla desaparece inmediatamente. Restauracion no es expuesta por la API — abre un ticket de soporte si necesitas revertir.
Tipos de columna soportados
| Tipo | PostgreSQL DDL | Ejemplo |
|---|---|---|
text | TEXT | "abc" |
integer | BIGINT | 42 |
decimal | NUMERIC | 89.90 |
boolean | BOOLEAN | true |
date | DATE | "2026-01-15" |
datetime | TIMESTAMPTZ | "2026-01-15T10:30:00Z" |
Tratamiento de errores
| HTTP | Codigo | Causa comun | Accion |
|---|---|---|---|
| 400 | MANAGED_TABLE_DUPLICATE_NAME | display_name ya existe activo | Pedir otro nombre al usuario |
| 400 | - | Banco no provisionado | Llamar POST /provision antes |
| 400 | - | Job no esta en waiting_confirm | Continuar polling antes de confirmar |
| 401 | - | JWT ausente/expirado | Refresh token |
| 403 | - | Sin permiso IAM | Verificar el role del usuario |
| 404 | - | Tabla/fila/job inexistente | Releer estado del recurso |
| 422 | - | Schema invalido (regex, tipo, campo obligatorio) | Mostrar error especifico al usuario |
| 500 | - | Error interno | Retry con backoff; loguear request_id |
Buenas practicas
- No llames
POST /provisionen loop — es idempotente, pero cada llamada es mas costosa. VerificaGET /statusprimero. - Polling con backoff exponencial — empieza en 1s, duplica hasta 10s. Job de upload puede llevar segundos a minutos dependiendo del tamano.
- Muestra
progress.processed_rows / progress.total_rowsduranteinsertingpara feedback al usuario en archivos grandes. - Valida el tamano de los archivos en el frontend antes del upload — backend rechaza >100MB total.
- Reusa
mode=appendpara uploads incrementales; no crees nueva tabla cada vez. - Para queries customizadas sobre las tablas managed, exponlas como Visualization y publicalas via Data API. Managed Tables no expone SQL libre.
Referencia completa
Para el contrato detallado de cada endpoint (todos los campos, status codes, ejemplos de error), ve Managed Tables API Reference.