SETTO API

Populate

Cómo el parámetro de consulta populate incrusta relaciones, la lista blanca exacta por endpoint, los valores por defecto de cada endpoint y las reglas para las rutas anidadas.

Las relaciones son opcionales. Por defecto cada endpoint devuelve sus propias columnas más un conjunto pequeño de relaciones; todo lo demás lo pides con populate, una lista separada por comas de rutas permitidas. Una clave de relación está ausente del JSON por completo si no se populó — así que 'divisions' in tournament es una prueba confiable de "¿pedí esto?", y una ruta desconocida es un 400 en lugar de un parámetro ignorado en silencio.

Sintaxis

GET /v1/external/tournaments/{idx}?populate=club,divisions,divisions.rounds
  • Separado por comas, sin espacios.
  • El orden no importa.
  • Repetir un valor es inofensivo.
  • Un valor fuera de la lista blanca del endpoint es un 400 — consulta Errores.

populate reemplaza el valor por defecto, no lo extiende

En cuanto envías un parámetro populate, la lista por defecto del endpoint desaparece. GET /v1/external/tournaments/{idx} devuelve club y divisions cuando no mandas nada; ?populate=divisions devuelve las categorías y ningún club. Si quieres ambos, pide ambos.

Las rutas anidadas necesitan a sus padres

Las rutas usan puntos: draws.rounds.games.score.sets. No tienes que listar a los ancestros — la API los expande por ti, así que populate=draws.rounds.games.score.sets implica draws, draws.rounds, draws.rounds.games y draws.rounds.games.score. Listarlos explícitamente no cambia nada.

Lo inverso no es cierto: popular un padre no trae a sus hijos. populate=games te da partidos a los que les faltan las claves homeTeam y score; para esas necesitas games.homeTeam y games.score.

Listas blancas por endpoint

GET /v1/external/tournaments

Las filas de listado se mantienen deliberadamente someras — este es el único endpoint que pagina, así que una fila gorda se multiplica por 100.

PermitidoPor defecto
club(ninguno)

GET /v1/external/tournaments/{idx}

PermitidoPor defecto
club, club.courts, divisions, divisions.rounds, sponsors, circuit, circuitCategory, rankedTiebreakRulesclub,divisions

GET /v1/external/tournaments/{idx}/divisions

PermitidoPor defecto
rounds, teams, teams.playerProfiles, teams.leagueTeam, circuitCategoryrounds

GET /v1/external/tournaments/{idx}/teams

PermitidoPor defecto
playerProfiles, captainProfile, leagueTeam, divisionplayerProfiles,division

GET /v1/external/rounds/{idx}

El endpoint más rico, y aquel cuyo valor por defecto conviene saberse de memoria.

Permitido:

division
pools
pools.teams
pools.standings
pools.standings.team
pools.standings.teamStats
games
games.homeTeam
games.awayTeam
games.winner
games.court
games.score
games.score.sets
draws
draws.rounds
draws.rounds.games
draws.rounds.games.homeTeam
draws.rounds.games.awayTeam
draws.rounds.games.winner
draws.rounds.games.court
draws.rounds.games.score
draws.rounds.games.score.sets

Por defecto, cuando no mandas populate:

division
pools
pools.teams
games
games.homeTeam
games.awayTeam
games.winner
draws.rounds
draws.rounds.games
draws.rounds.games.homeTeam
draws.rounds.games.awayTeam
draws.rounds.games.winner
draws.rounds.games.score
draws.rounds.games.score.sets

El valor por defecto trae los marcadores del cuadro, pero no los de la lista plana

Fíjate en la asimetría: el valor por defecto popula draws.rounds.games.score (+ sets) pero no games.score. Si estás leyendo resultados del arreglo plano games, pide games.score,games.score.sets explícitamente — y recuerda que hacerlo reemplaza toda la lista por defecto, así que vuelve a listar todo lo demás que necesites.

Las claves de populate no siempre son claves de la respuesta

Tres rutas se incrustan bajo un nombre distinto al que pides:

Lo que populasCómo aparece
playerProfiles (o teams.playerProfiles)players: [{ idx, firstName, lastName, avatar }]
captainProfilecaptainProfileIdx: string | null
pools.standings.teamStatsstandings[].teamStats

Ejemplos resueltos

Un cuadro público para una ronda de eliminación — llaves, ganadores y marcadores, sin tablas de grupo:

curl -s -G https://api.setto.io/v1/external/rounds/2e7f5b10-8c94-4d63-a1b8-7f0e3d6c2a95 \
  -H "Authorization: Bearer $SETTO_API_TOKEN" \
  -d populate=draws.rounds.games.homeTeam,draws.rounds.games.awayTeam,draws.rounds.games.winner,draws.rounds.games.score.sets

Una tabla de clasificación de fase de grupos:

curl -s -G https://api.setto.io/v1/external/rounds/9d3c6a84-7e15-4b02-8f6d-1c4a9e7b53f2 \
  -H "Authorization: Bearer $SETTO_API_TOKEN" \
  -d populate=pools.standings.team,pools.standings.teamStats

Un listado completo de categorías con cada pareja inscrita y sus jugadores:

curl -s -G https://api.setto.io/v1/external/tournaments/3c9b7f52-6d41-4a8e-b1f0-2e7d5c9a4b18/divisions \
  -H "Authorization: Bearer $SETTO_API_TOKEN" \
  -d populate=teams,teams.playerProfiles

Costo

Cada ruta populada son más joins y más filas. Tres hábitos mantienen las respuestas rápidas:

  1. Pide las hojas que renderizas, nada más. pools.standings.teamStats sin pools.standings.team es una petición legal y más barata si ya conoces los equipos.
  2. No popules en el endpoint de listado a menos que necesites el club. Toma los ids del listado y luego trae el único torneo que vas a renderizar.
  3. Cachea. Los payloads de una ronda cambian solo cuando se captura un resultado. Combina un TTL corto con peticiones condicionales y la página de una ronda te cuesta un puñado de peticiones por hora en lugar de una por visitante.

En esta página