Lectura¶
Un registro¶
Si no existe —o el RLS no deja verlo—, 404. Nunca 403: para ese usuario la fila no existe, y un 403 le confirmaría que está ahí.
Una lista¶
GET /public/publicacion?autor_id=3&in_estado=publicada&in_estado=borrador&limit=20&offset=0&order_by=publicado_en&order=DESC
Filtros¶
Un parámetro por columna, con el nombre de la columna. Qué filtros tiene cada una depende de su tipo:
| Parámetro | Qué es | Columnas |
|---|---|---|
campo |
Igual a | Enteros, texto, fechas (date), booleanos, enumerados, claves |
in_campo |
Uno de varios valores | Enteros, texto, fechas (date), claves |
min_campo · max_campo |
Entre dos valores, incluidos | Enteros, decimales, fechas y horas |
- Las listas se repiten:
?in_estado=publicada&in_estado=borrador. Separadas por comas no funcionan. - Un
%en un filtro de texto es un patrón (ILIKE):?titulo=%hola%. No hay forma de buscar un%literal. - La clave autoincremental se filtra solo por lista:
?in_id=3&in_id=7trae esas filas (en una petición, no una por id). No tiene igualdad —para un registro estáGET /{schema}/{tabla}/{clave}— ni rango, que sobre un contador del motor no dice nada del dato. Necesita tai-sql 0.8.0; antes no tenía ningún filtro. - Las demás claves primarias y las foráneas tienen igualdad y lista, sin rango.
- Sin filtro: las columnas cifradas y las hasheadas —guardan un texto distinto para el mismo valor, así que no se pueden comparar—.
- Los campos operativos (
created_at,created_by…) tienen lista y rango, pero no igualdad.
Un filtro sobre una columna que no existe no es un error: se ignora —salvo en el modo estricto—.
Paginación y orden¶
| Parámetro | Qué es |
|---|---|
limit |
Cuántos registros. Sin él, devuelve todos |
offset |
Cuántos saltarse |
order_by |
Columnas por las que ordenar, repetido: ?order_by=estado&order_by=titulo. Las que no existen se ignoran —salvo en el modo estricto— |
order |
ASC (por defecto) o DESC, para todas las columnas de order_by |
meta.pagination —total, has_next, has_prev— solo se calcula si se pide limit u
offset. El total cuenta con los mismos filtros y el mismo RLS que la página, en la misma
transacción: no puede contar filas que el usuario no ve.
Relaciones¶
includes se repite una vez por relación, y admite rutas con puntos hasta la profundidad
máxima (client.max_depth del .taiapiproject, 5 por defecto). En la respuesta cada registro lleva
todas sus relaciones, en todos los niveles: las que se pidieron con sus datos —una lista, [] si
no hay filas; un registro, o null si su clave foránea es nula— y las demás a null. Un nombre que
no existe se ignora, y lo que pasa de la profundidad máxima llega vacío —salvo en el modo estricto—.
El modo estricto¶
Con la cabecera X-Tai-Strict: 1, lo que la API ignoraría en silencio es un 422
VALIDATION_ERROR, con el nombre del parámetro en field:
- un parámetro de consulta que el endpoint no tiene (
?in_idd=3, olimiten/count); - un
order_bysobre una columna que no existe (o que no está en la respuesta, como una hasheada); - un
includesque no es una relación, o con más niveles que la profundidad máxima.
GET /public/publicacion?in_idd=3
X-Tai-Strict: 1
→ 422 { "errors": [ { "code": "VALIDATION_ERROR", "field": "in_idd", … } ] }
Sin la cabecera, todo sigue como siempre: un frontend que no la manda no nota nada. Vale en
todos los endpoints de datos, y se comprueba después de la sesión y los permisos: sin token
sigue siendo un 401. El cliente TypeScript la manda siempre (createTaiClient({ strict: false })
para no hacerlo): un filtro con una errata que devolvía la tabla entera pasa a ser un error.
Contar y comprobar¶
GET /public/publicacion/count?autor_id=3 → data: 7
GET /public/publicacion/exists?autor_id=3 → data: true
Con los mismos filtros que la lista.
Los tipos, tal como viajan¶
| En el schema | En el JSON | Ojo |
|---|---|---|
int, bigint, smallint |
número | un bigint por encima de 2^53 pierde precisión en JavaScript |
float, numeric |
número | un numeric con muchos decimales, también |
datetime, date, time |
texto ISO 8601 | datetime va sin zona horaria: la columna es TIMESTAMP sin zona |
| enumerado | su valor, como texto | sus valores, en GET /{schema}/enums/{nombre} |
dict |
objeto | |
columna hash=True |
no aparece | el valor original no existe: solo se puede verificar |
columna encrypt=True |
el valor, descifrado | el cifrado protege el dato en reposo, no del usuario con permiso |
bytes |
texto base64 | sale en base64 estándar con relleno; se acepta estándar o url-safe, sin el prefijo data:…;base64, (con él, 422). En el cliente TypeScript, fileToBytes y compañía |