Qué significa “encadenar requests” en un flujo end-to-end
Encadenar requests es construir un flujo donde la salida de una llamada (IDs, tokens, estados, timestamps) se convierte en la entrada de la siguiente. En Postman esto se logra principalmente con: (1) extracción de datos desde la respuesta (JSON) y guardado en variables, (2) orden y control de ejecución dentro de una colección, y (3) validaciones y condiciones para decidir si continuar, reintentar o limpiar datos.
En un flujo real, no basta con “llamar endpoints”: necesitas controlar dependencias (por ejemplo, no puedes actualizar un usuario si no tienes su userId), manejar estados (si ya existe, no lo vuelvas a crear) y asegurar limpieza (borrar lo creado para que el entorno quede consistente).
Flujo de negocio del capítulo: alta de usuario y gestión de sesión
Diseñaremos un flujo completo típico de QA: crear un usuario, iniciar sesión, consultar perfil, actualizar datos y finalmente eliminar el usuario (y cerrar sesión si aplica). Este patrón se usa para pruebas end-to-end repetibles.
Diagrama textual del flujo (pasos, variables y validaciones)
0) (Opcional) Buscar usuario por email (para idempotencia) -> si existe, capturar userId y saltar creación o limpiar antes de crear. Variables: email, userId. Validación: 200 con lista/objeto o 404/[] si no existe. 1) Crear usuario (POST /users) -> extraer userId. Variables: userId. Validación: 201, schema mínimo, userId no vacío. 2) Login (POST /auth/login) -> extraer accessToken y refreshToken. Variables: accessToken, refreshToken. Validación: 200, token presente, expiración coherente. 3) Consultar perfil (GET /users/{userId}) -> comparar email y estado. Variables: userId, accessToken. Validación: 200, email coincide, status=ACTIVE. 4) Actualizar usuario (PATCH /users/{userId}) -> extraer updatedAt o version. Variables: updatedAt/version. Validación: 200, campo actualizado. 5) Eliminar usuario (DELETE /users/{userId}) -> confirmar eliminación. Variables: userId. Validación: 204/200. 6) Verificación post-borrado (GET /users/{userId}) -> debe fallar o devolver 404. Validación: 404 o indicador de no existencia. 7) (Opcional) Logout (POST /auth/logout) -> invalidar token. Variables: refreshToken/accessToken. Validación: 204/200.Variables involucradas (tabla rápida)
| Variable | Tipo | Origen | Uso |
|---|---|---|---|
baseUrl | environment | config | Host de la API |
email | collection/environment | dato de prueba | Identificador funcional del usuario |
password | collection/environment | dato de prueba | Login |
userId | collection | respuesta de creación/búsqueda | Path param en GET/PATCH/DELETE |
accessToken | collection | respuesta de login | Header Authorization |
refreshToken | collection | respuesta de login | Logout/refresh |
retryCount | collection | control interno | Reintentos ante condiciones transitorias |
flowStep | collection | control interno | Depuración/seguimiento del flujo |
Guía práctica: construir el encadenamiento en una colección
1) Estructura recomendada de la colección
- Folder:
E2E - Usuario y Sesión - Requests en orden:
Buscar usuario→Crear usuario→Login→Get perfil→Actualizar usuario→Eliminar usuario→Verificar borrado→Logout - Variables de colección: para datos generados en runtime (
userId,accessToken), evitando “ensuciar” el environment compartido.
El orden se controla desde el Collection Runner o Newman. Si necesitas saltos condicionales, se controlan con postman.setNextRequest() en scripts de tests.
2) Request: Buscar usuario por email (idempotencia)
Objetivo: si el usuario ya existe, decidir si reutilizarlo o eliminarlo antes de crear uno nuevo. Esto evita fallos por “email duplicado” y hace el flujo repetible.
- Escuche el audio con la pantalla apagada.
- Obtenga un certificado al finalizar.
- ¡Más de 5000 cursos para que explores!
Descargar la aplicación
Ejemplo: GET {{baseUrl}}/users?email={{email}}
Extracción con JSONPath (si la API devuelve lista):
// Tests tab (Buscar usuario) const json = pm.response.json(); // Caso A: devuelve array de usuarios [{id,...}] const existingId = pm.jsonPath(json, "$[0].id"); if (existingId) { pm.collectionVariables.set("userId", existingId); pm.collectionVariables.set("flowStep", "user_exists"); // Decide estrategia: saltar creación y seguir a login, o limpiar y recrear. // Opción 1: reutilizar y saltar a Login postman.setNextRequest("Login"); } else { pm.collectionVariables.unset("userId"); pm.collectionVariables.set("flowStep", "user_not_found"); postman.setNextRequest("Crear usuario"); }Acceso directo al JSON (si devuelve objeto con items):
// Tests tab (Buscar usuario) const json = pm.response.json(); const first = json.items && json.items.length ? json.items[0] : null; if (first && first.id) { pm.collectionVariables.set("userId", first.id); postman.setNextRequest("Login"); } else { postman.setNextRequest("Crear usuario"); }Punto de validación: no solo “status 200”. Valida que el formato sea el esperado para poder decidir. Si el endpoint devuelve 404 cuando no existe, adapta la condición usando pm.response.code.
3) Request: Crear usuario y guardar el ID
Ejemplo: POST {{baseUrl}}/users con body JSON (mínimo):
{ "email": "{{email}}", "password": "{{password}}", "name": "QA User" }Extraer userId con JSONPath:
// Tests tab (Crear usuario) const json = pm.response.json(); const userId = pm.jsonPath(json, "$.id") || pm.jsonPath(json, "$.data.id"); if (!userId) { throw new Error("No se pudo extraer userId de la respuesta"); } pm.collectionVariables.set("userId", userId); pm.collectionVariables.set("flowStep", "user_created"); // Continuar al login postman.setNextRequest("Login");Limpieza de datos: si la creación falla por duplicado (409), puedes decidir ir a “Buscar usuario” o “Eliminar usuario” según tu estrategia. Ejemplo de control:
// Tests tab (Crear usuario) if (pm.response.code === 409) { // Conflicto: ya existe. Reintenta el flujo de búsqueda y decide. postman.setNextRequest("Buscar usuario"); }4) Request: Login y almacenamiento de tokens
Ejemplo: POST {{baseUrl}}/auth/login con:
{ "email": "{{email}}", "password": "{{password}}" }Extraer tokens:
// Tests tab (Login) const json = pm.response.json(); const accessToken = pm.jsonPath(json, "$.accessToken") || pm.jsonPath(json, "$.data.accessToken"); const refreshToken = pm.jsonPath(json, "$.refreshToken") || pm.jsonPath(json, "$.data.refreshToken"); if (!accessToken) { throw new Error("Login sin accessToken"); } pm.collectionVariables.set("accessToken", accessToken); if (refreshToken) pm.collectionVariables.set("refreshToken", refreshToken); pm.collectionVariables.set("flowStep", "logged_in"); postman.setNextRequest("Get perfil");Dependencia clave: a partir de aquí, todas las requests protegidas deben usar Authorization. En cada request subsiguiente, configura el header:
Authorization: Bearer {{accessToken}}5) Request: Consultar perfil (GET) usando variables
Ejemplo: GET {{baseUrl}}/users/{{userId}}
Validaciones orientadas al flujo (puntos de control):
- El
userIdusado en la URL existe (variable no vacía). - El email del perfil coincide con
{{email}}. - El estado del usuario es el esperado para continuar (por ejemplo
ACTIVE).
// Tests tab (Get perfil) const userId = pm.collectionVariables.get("userId"); if (!userId) throw new Error("userId no definido antes de Get perfil"); const json = pm.response.json(); const email = pm.jsonPath(json, "$.email") || pm.jsonPath(json, "$.data.email"); pm.expect(email).to.eql(pm.collectionVariables.get("email")); const status = pm.jsonPath(json, "$.status") || pm.jsonPath(json, "$.data.status"); if (status && status !== "ACTIVE") { // Si el negocio requiere ACTIVE, decide: reintentar o abortar. throw new Error("Usuario no está ACTIVE: " + status); } pm.collectionVariables.set("flowStep", "profile_ok"); postman.setNextRequest("Actualizar usuario");6) Request: Actualizar usuario (PATCH) y confirmar cambios
Ejemplo: PATCH {{baseUrl}}/users/{{userId}}
{ "name": "QA User Updated" }Extraer un marcador de actualización (version/updatedAt) y validar el campo:
// Tests tab (Actualizar usuario) const json = pm.response.json(); const newName = pm.jsonPath(json, "$.name") || pm.jsonPath(json, "$.data.name"); pm.expect(newName).to.eql("QA User Updated"); const updatedAt = pm.jsonPath(json, "$.updatedAt") || pm.jsonPath(json, "$.data.updatedAt"); if (updatedAt) pm.collectionVariables.set("updatedAt", updatedAt); pm.collectionVariables.set("flowStep", "user_updated"); postman.setNextRequest("Eliminar usuario");7) Request: Eliminar usuario y limpiar variables
Ejemplo: DELETE {{baseUrl}}/users/{{userId}}
En flujos end-to-end, la eliminación es parte de la higiene del entorno. Además, conviene limpiar variables sensibles o que ya no deben reutilizarse.
// Tests tab (Eliminar usuario) if (![200, 202, 204].includes(pm.response.code)) { throw new Error("Fallo al eliminar usuario. Code=" + pm.response.code); } pm.collectionVariables.set("flowStep", "user_deleted"); // Mantén userId para verificar borrado y luego límpialo postman.setNextRequest("Verificar borrado");8) Request: Verificar borrado (control de condición “no existe”)
Ejemplo: GET {{baseUrl}}/users/{{userId}}
Este paso valida el resultado final del flujo. La condición esperada suele ser 404 o una respuesta que indique no existencia.
// Tests tab (Verificar borrado) if (pm.response.code !== 404) { // Algunas APIs devuelven 200 con flag deleted=true; adapta según contrato. const json = pm.response.json(); const deleted = pm.jsonPath(json, "$.deleted") || pm.jsonPath(json, "$.data.deleted"); if (!deleted) { throw new Error("Se esperaba 404 o deleted=true tras borrar"); } } // Limpieza final de variables del recurso pm.collectionVariables.unset("userId"); pm.collectionVariables.unset("updatedAt"); pm.collectionVariables.set("flowStep", "delete_verified"); postman.setNextRequest("Logout");9) Request: Logout (opcional) y limpieza de tokens
Ejemplo: POST {{baseUrl}}/auth/logout (según API) con refresh token o access token.
// Tests tab (Logout) if (![200, 204].includes(pm.response.code)) { // Si tu API no implementa logout real, puedes omitir este paso. } pm.collectionVariables.unset("accessToken"); pm.collectionVariables.unset("refreshToken"); pm.collectionVariables.set("flowStep", "logged_out");Manejo de dependencias: orden, condiciones, limpieza y reintentos
Orden: cuándo usar setNextRequest vs. orden fijo
- Orden fijo: ideal cuando el flujo siempre es el mismo (crear → login → operar → borrar).
- Saltos condicionales con
postman.setNextRequest(): necesarios cuando hay bifurcaciones (si existe/no existe, si token expiró, si el recurso está en estado inválido).
Regla práctica: usa orden fijo para el “camino feliz” y setNextRequest solo para decisiones inevitables (idempotencia, recuperación, limpieza).
Limpieza de datos: patrón “siempre borrar lo que creas”
Para evitar contaminación del entorno, aplica estas tácticas:
- Guardar IDs de todo recurso creado (no solo del usuario; también direcciones, sesiones, etc.).
- Eliminar en cascada en orden inverso a la creación (primero dependencias, luego el recurso padre).
- Limpiar variables al final (o cuando un paso falla) para no reutilizar valores obsoletos.
Si necesitas garantizar limpieza incluso cuando un request falla, una estrategia es tener un request “Cleanup” que intente borrar si existe userId y luego se ejecute como ruta alternativa cuando detectas error en pasos intermedios.
Reintentos: manejar consistencia eventual y fallos transitorios
En APIs con consistencia eventual, puede ocurrir que justo después de crear, el GET todavía no “vea” el recurso. En ese caso, implementa reintentos controlados con contador y espera.
// Tests tab (Get perfil) - ejemplo de reintento simple const maxRetries = 3; const retryCount = parseInt(pm.collectionVariables.get("retryCount") || "0", 10); if (pm.response.code === 404 && retryCount < maxRetries) { pm.collectionVariables.set("retryCount", String(retryCount + 1)); // Espera corta (bloqueante) para demo; úsala con cuidado en suites grandes const waitMs = 500; const start = Date.now(); while (Date.now() - start < waitMs) {} postman.setNextRequest("Get perfil"); } else { pm.collectionVariables.unset("retryCount"); if (pm.response.code === 404) throw new Error("Perfil no disponible tras reintentos"); postman.setNextRequest("Actualizar usuario"); }Notas prácticas: (1) limita reintentos para no crear loops infinitos, (2) registra retryCount para depuración, (3) reintenta solo en códigos esperables (404 temporal, 429, 503) y no en errores de validación (400).
Control de condiciones: “si existe/no existe” y “si está autorizado/no autorizado”
Dos condiciones típicas en flujos end-to-end:
- Recurso existe: decide entre reutilizar, actualizar, o borrar y recrear. Esto se resuelve en el paso “Buscar usuario”.
- Token inválido: si un GET devuelve 401, decide si reloguear o abortar. En un flujo de sesión, puedes redirigir a “Login” si aún tienes credenciales.
// Tests tab (Get perfil) - ejemplo de control 401 if (pm.response.code === 401) { // Token expirado o inválido: intenta reloguear una vez const relogged = pm.collectionVariables.get("relogged"); if (!relogged) { pm.collectionVariables.set("relogged", "true"); postman.setNextRequest("Login"); } else { pm.collectionVariables.unset("relogged"); throw new Error("No autorizado incluso tras relogin"); } } else { pm.collectionVariables.unset("relogged"); }Checklist de puntos de validación del flujo (para detectar roturas reales)
- Creación: se obtiene
userIdy no es nulo/vacío. - Login: se obtiene
accessTokeny se puede usar en requests protegidas. - Lectura: el perfil coincide con el usuario creado/buscado (email).
- Actualización: el campo modificado se refleja en la respuesta (y/o en un GET posterior si tu API no devuelve el recurso actualizado).
- Eliminación: el recurso deja de existir (404 o flag equivalente).
- Limpieza: variables sensibles (
accessToken) y de recursos (userId) se eliminan al final.