Osy#betaRun it on Osyrin: osyrin.com

Reference / HTTP

Calling other services

Every outbound HTTP call goes through `Http.*` — `Http.Get`/`Post`/`Put`/`Delete` take the URL as a value and hand back an `HttpResponse` you branch on, so a non-2xx is a value, not a throw. For a known API — a payment API, an exchange-rate feed, a shipping tracker — wrap those calls in an ordinary class with one typed method per endpoint; `osy import-api` writes that class from an OpenAPI document.

stablehttpintegrationguide

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#

Related

a typed HTTP client (a class over Http.*)

A typed HTTP client is an **ordinary class** that wraps an external API: a `BaseUrl` field, a credential field, one…

Http.*

Make an outbound HTTP call to a URL you build at runtime — a webhook, a third-party API, a discovered endpoint…

HttpResponse

The result of an `Http.*` call. Carries the HTTP status code, the body as text AND as bytes, every response header, and…

declaring secrets (app.Secrets)

`app.Secrets` declares the named secrets your app uses — API keys, tokens, client secrets. Each is `new…

OAuth clients (app.OAuthClients)

`app.OAuthClients` declares the third-party OAuth providers your app uses — for signing users in (Login), for…