API de entidades
API REST para gestionar entidades personalizadas y sus registros.
Todos los endpoints de esta página son relativos a la URL base: https://api-eu1.joryio.com. Consulta el resumen de la API.
Resumen
La API de entidades te permite mediante programación:
- Crear y gestionar definiciones de entidad (esquemas).
- Añadir, actualizar y eliminar registros de entidad (datos).
- Consultar y buscar registros.
- Gestionar campos y relaciones de entidad.
Autenticación
Todos los endpoints requieren autenticación mediante token Bearer:
Authorization: Bearer YOUR_API_KEY
Y el contexto de espacio de trabajo mediante encabezado:
X-Workspace-Id: YOUR_WORKSPACE_ID
Definiciones de entidad
Listar todas las entidades
Obtiene todas las definiciones de entidad del espacio de trabajo actual.
GET /entities
Respuesta:
[
{
"id": "uuid",
"organizationId": "uuid",
"workspaceId": "uuid",
"name": "products",
"displayName": "Products",
"description": "Product catalog",
"collectionName": "entity_products",
"primaryKey": "_id",
"displayField": "name",
"settings": {
"allowDuplicates": false,
"enableAudit": true,
"enableVersioning": false,
"softDelete": true
},
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
]
Obtener una entidad por ID
Recupera una definición de entidad concreta.
GET /entities/:entityId
Respuesta:
{
"id": "uuid",
"name": "products",
"displayName": "Products",
...
}
Crear una entidad
Crea una definición de entidad nueva con campos.
POST /entities
Cuerpo de la solicitud:
{
"name": "products",
"displayName": "Products",
"description": "Product catalog with pricing",
"displayField": "name",
"fields": [
{
"name": "sku",
"displayName": "SKU",
"fieldType": "string",
"validation": {
"required": true,
"unique": true,
"minLength": 5,
"maxLength": 20
},
"indexed": true,
"displayOrder": 0
},
{
"name": "name",
"displayName": "Product Name",
"fieldType": "string",
"validation": {
"required": true,
"maxLength": 255
},
"displayOrder": 1
},
{
"name": "price",
"displayName": "Price",
"fieldType": "currency",
"validation": {
"required": true,
"min": 0
},
"displayOrder": 2
},
{
"name": "description",
"displayName": "Description",
"fieldType": "markdown",
"displayOrder": 3
},
{
"name": "active",
"displayName": "Active",
"fieldType": "boolean",
"validation": {
"default": true
},
"displayOrder": 4
}
],
"settings": {
"allowDuplicates": false,
"enableAudit": true,
"enableVersioning": false,
"softDelete": true
}
}
Tipos de campo:
string,email,phone,urlnumber,integer,currency,percentagebooleandate,datetimemarkdown,html,jsonimage_url,file_url
Respuesta:
{
"id": "uuid",
"name": "products",
...
}
Actualizar una entidad
Actualiza la definición de entidad (nombre, descripción y configuración).
PUT /entities/:entityId
Cuerpo de la solicitud:
{
"displayName": "Updated Products",
"description": "Updated description",
"displayField": "sku",
"settings": {
"enableAudit": false
}
}
Eliminar una entidad
Elimina una entidad y todos sus registros.
DELETE /entities/:entityId
Respuesta: 204 No Content
Advertencia: Esto elimina permanentemente el esquema de entidad y todos los registros.
Campos de entidad
Listar campos
Obtiene todos los campos de una entidad.
GET /entities/:entityId/fields
Respuesta:
[
{
"id": "uuid",
"entityDefinitionId": "uuid",
"name": "sku",
"displayName": "SKU",
"description": "Product SKU",
"fieldType": "string",
"validation": {
"required": true,
"unique": true,
"minLength": 5,
"maxLength": 20
},
"indexed": true,
"indexType": "btree",
"displayOrder": 0,
"hidden": false,
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
]
Añadir un campo
Añade un campo nuevo a una entidad.
POST /entities/:entityId/fields
Cuerpo de la solicitud:
{
"name": "category",
"displayName": "Category",
"fieldType": "string",
"validation": {
"required": false
},
"indexed": true,
"displayOrder": 5
}
Eliminar un campo
Elimina un campo de una entidad.
DELETE /entities/:entityId/fields/:fieldId
Respuesta: 204 No Content
Advertencia: Esto elimina la definición de campo. Los datos de registros existentes no se borran, pero quedan inaccesibles.
Registros de entidad
Listar registros
Recupera registros de una entidad con filtrado opcional.
GET /entities/:entityId/records
Parámetros de consulta:
filter: objeto de filtro JSON (codificado para URL).sort: objeto de orden JSON (codificado para URL).limit: máximo de registros que se devolverán (predeterminado: 50).offset: número de registros que se omitirán (predeterminado: 0).
Ejemplos:
# Todos los productos activos
GET /entities/ENTITY_ID/records?filter={"active":true}
# Productos ordenados por precio descendente
GET /entities/ENTITY_ID/records?sort={"price":-1}
# Resultados paginados
GET /entities/ENTITY_ID/records?limit=20&offset=40
Respuesta:
{
"data": [
{
"_id": "665f1c0a9b2e4d0012ab34cd",
"sku": "PROD-001",
"name": "Widget",
"price": 29.99,
"description": "A great widget",
"active": true,
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
],
"total": 150
}
Obtener un registro por ID
Recupera un registro concreto.
GET /entities/:entityId/records/:recordId
Respuesta:
{
"_id": "665f1c0a9b2e4d0012ab34cd",
"sku": "PROD-001",
"name": "Widget",
...
}
Crear un registro
Añade un registro nuevo a una entidad.
POST /entities/:entityId/records
Cuerpo de la solicitud:
{
"sku": "PROD-001",
"name": "Widget",
"price": 29.99,
"description": "A great widget",
"active": true
}
Validación:
- Los campos obligatorios deben estar presentes.
- Los campos únicos deben ser únicos.
- Los valores deben coincidir con los tipos de campo.
- Se aplican las restricciones mín./máx.
Respuesta:
{
"_id": "665f1c0a9b2e4d0012ab34cd",
"sku": "PROD-001",
...
}
Actualizar un registro
Actualiza un registro existente.
PUT /entities/:entityId/records/:recordId
Cuerpo de la solicitud:
{
"price": 34.99,
"description": "An even better widget"
}
Se admiten actualizaciones parciales: incluye solo los campos que quieras cambiar.
Eliminar un registro
Elimina un registro de una entidad.
DELETE /entities/:entityId/records/:recordId
Respuesta: 204 No Content
Si está activada la eliminación reversible, el registro se marca como eliminado. De lo contrario, se elimina de forma permanente.
Crear registros masivamente (cuerpo de matriz)
No hay un endpoint masivo independiente: POST /entities/:entityId/records acepta un objeto de registro único o una matriz JSON de objetos de registro, sin objeto envoltorio. El formato de matriz crea hasta 1000 registros en una solicitud.
POST /entities/:entityId/records
Parámetros de consulta:
triggerAlerts: definetruepara activar alertas de relaciones (reposición y similares) para registros que cambian en esta importación (predeterminado:false).
Cuerpo de la solicitud:
Una matriz JSON de hasta 1000 elementos; una matriz vacía o con más de 1000 devuelve 400. Cada elemento usa el mismo envoltorio data que el objeto único.
El envoltorio de cada elemento se valida individualmente: un elemento sin objeto data se informa en failed mediante su índice de matriz, nunca se acepta silenciosamente, y los elementos válidos restantes se insertan de todos modos. La validación de definición de campo (campos obligatorios, tipos, mín./máx.) se aplica a todo el lote igual que en las creaciones individuales.
[
{
"data": {
"sku": "PROD-001",
"name": "Widget A",
"price": 29.99
}
},
{
"data": {
"sku": "PROD-002",
"name": "Widget B",
"price": 39.99
}
}
]
Respuesta:
A diferencia del formato de objeto, que devuelve el registro creado, el formato de matriz devuelve un resumen agregado:
{
"processed": 2,
"inserted": 2,
"insertedIds": ["id-1", "id-2"],
"failed": []
}
| Campo | Descripción |
|---|---|
processed | Número de elementos recibidos en la matriz de solicitud. |
inserted | Registros creados realmente. |
insertedIds | ID de los registros creados, en orden de inserción. |
failed | Errores de envoltorio por elemento: index (posición en la matriz de solicitud) y reason. |
Búsqueda
Buscar registros
Búsqueda de texto completo en los campos indicados.
GET /entities/:entityId/search
Parámetros de consulta:
q: consulta de búsqueda (obligatoria).fields: nombres de campo separados por comas en los que se buscará (opcional).limit: máximo de resultados (predeterminado: 10).
Ejemplos:
# Busca en todos los campos indexados
GET /entities/ENTITY_ID/search?q=widget
# Busca en campos concretos
GET /entities/ENTITY_ID/search?q=PROD-001&fields=sku,name
# Limita resultados
GET /entities/ENTITY_ID/search?q=widget&limit=5
Respuesta:
[
{
"_id": "id",
"sku": "PROD-001",
"name": "Widget",
...
}
]
Consultas avanzadas
Agregación
Realiza agregaciones en los registros de entidad.
POST /entities/:entityId/aggregate
Cuerpo de la solicitud:
{
"groupBy": "category",
"aggregations": [
{
"field": "price",
"operation": "avg",
"as": "avgPrice"
},
{
"field": "price",
"operation": "sum",
"as": "totalValue"
},
{
"operation": "count",
"as": "productCount"
}
]
}
Operaciones:
count: contar registros.sum: sumar valores.avg: media de valores.min: valor mínimo.max: valor máximo.
Respuesta:
{
"results": [
{
"category": "Electronics",
"avgPrice": 45.99,
"totalValue": 2299.50,
"productCount": 50
},
{
"category": "Clothing",
"avgPrice": 29.99,
"totalValue": 1499.50,
"productCount": 50
}
]
}
Consultas complejas
Ejecuta consultas complejas con sintaxis de estilo MongoDB.
POST /entities/query
Cuerpo de la solicitud:
{
"entity": "products",
"pipeline": [
{
"$match": {
"price": { "$gte": 20, "$lte": 50 },
"active": true
}
},
{
"$group": {
"_id": "$category",
"count": { "$sum": 1 },
"avgPrice": { "$avg": "$price" }
}
},
{
"$sort": { "avgPrice": -1 }
}
]
}
Operadores de filtro
Al usar filtros, puedes utilizar operadores de consulta de MongoDB:
Comparación
$eq: igual a.$ne: distinto de.$gt: mayor que.$gte: mayor o igual que.$lt: menor que.$lte: menor o igual que.$in: valor incluido en la matriz.$nin: valor no incluido en la matriz.
Lógicos
$and: AND lógico.$or: OR lógico.$not: NOT lógico.$nor: NOR lógico.
Elemento
$exists: el campo existe.$type: comprobación del tipo de campo.
Cadena
$regex: coincidencia de expresión regular.
Ejemplos:
// Precio entre 10 y 100
{
"price": { "$gte": 10, "$lte": 100 }
}
// Productos activos en categorías específicas
{
"active": true,
"category": { "$in": ["Electronics", "Computers"] }
}
// Condición compleja
{
"$or": [
{ "price": { "$lte": 20 } },
{ "onSale": true }
],
"active": true
}
Respuestas de error
400 Solicitud incorrecta
{
"statusCode": 400,
"message": "Validation failed",
"errors": [
{
"field": "price",
"message": "price must be greater than or equal to 0"
}
]
}
401 No autorizado
{
"statusCode": 401,
"message": "Unauthorized"
}
404 No encontrado
{
"statusCode": 404,
"message": "Entity not found"
}
409 Conflicto
{
"statusCode": 409,
"message": "Duplicate value for unique field 'sku'"
}
Límites de frecuencia
La API de entidades no tiene hoy límites de frecuencia fijos por endpoint. Consulta resumen de la API: límites de frecuencia para conocer el comportamiento de toda la plataforma y cómo gestionar respuestas 429.
Prácticas recomendadas
Rendimiento
- Usa índices: indexa los campos por los que filtras o buscas con frecuencia.
- Pagina los resultados: no recuperes todos los registros de una vez.
- Limita la selección de campos: recupera solo los campos que necesites.
- Almacena respuestas en caché: guarda en caché los datos a los que accedes con frecuencia.
- Agrupa operaciones: usa endpoints masivos cuando sea posible.
Calidad de datos
- Valida antes de insertar: comprueba los datos del lado cliente.
- Gestiona errores: implementa una gestión de errores adecuada.
- Usa transacciones: para operaciones de varios registros.
- Limpia regularmente: archiva o elimina los registros antiguos.
Seguridad
- Nunca expongas claves de API: mantenlas del lado servidor.
- Valida la entrada de usuario: sanitízala antes de enviarla a la API.
- Usa solo HTTPS: nunca uses HTTP.
- Rota las claves regularmente: actualiza las claves de API periódicamente.
- Implementa límites de frecuencia: también de tu lado.
Ejemplos de código
JavaScript/Node.js
const axios = require('axios');
const api = axios.create({
baseURL: 'https://api-eu1.joryio.com',
headers: {
'Authorization': `Bearer ${process.env.HIPPO_API_KEY}`,
'X-Workspace-Id': process.env.WORKSPACE_ID
}
});
// Crea una entidad
const entity = await api.post('/entities', {
name: 'products',
displayName: 'Products',
fields: [/* ... */]
});
// Crea un registro
const record = await api.post(`/entities/${entity.data.id}/records`, {
sku: 'PROD-001',
name: 'Widget',
price: 29.99
});
// Busca registros
const results = await api.get(`/entities/${entity.data.id}/search`, {
params: { q: 'widget' }
});
Python
import requests
import os
api_key = os.getenv('HIPPO_API_KEY')
workspace_id = os.getenv('WORKSPACE_ID')
headers = {
'Authorization': f'Bearer {api_key}',
'X-Workspace-Id': workspace_id
}
# Crea una entidad
response = requests.post(
'https://api-eu1.joryio.com/entities',
json={
'name': 'products',
'displayName': 'Products',
'fields': [...]
},
headers=headers
)
entity = response.json()
# Crea un registro
response = requests.post(
f'https://api-eu1.joryio.com/entities/{entity["id"]}/records',
json={
'sku': 'PROD-001',
'name': 'Widget',
'price': 29.99
},
headers=headers
)