Ir al contenido

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.

Todas las actividades devuelven un objeto ZoanHttpResponse con:

PropiedadTipoDescripción
.StatusCodeintCódigo HTTP final de la respuesta (200, 201, 204…). Si hubo redirecciones, es el de la última.
.Okbooltrue 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.
.BodyobjectEl 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.
.HeadersDictionaryLas cabeceras de la respuesta (nombre → valor, ambos texto).
HTTP GET url = "https://api.ejemplo.com/clientes/42" → output: resp
Log message = "Nombre: " + resp.Body["nombre"]
  • Si la cabecera Content-Type de la respuesta contiene application/json y el cuerpo no está vacío, se interpreta como JSON: un objeto pasa a diccionario, un arreglo a lista, y los valores a string, 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, .Body es el texto completo de la respuesta: úsalo con str(resp.Body) o pásalo a XML, Write File, etc. Un cuerpo vacío (por ejemplo, en un 204) 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.

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"].

Respuesta del servidorResultado
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.Message

Para fallos transitorios (red inestable, 429, 503) usa Retry alrededor de la petición; ante un 400 o un 404, reintentar no cambia el resultado.

LímiteValorConfigurable
Establecer la conexión con el servidor30 sNo
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.Message

Terminar 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.

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):

TipoQué pones en el campo authorizationQué 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.

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: resp

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.

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).

contentTypeQué 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.

ActividadTipoSalidaQué hace
HTTP GEThttp-getZoanHttpResponseLee/consulta datos de una URL
HTTP DELETEhttp-deleteZoanHttpResponseElimina un recurso
ActividadTipoSalidaQué hace
HTTP POSThttp-postZoanHttpResponseCrea un recurso o envía datos
HTTP PUThttp-putZoanHttpResponseReemplaza un recurso completo
HTTP PATCHhttp-patchZoanHttpResponseActualiza parcialmente un recurso