|
| 1 | +# Helper Methods |
| 2 | + |
| 3 | +Standalone functions you call directly — no `UiPath` instance, no service class. |
| 4 | + |
| 5 | +- **`httpRequest`** calls any URL, with optional retries, backoff, and a per-attempt timeout. It |
| 6 | + sends no UiPath authentication and adds no UiPath headers, so it is for third-party endpoints — |
| 7 | + use the SDK's service methods for UiPath itself. |
| 8 | +- **`wait`** pauses for a duration, useful between calls you are pacing yourself. |
| 9 | + |
| 10 | +## Error contract |
| 11 | + |
| 12 | +Because it proxies arbitrary third-party calls, `httpRequest` follows a different contract from the |
| 13 | +SDK's service methods. |
| 14 | + |
| 15 | +**A status the server returned is never an exception.** A 404 or a 500 comes back as a resolved |
| 16 | +response with `ok: false` — branch on the status rather than catching: |
| 17 | + |
| 18 | +```typescript |
| 19 | +import { httpRequest } from '@uipath/uipath-typescript/core'; |
| 20 | + |
| 21 | +const response = await httpRequest('https://api.example.com/v1/orders'); |
| 22 | + |
| 23 | +if (response.ok) { |
| 24 | + console.log(response.data); |
| 25 | +} else { |
| 26 | + console.log('Request failed with status', response.status); |
| 27 | +} |
| 28 | +``` |
| 29 | + |
| 30 | +**`data` is `unknown`.** The body is whatever the server sent — the shape you expect on a success, |
| 31 | +an error payload on a 4xx or 5xx, and nothing at all on a 204. Give it a type once you know which |
| 32 | +you have: |
| 33 | + |
| 34 | +```typescript |
| 35 | +if (response.ok) { |
| 36 | + const order = response.data as { id: string }; |
| 37 | + console.log(order.id); |
| 38 | +} |
| 39 | +``` |
| 40 | + |
| 41 | +**A request that never produced a response still throws.** DNS failures, refused connections, |
| 42 | +a timeout, and caller cancellation all surface as a `NetworkError`: |
| 43 | + |
| 44 | +```typescript |
| 45 | +import { httpRequest, NetworkError } from '@uipath/uipath-typescript/core'; |
| 46 | + |
| 47 | +try { |
| 48 | + await httpRequest('https://api.example.com/v1/orders', { timeoutMs: 5000 }); |
| 49 | +} catch (error) { |
| 50 | + if (error instanceof NetworkError) { |
| 51 | + console.log('The request never reached the server:', error.message); |
| 52 | + } |
| 53 | +} |
| 54 | +``` |
| 55 | + |
| 56 | +One other case throws: asking for `responseType: 'json'` explicitly when the body does not parse |
| 57 | +raises a `ServerError`. Without an explicit `responseType`, an unparseable body is returned as raw |
| 58 | +text instead — auto-detection is a guess, and a host can label an HTML error page as JSON. |
| 59 | + |
| 60 | +## Retries and backoff |
| 61 | + |
| 62 | +The idempotent methods — `GET`, `HEAD`, `PUT`, `DELETE`, `OPTIONS`, per RFC 9110 — are retried up |
| 63 | +to twice by default on a transient failure: a transport error, or a `408`, `429`, `500`, `502`, |
| 64 | +`503`, or `504`. `POST` and `PATCH` are not retried, since a replayed `POST` can create the same |
| 65 | +resource twice. Pass `retry` to change any of that: |
| 66 | + |
| 67 | +```typescript |
| 68 | +const response = await httpRequest('https://api.example.com/v1/orders', { |
| 69 | + method: 'POST', |
| 70 | + body: { sku: 'ABC-123' }, |
| 71 | + timeoutMs: 10000, // bounds one attempt; each retry gets a fresh timeout |
| 72 | + retry: { |
| 73 | + maxRetries: 4, |
| 74 | + initialDelayMs: 1000, // the first delay; later ones grow from it |
| 75 | + backoffStrategy: 'exponential', // 1s, 2s, 4s, 8s |
| 76 | + backoffFactor: 2, |
| 77 | + backoffMaxDelayMs: 30000, |
| 78 | + retryMethods: ['GET', 'HEAD', 'POST'] |
| 79 | + } |
| 80 | +}); |
| 81 | +``` |
| 82 | + |
| 83 | +`backoffStrategy` controls how the delay grows, given an `initialDelayMs` of `d` and a `backoffFactor` of `f`: |
| 84 | + |
| 85 | +| Strategy | Delays | |
| 86 | +|---|---| |
| 87 | +| `constant` | `d, d, d, …` | |
| 88 | +| `linear` | `d, 2d, 3d, …` | |
| 89 | +| `exponential` (default) | `d, d×f, d×f², …` | |
| 90 | + |
| 91 | +`backoffFactor` applies only to `exponential`; the other strategies ignore it. Every computed delay |
| 92 | +is capped at `backoffMaxDelayMs`. |
| 93 | + |
| 94 | +A `Retry-After` response header overrides the computed delay unless `respectRetryAfter` is `false`. |
| 95 | +It is honoured as the server sent it — `backoffMaxDelayMs` does not apply to it — so set |
| 96 | +`maxRetryAfterMs` if you need a ceiling on how long a server can ask you to wait. |
| 97 | + |
| 98 | +Set `retryNetworkErrors: false` to retry only on response status codes, leaving connection |
| 99 | +failures, DNS errors, and timeouts to fail on the first attempt. |
| 100 | + |
| 101 | +`timeoutMs` sits outside `retry` deliberately — it bounds a single attempt whether or not |
| 102 | +retrying is enabled, so a call that just needs a deadline does not have to open a bag of retry |
| 103 | +options to get one: |
| 104 | + |
| 105 | +```typescript |
| 106 | +// one attempt, five second ceiling, no retrying involved |
| 107 | +const response = await httpRequest('https://api.example.com/v1/orders', { timeoutMs: 5000 }); |
| 108 | +``` |
| 109 | + |
| 110 | +Two cases never retry, regardless of settings: a `ReadableStream` body (it is consumed by the first |
| 111 | +attempt and cannot be replayed) and a request cancelled through `signal`. |
| 112 | + |
| 113 | +Use `wait` to pause between calls of your own: |
| 114 | + |
| 115 | +```typescript |
| 116 | +import { wait } from '@uipath/uipath-typescript/core'; |
| 117 | + |
| 118 | +await wait(1000); // milliseconds |
| 119 | +``` |
0 commit comments