Saltar al contenido principal

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, url
  • number, integer, currency, percentage
  • boolean
  • date, datetime
  • markdown, html, json
  • image_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: define true para 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": []
}
CampoDescripción
processedNúmero de elementos recibidos en la matriz de solicitud.
insertedRegistros creados realmente.
insertedIdsID de los registros creados, en orden de inserción.
failedErrores 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

  1. Usa índices: indexa los campos por los que filtras o buscas con frecuencia.
  2. Pagina los resultados: no recuperes todos los registros de una vez.
  3. Limita la selección de campos: recupera solo los campos que necesites.
  4. Almacena respuestas en caché: guarda en caché los datos a los que accedes con frecuencia.
  5. Agrupa operaciones: usa endpoints masivos cuando sea posible.

Calidad de datos

  1. Valida antes de insertar: comprueba los datos del lado cliente.
  2. Gestiona errores: implementa una gestión de errores adecuada.
  3. Usa transacciones: para operaciones de varios registros.
  4. Limpia regularmente: archiva o elimina los registros antiguos.

Seguridad

  1. Nunca expongas claves de API: mantenlas del lado servidor.
  2. Valida la entrada de usuario: sanitízala antes de enviarla a la API.
  3. Usa solo HTTPS: nunca uses HTTP.
  4. Rota las claves regularmente: actualiza las claves de API periódicamente.
  5. 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
)

Documentación relacionada