Praxsuite

Introducción a PraxQL

Vincent Depassier · 29 de agosto de 2026

PraxQL — Introducción

PraxQL es el lenguaje de consulta declarativo de Praxsuite, basado en JSON. Es lo que usás para leer y escribir datos a través del API Gateway. En vez de configurar un endpoint REST por cada patrón de acceso, mandás un único cuerpo JSON estructurado que describe exactamente lo que querés.


Por qué existe PraxQL

Las tablas de Praxsuite las crean los usuarios en tiempo de ejecución, no las define un desarrollador al desplegar. La forma de un workspace cambia cada vez que alguien agrega una tabla o renombra una columna, y es distinta de la de cualquier otro workspace.

Eso descarta las opciones de estante. GraphQL quiere un esquema fijo al momento de desplegar. Las capas REST autogeneradas asumen una estructura estable y segura de exponer. OData no describe un esquema que cambia por tenant y se modifica mientras el servicio corre.

PraxQL se construyó para esa situación: un endpoint, un formato de request, y un esquema que descubrís en runtime en vez de uno contra el que compilás.


La forma del request

Toda llamada PraxQL es un POST a un solo endpoint:

POST https://gateway.praxsuite.com/{workspaceId}/query
Authorization: Bearer sk_live_xxxxx
Content-Type: application/json

Esa forma corta es la que conviene usar. El gateway también responde la ruta larga /api/v1/gateway/{workspaceId}/query, que es la que vas a ver en ejemplos viejos — mismo endpoint, mismo cuerpo.

El cuerpo siempre tiene dos partes:

{
  "refs": {
    "Alias": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  },
  "query": { ... }
}

O, para escrituras:

{
  "refs": {
    "Alias": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  },
  "mutation": { ... }
}

query y mutation son mutuamente excluyentes.


refs — el diccionario de tablas

El objeto refs mapea los alias que elegís vos a GUIDs de tabla. Existe porque los nombres de tabla no son únicos: un workspace puede tener varias tablas llamadas "Clientes" en distintos momentos, así que un nombre no alcanza para identificar una.

{
  "refs": {
    "Clientes": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "Pedidos":  "b2c3d4e5-f6a7-8901-bcde-f12345678901"
  }
}

Reglas:

  • Las claves son cualquier string que elijas — pasan a ser tu alias dentro de query / mutation.

  • Los valores son los GUID de tabla. Los sacás del panel de esquema del Playground o de GET /schema.

  • Todo GUID debe pertenecer al workspace autenticado. Una referencia a una tabla de otro workspace se rechaza.

  • Hasta 20 refs por request.

refs es además la lista completa de lo que un request puede tocar, que es lo que le permite al gateway contrastarlo con tus permisos antes de hacer ningún trabajo.


query vs mutation

Clave

Operaciones

Cuándo

query

Leer

Traer registros, filtrar, agregar, unir

mutation

Escribir

Insertar filas, actualizar campos, eliminar registros


Opcional: includeTotalCount

Por defecto la respuesta no trae el total de filas que matchean — se omite porque cuesta una segunda pasada sobre los datos. Para pedirlo:

{
  "refs": { ... },
  "query": { ... },
  "includeTotalCount": true
}

Pedilo solo cuando estés dibujando controles de paginación que muestran un total; un botón de "siguiente" no lo necesita.


La forma de la respuesta

{
  "data": [
    { "Nombre": "Acme Corp", "Email": "hola@acme.com" },
    { "Nombre": "Beta Inc",  "Email": "info@beta.io" }
  ],
  "meta": {
    "count": 2,
    "limit": 50,
    "offset": 0,
    "total": null,
    "durationMs": 4
  }
}

Campo

Significado

data

Array de filas. Las claves son nombres lógicos de columna.

meta.count

Cantidad de filas en esta respuesta

meta.limit

El límite efectivo aplicado

meta.offset

El offset aplicado

meta.total

Total de filas que matchean — solo con includeTotalCount: true

meta.durationMs

Tiempo de ejecución, sin contar la autenticación

Conviene leer meta.limit en vez de asumirlo: el límite efectivo puede ser menor que el que pediste.


Errores

{
  "error": {
    "code": "INVALID_QUERY",
    "message": "Column 'Emaill' not found in table 'Clientes'.",
    "details": ["Available columns: Nombre, Email, Telefono, Estado"]
  }
}

HTTP

Código

Causa

400

INVALID_QUERY

Consulta malformada, columna desconocida, operador inválido

400

INVALID_REFS

GUID desconocido, de otro workspace, o refs vacío

401

UNAUTHORIZED

API key inválida o ausente

403

SCOPE_VIOLATION

Tabla o columna fuera de permisos, agregación no permitida

403

FORBIDDEN

Key revocada o vencida, o principal suspendido

408

QUERY_TIMEOUT

La consulta superó los 30 segundos

429

RATE_LIMITED

La key superó su cuota

500

EXECUTION_ERROR

Error interno, registrado del lado del servidor

SCOPE_VIOLATION merece entenderse: una tabla para la que tu key no tiene permiso responde 403, no 404, y el mensaje no confirma si la tabla existe. Es deliberado — un 404 permitiría mapear tu workspace probando GUIDs.


Qué le pasa a un request

Toda llamada se autentica, se contrasta con los permisos de la credencial que la mandó, se traduce de los nombres lógicos que usaste a lo que la capa de almacenamiento necesita, se ejecuta, y se vuelve a filtrar a la salida para aplicar las reglas de enmascarado.

Lo último importa para cómo diseñás tus consultas: los permisos se aplican a la entrada y a la salida. Una columna sobre la que podés filtrar pero no leer participa igual del where sin aparecer nunca en la respuesta.

Todo request queda además registrado en el log de auditoría — incluidos los que fallaron.