Saltar al contenido
Payment Emulator LabDocumentaciónEntrar a la consola

Funcionamiento interno

El contrato de listados

Todos los listados del plano de control hablan un mismo contrato. Un cliente loaprende una vez, y un endpoint nuevo no puede inventarse el suyo.

3 min de lectura

Índice / Index · English

Traducción de docs/en/runtime/list-contract.md, que es el original. Si discrepan, manda el inglés.

Todos los listados del plano de control hablan un mismo contrato. Un cliente lo aprende una vez, y un endpoint nuevo no puede inventarse el suyo.

text
GET /applications?page=2&pageSize=25&sort=-createdAt,name&search=ana&filter[state]=captured
Parámetro Por defecto Qué significa
page 1 Empieza en 1
pageSize 25, tope 200 Un tamaño sin tope es una denegación de servicio accidental sobre cualquier tabla con historia detrás
sort según el endpoint Separado por comas; un - delante es descendente
search Texto libre, sin distinguir mayúsculas, sobre los campos que el endpoint abre
filter[campo] Coincidencia exacta o por subcadena, según declare el endpoint

Todos los listados responden con el mismo sobre:

json
{ "data": [  ], "meta": { "page": 2, "pageSize": 25, "total": 314, "lastPage": 13 } }

#Listas blancas, no comodidades

Cada endpoint declara un ListSpec: qué campos se pueden ordenar, cuáles filtrar y cómo, cuáles se buscan, y el orden que se usa cuando quien llama no pide ninguno.

No es ceremonia. Un sort abierto deja a cualquiera ordenar por una columna sin índice en una tabla con historia detrás, y un filter abierto le deja sondear campos que el endpoint nunca quiso exponer. Un campo no declarado es un error, no un parámetro ignorado en silencio:

Error Causa
unsortable_field sort nombró un campo que el endpoint no abrió, y la respuesta lista los que sí
unfilterable_field filter[…] nombró un campo que el endpoint no abrió

#Dos propiedades que es fácil perder

Un listado nunca va sin orden. Cuando quien llama no pide ninguno, aplica el del endpoint — y la clave primaria se añade siempre al final. Ordenar por una columna con empates deja las filas empatadas en el orden en que la base las encontró, y ese orden no es estable entre dos consultas, así que la página 2 de un listado ordenado por name puede repetir una fila de la página 1 y saltarse otra entera. Un desempate único es lo que hace que paginar signifique algo.

Un filtro estrecha y nunca ensancha. El alcance propio del endpoint —la aplicación a la que pertenece un listado, las filas que quien llama puede ver— se interseca con los filtros. Un filtro no puede ser una salida del inquilino. Ver identidad y alcance.

#Listados que no son tablas

Los escenarios propios y el catálogo de proveedores viven en código, no en la base. Se paginan con el mismo ayudante sobre un array, con las mismas listas blancas aplicadas igual, porque un cliente no debería tener que distinguir esos listados del resto.

#El lado de la consola

useEntityCollection implementa la mitad de quien llama, una vez: parámetros, carga, paginación, ordenación, filtrado, búsqueda y sincronía opcional con la URL, para que una vista filtrada sea un enlace. core/data/serialization/list-params.serializer.ts mapea su forma a la consulta de arriba — los filtros van anidados y no esparcidos en el nivel superior, para que un filtro llamado search, page o sort no pueda chocar con el contrato.

Una columna que dice sortable tiene que nombrar un campo que el endpoint declaró ordenable, o la API responde unsortable_field y el operador se entera. Que las dos concuerden no se repite en el fichero de columnas a propósito: una segunda copia de la regla podría discrepar de la primera.

#Dónde vive

  • apps/api/src/core/http/list-query.dto.ts — la forma de la consulta y el sobre.
  • apps/api/src/core/http/paginate.ts — las listas blancas, el desempate y la variante sobre arrays.
  • apps/console/app/core/composables/collection/useEntityCollection.ts — la mitad de quien llama.
  • apps/api/test/integration/list-contract.spec.ts — lo que lo fija.
Payment Emulator Lab · RonuSoftwareMIT