Ir al contenido

Referencia valores entre bloques

La sintaxis {{...}} es lo que convierte a httui de “un editor markdown” en “un runtime encadenado”. Esta guía es el cheatsheet completo de referencias: de dónde vienen, a dónde pueden ir, qué reglas de scoping aplican.

{{ alias . field . path }}
^^^^^ ^^^^^ ^^^^
| | |
| | JSON path dentro del field
| body | status | headers | cookies | row
el alias del bloque cuya respuesta quieres

El whitespace dentro de {{ ... }} está permitido pero desaconsejado por grep-ability.

Fields disponibles en cada respuesta de bloque

Sección titulada «Fields disponibles en cada respuesta de bloque»
FieldQué esEjemplo
bodyresponse body parseado como JSON (o texto si no es JSON){{login.body.token}}
statuscódigo HTTP status numérico{{login.status}}
headers.<name>valor del header de respuesta{{login.headers.x-request-id}}
cookies.<name>valor de set-cookie{{login.cookies.session}}
sizelongitud del body de respuesta en bytes{{download.size}}
timetotal elapsed en ms{{slow.time}}

Los bloques DB tienen un field extra:

FieldQué esEjemplo
row[N]n-ésima fila del result set{{users_list.row[0].email}}
rowsarray completo de filas{{users_list.rows}} (raro)
affectedfilas afectadas por INSERT/UPDATE/DELETE{{seed.affected}}

Después de body. puedes drilear en cualquier shape JSON con notación de puntos e indexado [N]:

```http alias=order
GET {{BASE_URL}}/orders/{{previous.body.data.items[0].id}}
Authorization: Bearer {{login.body.tokens.access_token}}
```
PatternLee
body.user.id{ user: { id: 42 } } → 42
body.items[0].name{ items: [{ name: "x" }] } → "x"
body.tags[2]{ tags: ["a", "b", "c"] } → "c"
body.nested["odd key"]bracket-quoted para keys non-identifier
body[*].nameNO soportado — usa bloques encadenados o expects

Cuando no te importa el naming, $prev es “el bloque ejecutado anterior, response como root implícito”:

```http alias=login
POST {{BASE_URL}}/auth/login
```
```http
GET {{BASE_URL}}/users/{{$prev.body.user.id}}
```

{{$prev.body.user.id}} es exactamente {{login.body.user.id}}. Úsalo cuando el alias es obvio por contexto (estilo one-shot script).

Las referencias resuelven en estas posiciones antes de que el bloque despache:

Block typePosiciónEjemplo
HTTPURLGET {{BASE_URL}}/x
HTTPheader key{{HEADER_NAME}}: value
HTTPheader valueAuthorization: Bearer {{token}}
HTTPbody (cualquier content type){ "id": {{user.body.id}} }
HTTPquery string?since={{cutoff.body.iso}}
DBSQL textSELECT * FROM x WHERE id = {{user.body.id}}
DBconnection params (host/port vía session override){{PG_HOST}}
Standalonebody del bloquedepende del block type

Las referencias no resuelven en tokens de info-string (alias=..., timeout=...) — esos son configuración, no datos.

Cuando aparece un {{...}} en un bloque SQL, httui no hace string-interpolation. La referencia se convierte en un bind parameter ($1 para Postgres, ? para SQLite/MySQL), y el valor resuelto pasa por el binding de prepared-statement del driver:

```db-local
SELECT * FROM orders
WHERE customer_id = {{user.body.id}}
AND created_at > {{cutoff.body.iso}}
```

Lo que ve el driver:

SELECT * FROM orders
WHERE customer_id = $1
AND created_at > $2

Bind values: [user.body.id, cutoff.body.iso].

Cero superficie de SQL injection, incluso con valores controlados por el usuario fluyendo desde respuestas HTTP.

Si tienes un bloque aliased BASE_URL y una env var también llamada BASE_URL, el bloque gana cuando ambos están en scope:

```http alias=BASE_URL
GET https://dynamic-discovery.example.com/url
```
```http
GET {{BASE_URL}}/health # ¡usa el response body del bloque como URL!
```

Esto es by design (le da a los runbooks una forma de sobreescribir valores de env en runtime), pero es fácil sorprenderte a ti mismo. Regla de oro: usa ALL_CAPS para env vars, snake_case o kebab-case para aliases de bloques.

Cuando ejecutas un bloque que referencia {{other.body.X}}, httui:

  1. Parsea las referencias en tu bloque.
  2. Encuentra que other es un alias definido arriba del bloque actual.
  3. Chequea el cache — si el hash de los inputs de other (body, env, refs) matchea el run cacheado, usa la respuesta cacheada.
  4. Si no, ejecuta other (lo que puede en sí disparar dependencias upstream — recurse).
  5. Sustituye el valor resuelto en tu bloque.
  6. Ejecuta tu bloque.

Las referencias solo pueden apuntar hacia arriba en el archivo. Esto hace al runbook un DAG por construcción — no hay ciclos posibles, no hay loops “bloque 3 referencia bloque 7 que referencia bloque 2”.

CausaLo que ves
El alias no existe en ningún bloque de arribaEl editor subraya la ref en rojo; hover muestra “unknown alias”
El path del field no existe en la respuestaEl bloque ejecuta, el panel muestra error: “path body.user.id not found in response”
El bloque upstream no se ejecutó todavíahttui lo ejecuta primero (auto-exec)
El bloque upstream erroreóEl error se propaga — el bloque downstream no ejecuta, el panel muestra “upstream login failed”
DóndeCómo
En el editorHover el {{...}} — popup muestra valor resuelto o error
Antes del runEl popup se actualiza en vivo a medida que el cache se llena
Después del runEl tab Raw del panel de respuesta muestra la request literal, con todas las refs ya sustituidas
En el drawerClick ⚙ en la toolbar del bloque → tab References lista cada ref con su valor actual