Summary#
When your app has to reach out to another service — a payment API, an exchange-rate feed, a shipping tracker, a
webhook — every call is made with the Http.* Http.*. What changes is how much you wrap it:
- A specific, known API → a typed a typed HTTP client (a class over Http.*): an ordinary class whose methods are the API's endpoints, so every call site is type-checked.
- A URL built at runtime (a webhook target stored on a record) → call
Http.*directly.
Either way the result is an HttpResponse, and a non-2xx status is an ordinary value you branch on — not an exception you have to catch.
Description#
A typed client for a known API#
A a typed HTTP client (a class over Http.*) is the one to reach for when you're integrating a specific, known API. It is an ordinary class: a
BaseUrl field, a credential field, one public method per endpoint (TrackResult Track(string code)), and a small
private Get/Post that calls Http.* and turns a non-2xx into a thrown error. The results are typed, so a call site
that expects the wrong shape is a compile error, not a 4am surprise. osy import-api <spec> generates exactly this
class from an OpenAPI document. Full shape and examples on a typed HTTP client (a class over Http.*).
There is no retry at the transport: a call worth retrying is a durable step with a Backoff
policy on it.
The facade for a runtime URL#
When the URL isn't knowable until runtime — a webhook target stored on a record, an endpoint you just discovered —
use the Http.*. Http.Get/Post/Put/Delete take the URL as a value and return an HttpResponse, so
a webhook call is var res = Http.Post(webhookUrl, body); and you branch on res.IsSuccess.
The response is a value, not a throw#
An HttpResponse carries the status code, the body as text, and an IsSuccess flag (true for 2xx). A non-2xx —
a 404, a 500, a rate-limit 429 — is a normal return you inspect, not an exception. That is deliberate: an outbound
call fails in ordinary, expected ways, and forcing every one through a try/catch would be noise. You branch on the
status the same way you'd branch on any other value.
Credentials belong in secrets#
An API key or client secret an outbound call needs is declared as a secret, never inlined. For signing users in through a third party, or calling an API on a user's behalf, see OAuth clients (app.OAuthClients).
See also#
- a typed HTTP client (a class over Http.*) — a typed client: an ordinary class over
Http.*, one method per endpoint - Backoff (retry policy) — retrying an outbound call, as a durable step with a retry policy
- Http.* —
Http.*for a URL built at runtime - HttpResponse — the status / body /
IsSuccessresult you branch on - declaring secrets (app.Secrets) — where an API key lives; OAuth clients (app.OAuthClients) — third-party sign-in and delegated calls