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