HTTP Activities
Versión: 1.0.5 · ID: zoan-packages-http · Autor: Zoan Software
El paquete HTTP permite que tu automatización consuma APIs y servicios web (REST): consultar datos de un sistema, enviar información, integrar dos aplicaciones que se comunican por API. Es la forma más robusta y rápida de integrarse con un sistema cuando este ofrece una API — más fiable que automatizar su interfaz con el navegador.
La respuesta: ZoanHttpResponse
Sección titulada «La respuesta: ZoanHttpResponse»Todas las actividades devuelven un objeto ZoanHttpResponse con:
| Propiedad | Tipo | Descripción |
|---|---|---|
.StatusCode | int | Código HTTP final de la respuesta (200, 201, 204…). Si hubo redirecciones, es el de la última. |
.Ok | bool | true si el código es 2xx. Como cualquier otro código hace fallar la actividad (ver abajo), en una salida que llegas a recibir siempre vale true. |
.Body | object | El cuerpo de la respuesta. Si es JSON, se convierte automáticamente en diccionario/lista, listo para leer con ["clave"] e [índice]. Si no, es el texto tal cual. |
.Headers | Dictionary | Las cabeceras de la respuesta (nombre → valor, ambos texto). |
HTTP GET url = "https://api.ejemplo.com/clientes/42" → output: respLog message = "Nombre: " + resp.Body["nombre"]Cómo se interpreta el cuerpo (.Body)
Sección titulada «Cómo se interpreta el cuerpo (.Body)»- Si la cabecera
Content-Typede la respuesta contieneapplication/jsony el cuerpo no está vacío, se interpreta como JSON: un objeto pasa a diccionario, un arreglo a lista, y los valores astring,bool, entero (long) o decimal (double). Puedes navegar en profundidad:resp.Body["data"]["items"][0]["id"]. - Navegar es seguro: una clave que no existe o un índice fuera de rango devuelve un valor vacío en lugar de fallar. Compruébalo con
resp.Body["campo"].IsNull, o usa.ContainsKey("campo"),.Count,.Keys,.IsObject/.IsArray. - Si el servidor no declara JSON (por ejemplo
text/plain,text/xml,text/html), o el JSON viene mal formado,.Bodyes el texto completo de la respuesta: úsalo constr(resp.Body)o pásalo a XML, Write File, etc. Un cuerpo vacío (por ejemplo, en un204) es el texto"". - El cuerpo siempre se lee como texto: estas actividades están pensadas para APIs que responden datos (JSON, XML, texto), no para descargar archivos binarios.
Cabeceras de la respuesta (.Headers)
Sección titulada «Cabeceras de la respuesta (.Headers)»Reúne las cabeceras generales y las de contenido. Si una cabecera trae varios valores, llegan unidos por ", ". Las claves distinguen mayúsculas: usa la forma habitual, por ejemplo resp.Headers["Content-Type"].
Qué códigos hacen fallar la actividad
Sección titulada «Qué códigos hacen fallar la actividad»| Respuesta del servidor | Resultado |
|---|---|
| 2xx (200, 201, 202, 204…) | La actividad termina bien y entrega el ZoanHttpResponse. En el log queda Solicitud GET completada: HTTP 200. |
| 3xx de redirección (301, 302, 307, 308) | Se siguen automáticamente y recibes la respuesta final. Una redirección de HTTPS a HTTP no se sigue. |
| Cualquier otro código (304, 4xx, 5xx) | La actividad falla con El servidor respondió HTTP 404 (Not Found) a la solicitud GET. El mensaje lleva el código, su descripción y el método; no incluye el cuerpo de la respuesta de error. |
| Sin respuesta (DNS, conexión rechazada, certificado TLS inválido) | La actividad falla con el error del sistema (tipo HttpRequestException), por ejemplo No such host is known. |
Cuando una respuesta de error es esperable (y quieres manejarla, no detenerte), envuelve la petición en un Try / Catch. En la variable de error, .Message trae el texto de arriba y .Type distingue un fallo de red ("HttpRequestException") de una respuesta con código de error:
Try / Catch errorVariable = error ├─ try: │ HTTP GET url = "https://api.ejemplo.com/clientes/" + id → output: resp │ ... usar resp.Body ... └─ catch: If condition = error.Message.Contains("HTTP 404") ├─ then: │ Log level = warning message = "El cliente " + id + " no existe" └─ else: Throw message = "La API falló: " + error.MessagePara fallos transitorios (red inestable, 429, 503) usa Retry alrededor de la petición; ante un 400 o un 404, reintentar no cambia el resultado.
Tiempos de espera
Sección titulada «Tiempos de espera»| Límite | Valor | Configurable |
|---|---|---|
| Establecer la conexión con el servidor | 30 s | No |
| Petición completa (conectar, enviar y recibir la respuesta) | 300 s (5 min) | Sí, con el parámetro timeout (segundos, hasta 3600) |
Desde la versión 1.0.5, cuando se agota alguno de estos límites la actividad falla con un error normal de tipo TimeoutException, con un mensaje que dice qué pasó:
La solicitud GET a api.ejemplo.com no terminó en 300 s (tiempo de espera agotado). Sube «Tiempo de espera» si el servicio tarda más.No se pudo conectar con api.ejemplo.com en 30 s para la solicitud GET (tiempo de conexión agotado). Revisa la dirección y que el servidor esté disponible.
Ese error lo capturan Try / Catch (error.Type es "TimeoutException") y Retry, igual que un fallo de red:
Try / Catch errorVariable = error ├─ try: │ Retry attempts = 3 delay = 5000 │ └─ body: │ HTTP GET url = "https://api.ejemplo.com/reportes/" + id timeout = 60 → output: resp └─ catch: If condition = error.Type == "TimeoutException" ├─ then: │ Log level = warning message = "La API no respondió: " + error.Message └─ else: Throw message = error.MessageTerminar la ejecución desde Zoan Cloud o el Designer sigue cortando la petición en curso al instante, y eso no lo captura Try / Catch: la ejecución acaba como cancelada.
Otros detalles del envío:
- Las peticiones salen de la máquina donde corre el robot y usan la configuración de proxy de Windows.
- Se envía la cabecera
User-Agent: Zoan-Automation/1.0. - Las conexiones se reutilizan entre peticiones, así que llamar muchas veces a la misma API es eficiente.
Autenticación
Sección titulada «Autenticación»La mayoría de las APIs requieren autenticación. El parámetro authorization la configura — es un campo de tipo JSON donde indicas el tipo y sus datos. Hay tres tipos soportados (type no distingue mayúsculas):
| Tipo | Qué pones en el campo authorization | Qué se envía |
|---|---|---|
| Bearer (token) | { "type": "bearer", "token": "..." } | Authorization: Bearer <token> |
| Basic (usuario/clave) | { "type": "basic", "username": "...", "password": "..." } | Authorization: Basic <base64(usuario:clave)> (en UTF-8) |
| API Key | { "type": "apikey", "header": "X-API-Key", "value": "..." } | La cabecera header con el valor value. Si omites header, se usa X-API-Key. |
Si falta el dato principal (token en bearer, value en apikey) o el type no es uno de los tres, no se envía autenticación: la API responderá 401 y la actividad fallará con ese código. Si la API pide la clave en la URL (?api_key=...), ponla directamente en la url.
Token OAuth 2.0 (client credentials)
Sección titulada «Token OAuth 2.0 (client credentials)»Muchas APIs entregan un token temporal a cambio de un client_id y un client_secret. Pídelo con un POST y úsalo como bearer en las peticiones siguientes:
HTTP POST url = "https://auth.ejemplo.com/oauth/token" contentType = "application/x-www-form-urlencoded" body = "grant_type=client_credentials&client_id=" + clientId + "&client_secret=" + credential("api-erp")["value"] → output: tokenResp
HTTP GET url = "https://api.ejemplo.com/facturas?estado=pendiente" authorization = { "type": "bearer", "token": tokenResp.Body["access_token"] } → output: respCabeceras (headers)
Sección titulada «Cabeceras (headers)»El parámetro headers es otro campo JSON: un diccionario de cabeceras extra a enviar (nombre → valor). Los valores que no son texto se convierten a texto.
headers = { "Accept": "application/json", "X-Origen": "zoan-bot" }Las cabeceras de contenido (Content-Type, Content-Length, Content-Encoding…) no se pueden poner aquí: se ignoran sin aviso. El tipo de contenido se indica con el parámetro contentType de POST, PUT y PATCH. Si pones Authorization en headers y además usas authorization de tipo bearer o basic, prevalece authorization.
Cuerpo (body) y Content-Type
Sección titulada «Cuerpo (body) y Content-Type»En POST, PUT y PATCH envías un cuerpo (body). El contentType por defecto es application/json, y el cuerpo siempre se codifica en UTF-8 (charset=utf-8 se agrega solo).
contentType | Qué se envía |
|---|---|
Contiene application/json (por defecto) | El body convertido a JSON: un diccionario → objeto, una lista → arreglo, un número/booleano/texto → ese valor JSON. |
Cualquier otro (text/plain, text/xml, application/x-www-form-urlencoded…) | El body como texto, tal cual. Tú armas el formato (XML, formulario codificado…). |
body = new Dictionary<string, object> { ["nombre"] = nombreCliente, ["nit"] = nit }contentType debe ser solo el tipo de medio (application/json, text/xml): si le agregas parámetros como ; charset=utf-8, la actividad falla.
Actividades
Sección titulada «Actividades»Leer y eliminar (sin cuerpo)
Sección titulada «Leer y eliminar (sin cuerpo)»| Actividad | Tipo | Salida | Qué hace |
|---|---|---|---|
| HTTP GET | http-get | ZoanHttpResponse | Lee/consulta datos de una URL |
| HTTP DELETE | http-delete | ZoanHttpResponse | Elimina un recurso |
Crear y actualizar (con cuerpo)
Sección titulada «Crear y actualizar (con cuerpo)»| Actividad | Tipo | Salida | Qué hace |
|---|---|---|---|
| HTTP POST | http-post | ZoanHttpResponse | Crea un recurso o envía datos |
| HTTP PUT | http-put | ZoanHttpResponse | Reemplaza un recurso completo |
| HTTP PATCH | http-patch | ZoanHttpResponse | Actualiza parcialmente un recurso |
Siguientes pasos
Sección titulada «Siguientes pasos»- HTTP GET — la petición más común.
- Tipos de datos › ZoanHttpResponse — leer la respuesta.
- Uso de credenciales — autenticar de forma segura.