> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Trabajar con los datos de la solicitud y de la respuesta

> Mueve valores hacia la solicitud de un node executor y desde su respuesta. Declara los mapeos, ajusta los valores en tránsito y revisa la solicitud armada antes de llamar al servicio.

Un node executor envía datos a un servicio externo y recibe datos de vuelta. El servicio nombra sus propios campos y tu workflow nombra los suyos. Los mapeos son la forma de mover valores entre ambos: una lista de entradas origen-a-destino en el node, que se aplican a la solicitud antes de la llamada y a la respuesta después de ella.

Los necesitas cuando la forma que lleva tu workflow no es la que acepta el servicio: un documento que debe viajar sin puntuación, un importe que pertenece a un objeto anidado, un score que un node posterior lee con un nombre corto.

## Antes de empezar

***

* Una configuración de provider para el servicio y un node executor que la referencie. Consulta [Referenciar la configuración de provider desde un node de workflow](/es/flowker/integration-guide#paso-3-referenciar-la-configuración-de-provider-desde-un-node-de-workflow).
* Los nombres de los campos que espera el servicio. Cuando el documento OpenAPI del servicio está en el registro, [Derivar el esquema de una operación](/es/reference/flowker/derive-openapi-operation-schema) devuelve `inputSchema` — el cuerpo de la solicitud de la operación — y `outputSchema` — su respuesta correcta. Ambos te dan los nombres de campo que escribes como target y como source de tus mapeos.
* Un workflow en estado `draft`. Un workflow activo queda bloqueado, así que usa [Mover el workflow a draft](/es/reference/flowker/move-workflow-to-draft) antes de editar un node y actívalo de nuevo después.

<Note>
  No envíes `executorId` en un node que llama a una operación de un documento OpenAPI subido. Ese node nombra la operación con `operation_path` y `operation_method`. Flowker rellena el `executorId` por ti, a partir de la configuración de provider a la que apunta el node, antes de validar el workflow. Lo hace cuando creas el workflow y cuando lo actualizas. [Conectar tu propia API](/es/flowker/connecting-your-own-api) recorre todo ese camino. Los nodes de esta página nombran `http`, el conector HTTP genérico, que sí necesita un `executorId` explícito.
</Note>

## Paso 1: Conoce lo que puede leer un mapeo

***

Todo mapeo lee del contexto del workflow, un único objeto JSON que crece a medida que avanza la ejecución:

| Ruta                  | Lo que contiene                                                                                                                                                                                                                                                                                    |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `workflow`            | El payload del trigger: el `inputData` de una solicitud de ejecución, o el cuerpo que recibió una ruta de webhook. Una ruta de webhook agrega también `workflow._webhook` con los metadatos de la llamada — consulta [Metadatos del webhook](/es/flowker/integration-guide#metadatos-del-webhook). |
| `execution.id`        | El identificador de la ejecución.                                                                                                                                                                                                                                                                  |
| `execution.startedAt` | El momento en que empezó la ejecución, en UTC.                                                                                                                                                                                                                                                     |
| `<nodeId>`            | La salida de cada node ya completado, bajo el ID de ese node.                                                                                                                                                                                                                                      |

Direcciona un valor por su ruta desde una de esas claves de primer nivel:

| Source                         | Lo que selecciona                                   |
| ------------------------------ | --------------------------------------------------- |
| `workflow.customer.document`   | Un campo anidado del payload del trigger.           |
| `workflow.items[0].sku`        | Un elemento de un array.                            |
| `workflow.items[*].sku`        | El mismo campo en cada elemento, como array.        |
| `workflow`                     | Todo el payload del trigger como objeto.            |
| `score-transaction.body.score` | Un campo de la salida del node `score-transaction`. |

<Note>
  El `source` de un mapeo es una ruta simple. No lo envuelvas en `${...}`: las llaves pertenecen a los campos de plantilla del node (`body`, `headers`, `query`, `path`), y dentro de un mapeo una cadena `${...}` se lee como un nombre de ruta literal que no selecciona nada.
</Note>

## Paso 2: Declara el mapeo de entrada

***

Los mapeos de entrada viven en un array `inputMapping` dentro del objeto `data` del node executor. Cada entrada mueve un valor al cuerpo de la solicitud saliente.

| Campo            | Tipo    | Requerido | Descripción                                                                                                                                                 |
| ---------------- | ------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `source`         | string  | Sí        | La ruta del contexto del workflow que se lee.                                                                                                               |
| `target`         | string  | Sí        | La ruta del cuerpo de la solicitud saliente que se escribe. Un target con puntos crea el objeto anidado: `payment.amount` envía `{"payment":{"amount":…}}`. |
| `transformation` | object  | No        | Un cambio que se aplica al valor después de que llega al target. Consulta el [Paso 4](#paso-4-ajusta-un-valor-en-tránsito).                                 |
| `required`       | boolean | No        | Si la ruta de origen debe existir. Por defecto es `false`. Aplica a todo el node — mira más abajo.                                                          |

El resultado del mapeo **es** el cuerpo de la solicitud. Escribe cada `target` exactamente como el servicio espera recibirlo: no hay objeto envolvente ni prefijo que agregar.

<Accordion title="Ejemplo — mapear el payload del trigger a una verificación de fraude">
  ```json theme={null}
  {
    "id": "score-transaction",
    "type": "executor",
    "name": "Score transaction",
    "position": { "x": 200, "y": 0 },
    "data": {
      "executorId": "http",
      "providerConfigId": "019c96a0-0ac0-7de9-9f53-9cf842a2ee5a",
      "method": "POST",
      "path": "/score-transaction",
      "inputMapping": [
        { "source": "workflow.transactionId", "target": "reference" },
        { "source": "workflow.amount", "target": "payment.amount" },
        { "source": "workflow.customer.document", "target": "payment.document" }
      ]
    }
  }
  ```

  Con un payload de trigger de `{"transactionId":"txn-98765","amount":1500.00,"customer":{"document":"12345678900"}}`, el servicio recibe:

  ```json theme={null}
  {
    "reference": "txn-98765",
    "payment": { "amount": 1500.00, "document": "12345678900" }
  }
  ```
</Accordion>

### Cuando un source no selecciona nada

Una ruta de origen ausente del contexto no es un error. El target se escribe igualmente, con el valor `null`, y la solicitud sale.

Usa `required: true` cuando el node no deba llamar al servicio sin un valor. Flowker revisa entonces cada ruta de origen de ese node antes de armar la solicitud y falla el paso cuando alguna está ausente: la ejecución se detiene con `FLK-0504` y el paso informa `input transformation failed`.

<Note>
  `required` aplica al node, no solo a la entrada que lo lleva. Si alguna entrada del `inputMapping` de un node pone `required: true`, cada ruta de origen de ese array debe resolverse. Para mantener algunos campos opcionales, deja `required` fuera en todo el node.
</Note>

Dale a cada `target` una sola entrada. Cuando dos entradas escriben el mismo target, gana la última.

## Paso 3: Decide qué arma el cuerpo de la solicitud

***

Un node tiene tres formas de producir un cuerpo de solicitud. Flowker las revisa en un orden fijo y se detiene en la primera que esté presente:

<Steps>
  <Step title="data.body">
    Una plantilla de cuerpo explícita gana por completo. Flowker resuelve sus referencias `${...}` contra el contexto del workflow y envía el resultado. Mientras `data.body` está presente, `inputMapping`, `transforms` y `config` no aportan nada al cuerpo.

    Cada referencia `${...}` aquí debe resolverse. Una que no lo hace falla el node con `FLK-0143`, antes de hacer ninguna llamada — lo contrario de un source de mapeo, que se resuelve como `null`. Usa `data.body` cuando un valor ausente deba detener el workflow, y un mapeo cuando la solicitud deba salir de todos modos.
  </Step>

  <Step title="inputMapping o transforms">
    En caso contrario, Flowker arma una capa a partir de `inputMapping`. Cuando `inputMapping` está vacío, la arma a partir de `transforms`. Los dos son mutuamente excluyentes: un node con al menos una entrada en `inputMapping` nunca ejecuta sus `transforms` sobre la entrada.
  </Step>

  <Step title="Literales de config">
    Los valores literales de `data.config` siembran el cuerpo. Con una capa presente, los literales son la base y la capa gana en cualquier clave que ambos definan, así un mismo node puede combinar valores fijos con valores mapeados. Sin capa, los literales son el cuerpo por sí solos.
  </Step>
</Steps>

El transporte nunca forma parte del cuerpo de la solicitud. Antes de que `config` pueda sembrar el cuerpo, Flowker elimina de ahí estos nombres: `method`, `path`, `url`, `endpointName`, `query`, `headers`, `auth`, `retry`, `timeout`, `timeout_seconds`, `request_format`, `success_status_codes`, `allowedHosts` y `allowedPrivateHosts`. Por eso un node que guarda transporte en `config` por error no envía nada de eso al destino, y un bloque `auth` colocado ahí nunca puede viajar como contenido de la solicitud.

El node lee su propio transporte en el primer nivel de su objeto `data`: `path`, `endpointName`, `method`, `headers`, `query`, `auth`, `timeout_seconds`, `retry`, `success_status_codes` y `request_format`. Las listas de hosts permitidos de salida no están entre ellos: `allowedHosts` y `allowedPrivateHosts` se definen en la configuración de provider, y cada una aplica a todos los nodes que llaman a través de ella.

<Accordion title="Ejemplo — valores fijos junto con valores mapeados">
  ```json theme={null}
  {
    "data": {
      "executorId": "http",
      "providerConfigId": "019c96a0-0ac0-7de9-9f53-9cf842a2ee5a",
      "method": "POST",
      "path": "/score-transaction",
      "config": {
        "channel": "web",
        "payment": { "currency": "BRL" }
      },
      "inputMapping": [
        { "source": "workflow.transactionId", "target": "reference" },
        { "source": "workflow.amount", "target": "payment.amount" }
      ]
    }
  }
  ```

  Los literales y los valores mapeados se combinan, y el anidamiento se combina con el anidamiento:

  ```json theme={null}
  {
    "channel": "web",
    "reference": "txn-98765",
    "payment": { "currency": "BRL", "amount": 1500.00 }
  }
  ```
</Accordion>

## Paso 4: Ajusta un valor en tránsito

***

Cuando el servicio necesita un valor en otra forma, agrega una `transformation` a la entrada del mapeo. Se aplica al valor después de que llega al target.

| Tipo                | Qué hace                                    | Config                                         |
| ------------------- | ------------------------------------------- | ---------------------------------------------- |
| `remove_characters` | Elimina del texto los caracteres indicados. | `characters` — los caracteres que se eliminan. |
| `add_prefix`        | Pone texto delante del valor.               | `prefix` — el texto que se agrega.             |
| `add_suffix`        | Pone texto después del valor.               | `suffix` — el texto que se agrega.             |
| `to_uppercase`      | Convierte el texto a mayúsculas.            | —                                              |
| `to_lowercase`      | Convierte el texto a minúsculas.            | —                                              |

Estos cinco son todo el conjunto. Un `type` fuera de él se rechaza cuando guardas el workflow, con `FLK-0140`.

Dos reglas para escribirlas:

* Actúan sobre texto. Un valor que no es texto llega al target sin cambios.
* `prefix` y `suffix` necesitan al menos un carácter cada uno, y un solo espacio cuenta. `characters` necesita al menos un carácter que no sea un espacio, un tabulador ni un salto de línea. Un valor que no cumple esto falla el paso en tiempo de ejecución con `FLK-0504`.

<Accordion title="Ejemplo — normalizar un documento y sellar una referencia">
  ```json theme={null}
  {
    "inputMapping": [
      {
        "source": "workflow.customer.document",
        "target": "payer.document",
        "transformation": {
          "type": "remove_characters",
          "config": { "characters": ".-/" }
        }
      },
      {
        "source": "workflow.customer.name",
        "target": "payer.name",
        "transformation": { "type": "to_uppercase" }
      },
      {
        "source": "workflow.transactionId",
        "target": "payer.reference",
        "transformation": {
          "type": "add_prefix",
          "config": { "prefix": "BR-" }
        }
      }
    ]
  }
  ```

  A partir de `{"customer":{"document":"123.456.789-00","name":"ada lovelace"},"transactionId":"txn-98765"}`, el node envía:

  ```json theme={null}
  {
    "payer": {
      "document": "12345678900",
      "name": "ADA LOVELACE",
      "reference": "BR-txn-98765"
    }
  }
  ```
</Accordion>

### Transformaciones sobre todo el documento

Para el trabajo que el mapeo entrada por entrada no expresa — combinar dos campos, elegir el primer valor presente, rellenar un valor por defecto — declara un array `transforms`. Cada operación lee todo el contexto del workflow y escribe toda la capa.

Flowker acepta `shift` (mover o renombrar), `concat` (unir valores), `coalesce` (primer valor presente), `default` (rellenar una clave ausente), `extract` (subir un subárbol a la raíz), `delete` (eliminar una clave), `timestamp`, `uuid` y `pass`. Los cinco tipos de transformación de arriba también están disponibles aquí; como operaciones, reciben la ruta de destino en la spec como `path`.

<Accordion title="Ejemplo — un shift y un default en un mismo node">
  ```json theme={null}
  {
    "data": {
      "executorId": "http",
      "providerConfigId": "019c96a0-0ac0-7de9-9f53-9cf842a2ee5a",
      "transforms": [
        {
          "operation": "shift",
          "spec": {
            "reference": "workflow.transactionId",
            "payment.amount": "workflow.amount"
          }
        },
        { "operation": "default", "spec": { "channel": "web" } }
      ]
    }
  }
  ```

  El node envía:

  ```json theme={null}
  {
    "reference": "txn-98765",
    "payment": { "amount": 1500.00 },
    "channel": "web"
  }
  ```

  Una operación puede poner `require: true` para exigir que exista cada ruta que nombra su `spec`, igual que `required` funciona en una entrada de mapeo.
</Accordion>

<Note>
  `transforms` se ejecuta solo cuando el node no tiene `inputMapping`. Usa uno u otro en un mismo node, nunca ambos.
</Note>

## Paso 5: Lee la respuesta de vuelta

***

Los mapeos de salida extraen campos de la respuesta y los guardan en el contexto del workflow bajo el ID del node, para que los nodes posteriores lean nombres cortos y estables. Decláralos en un array `outputMapping` dentro del `data` del node, con los mismos cuatro campos de entrada que un mapeo de entrada.

Un `source` de salida es una ruta dentro del envoltorio de respuesta, no dentro del cuerpo de la respuesta:

| Ruta               | Lo que contiene                                                                                                                                                                                           |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status`           | El código de estado HTTP.                                                                                                                                                                                 |
| `status_text`      | La línea de estado HTTP, como `200 OK`.                                                                                                                                                                   |
| `url`              | La URL que Flowker pidió, con la query string que armó.                                                                                                                                                   |
| `headers`          | Los encabezados de la respuesta, como objeto clave-valor bajo sus nombres canónicos, como `Content-Type`. Un encabezado que el servicio envió más de una vez llega como un solo valor separado por comas. |
| `body`             | El cuerpo de la respuesta, interpretado cuando la respuesta es `application/json` o un tipo XML — `application/xml`, `text/xml`, o un tipo cuyo nombre termina en `+xml`.                                 |
| `raw_body`         | La respuesta tal como llegó, como texto. Presente en una respuesta XML.                                                                                                                                   |
| `body_format`      | Vale `xml` cuando se decodificó un cuerpo XML.                                                                                                                                                            |
| `body_parse_error` | Aparece en lugar de `body` cuando un cuerpo XML no se pudo decodificar, para que el workflow pueda ramificar ante eso.                                                                                    |

Por eso los campos de la respuesta están bajo `body`:

```json theme={null}
{
  "outputMapping": [
    { "source": "body.score", "target": "score" },
    { "source": "body.decision", "target": "decision" },
    { "source": "status", "target": "httpStatus" }
  ]
}
```

En un node cuyo ID es `score-transaction`, eso guarda:

```json theme={null}
{ "score": 42, "decision": "review", "httpStatus": 200 }
```

Los nodes posteriores leen entonces `${score-transaction.score}` y `${score-transaction.httpStatus}`.

Un node que no declara `outputMapping` guarda todo el envoltorio bajo su ID, y los nodes posteriores leen la ruta del envoltorio directamente: `${score-transaction.body.score}`. Agrega un mapeo de salida cuando quieras el nombre corto; omítelo cuando la ruta del envoltorio sea suficientemente clara.

Un source de salida que no selecciona nada se comporta como uno de entrada: el target se guarda como `null`, salvo que una entrada de ese node ponga `required: true`.

## Paso 6: Revisa el mapeo antes de llamar al servicio

***

[Previsualizar la solicitud de un executor](/es/reference/flowker/preview-executor-request) arma la solicitud que enviaría un node y te la devuelve. Ejecuta el mismo armado de mapeos, transformaciones y autenticación que ejecuta una ejecución real, y nunca abre una conexión con el servicio, así que puedes iterar sobre un mapeo sin que salga una sola llamada de tu despliegue. Ninguna credencial aparece en lo que devuelve, ni siquiera en el `curl`.

Envía el node, la configuración de provider a la que apunta y un payload de muestra. La configuración de provider va en la propia solicitud, así que la previsualización no depende de nada más que de lo que envías:

```json theme={null}
POST /v1/workflows/preview-request

{
  "node": {
    "executorId": "http",
    "method": "POST",
    "path": "/score-transaction",
    "inputMapping": [
      {
        "source": "workflow.customer.document",
        "target": "payer.document",
        "transformation": {
          "type": "remove_characters",
          "config": { "characters": ".-/" }
        }
      },
      {
        "source": "workflow.customer.name",
        "target": "payer.name",
        "transformation": { "type": "to_uppercase" }
      },
      {
        "source": "workflow.transactionId",
        "target": "payer.reference",
        "transformation": {
          "type": "add_prefix",
          "config": { "prefix": "BR-" }
        }
      }
    ]
  },
  "providerConfig": {
    "providerId": "http",
    "config": { "base_url": "https://api.fraudshield.example.com" },
    "allowedHosts": ["api.fraudshield.example.com"]
  },
  "sampleInput": {
    "transactionId": "txn-98765",
    "customer": { "document": "123.456.789-00", "name": "ada lovelace" }
  }
}
```

Tu `sampleInput` se convierte en el payload del trigger, así que los source del mapeo lo leen como `workflow.*`, exactamente como lo harán en tiempo de ejecución.

La respuesta es la solicitud armada:

```json theme={null}
{
  "method": "POST",
  "url": "https://api.fraudshield.example.com/score-transaction",
  "headers": { "Content-Type": "application/json" },
  "body": "{\"payer\":{\"document\":\"12345678900\",\"name\":\"ADA LOVELACE\",\"reference\":\"BR-txn-98765\"}}",
  "curl": "curl -X POST -H 'Content-Type: application/json' --data '{\"payer\":{\"document\":\"12345678900\",\"name\":\"ADA LOVELACE\",\"reference\":\"BR-txn-98765\"}}' 'https://api.fraudshield.example.com/score-transaction'",
  "unresolved": []
}
```

Cada transformación se resolvió: el documento perdió la puntuación, el nombre está en mayúsculas y la referencia lleva su prefijo — y ninguna llamada llegó al servicio.

Lee la respuesta en este orden:

<Steps>
  <Step title="Revisa la URL">
    Es la URL base de la configuración de provider más el `path` del node. Una ruta que no esperabas es un campo del node por corregir, no un mapeo.
  </Step>

  <Step title="Revisa el cuerpo contra los nombres de campo que espera el servicio">
    Cada `target` debe aparecer donde el servicio lo quiere. Un campo con `null` es una ruta `source` que no selecciona nada.
  </Step>

  <Step title="Revisa `unresolved`">
    Lista las referencias `${...}` de los campos de plantilla del node que tu payload de muestra no resolvió. Quedan literales en la solicitud armada. Un array vacío significa que cada referencia encontró un valor.
  </Step>
</Steps>

Para revisar además los campos fijos de un node contra el esquema del executor del catálogo, llama a [Validar la configuración de un node](/es/reference/flowker/validate-executor-config) con la configuración del node en `config` y, en `mappedTargets`, las rutas de target que aporta tu `inputMapping`. Flowker las cuenta como satisfechas, así que un node que mapea un campo requerido desde el trigger pasa la revisión.

## Qué puede salir mal

***

| Síntoma                                            | Causa                                                                                                       | Solución                                                                                                                              |
| -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| El servicio recibe un campo con valor `null`.      | La ruta `source` está ausente del contexto del workflow.                                                    | Compara la ruta con el cuerpo armado de una previsualización. Pon `required: true` en el node cuando no deba ejecutarse sin el valor. |
| El servicio recibe un objeto anidado que no pidió. | El `target` lleva un prefijo.                                                                               | Escribe el target exactamente como lo espera el servicio. Un target `executor.accountId` envía un objeto `executor`.                  |
| El cuerpo de la solicitud está vacío.              | El node no tiene `data.body`, ni mapeo, ni `transforms`, y su `config` solo contiene nombres de transporte. | Agrega los valores como literales de `config` o como entradas de mapeo.                                                               |
| Los mapeos parecen ignorarse.                      | El node lleva también `data.body`, que es la única fuente del cuerpo mientras está presente.                | Elimina `data.body` para que los mapeos armen el cuerpo.                                                                              |
| `transforms` parece ignorarse.                     | El node tiene al menos una entrada en `inputMapping`.                                                       | Elimina las entradas de `inputMapping`, o mueve la lógica a ellas.                                                                    |
| Un node posterior no lee nada.                     | La referencia no nombra al node que produce el valor.                                                       | Lee `${<nodeId>.<target>}`. No existe un espacio de nombres compartido de primer nivel.                                               |
| Un mapeo de salida guarda `null`.                  | El `source` omite el prefijo del envoltorio.                                                                | Mapea `body.score`, no `score`.                                                                                                       |

| Código de error | Cuándo                         | Qué significa                                                                                                                                                                                                                  |
| --------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `FLK-0140`      | Al crear, actualizar o activar | El `inputMapping` del node no forma una spec válida — con más frecuencia, un `transformation.type` fuera de los cinco tipos admitidos.                                                                                         |
| `FLK-0141`      | Al crear, actualizar o activar | Lo mismo, para el `outputMapping` del node.                                                                                                                                                                                    |
| `FLK-0142`      | Al crear, actualizar o activar | Lo mismo, para los `transforms` del node.                                                                                                                                                                                      |
| `FLK-0143`      | En ejecución                   | Una referencia `${...}` del `data.body` del node no se resuelve contra el contexto del workflow. El node falla sin llamar al servicio.                                                                                         |
| `FLK-0504`      | En ejecución                   | El node falló. El mensaje del paso nombra la etapa: `input transformation failed` para un source requerido ausente o una transformación que no pudo ejecutarse, y `output transformation failed` para el lado de la respuesta. |

Consulta la [lista de errores de Flowker](/es/reference/flowker/flowker-error-list) para ver todos los códigos.

## Qué sigue

***

<CardGroup cols={2}>
  <Card title="Guía de integración" icon="plug" href="/es/flowker/integration-guide">
    Crea la configuración de provider por la que llama un node y define su autenticación.
  </Card>

  <Card title="Configurar un trigger de webhook" icon="webhook" href="/es/flowker/configuring-a-webhook-trigger">
    Elige el contrato de payload que llena el espacio de nombres `workflow` que leen tus mapeos.
  </Card>
</CardGroup>
