~/bend-docscommunity

client.bend source

client.bend on the hub · documented module

# ezhttp/client: fetch a URL. URL and HTTP parsing joined to the wire effect.# Answers a structured Response (status + headers + body), not a hub-style# "0\n…" string contract.import Baseimport ./url.bend as Urlimport ./http.bend as Httpimport ./body.bend as Bodyimport ./wire.bend as Wireimport ./b64.bend as B64# structured client result: transport/parse error, or an HTTP responsetype Response is Data:  Err{why: String}  Response{status: U32, headers: List<&2, Http.Header>, body: String}# transport status line: first line is a code, rest is the payloaddef wire.code(raw: String) -> Maybe<&2, U32>:  U32.read(Http.first(String.split(raw, '\n')))# text after the first newlinedef wire.text.of(c: Http.Cut) -> String:  match c:    case Http.NoCut{}:      ""    case Http.Cut{_before, after}:      afterdef wire.text(raw: String) -> String:  wire.text.of(Http.divide(raw, "\n"))# whether the wire status is success (0)def wire.ok.of(m: Maybe<&2, U32>) -> Bool:  match m:    case None{}:      False{}    case Some{n}:      U32.is_eq(n, 0)def wire.ok(raw: String) -> Bool:  wire.ok.of(wire.code(raw))# a torn or successful HTTP parse as a client Responsedef from.reply(r: Http.Reply) -> Response:  match r:    case Http.Torn{why}:      Err{why}    case Http.Reply{status, headers, body}:      Response{status, headers, body}# a finished exchangedef from.raw(raw: String, ok: Bool) -> Response:  match ok:    case False{}:      Err{wire.text(raw)}    case True{}:      from.reply(Http.parse(wire.text(raw)))# HTTP(S) exchange with a pre-built requestdef http.talk(secure: Bool, host: String, port: U32, req: String)  -> IO(Response):  do IO<Response>:    +raw : String <- Wire.wire.talk(secure, host, port, req)    IO.pure(Response, from.raw(raw, wire.ok(raw)))# a URL that came apart into an HTTP exchangedef http.loc(method: String, l: Url.Loc, headers: List<&2, Http.Header>,  body: String) -> IO(Response):  match l:    case Url.Bad{why}:      IO.pure(Response, Err{why})    case Url.Loc{+scheme, +host, port, path}:      http.talk(String.eq(scheme, "https"), host, port,        Http.request(method, host, path, headers, body))# GETdef client.get(url: String, headers: List<&2, Http.Header>) -> IO(Response):  http.loc("GET", Url.parse(url), headers, "")# HEAD (RFC 9110 §9.3.2)def client.head(url: String, headers: List<&2, Http.Header>) -> IO(Response):  http.loc("HEAD", Url.parse(url), headers, "")# POSTdef client.post(url: String, headers: List<&2, Http.Header>, body: Body.Body)  -> IO(Response):  http.loc("POST", Url.parse(url), headers, Body.body.payload(body))# PUTdef client.put(url: String, headers: List<&2, Http.Header>, body: Body.Body)  -> IO(Response):  http.loc("PUT", Url.parse(url), headers, Body.body.payload(body))# DELETEdef client.delete(url: String, headers: List<&2, Http.Header>, body: Body.Body)  -> IO(Response):  http.loc("DELETE", Url.parse(url), headers, Body.body.payload(body))# OPTIONSdef client.options(url: String, headers: List<&2, Http.Header>) -> IO(Response):  http.loc("OPTIONS", Url.parse(url), headers, "")# Authorization: Bearer …def client.bearer(token: String) -> Http.Header:  Http.H{"Authorization", "Bearer " ++ token}# Authorization: Basic … (RFC 7617, credentials are RFC 4648 Base64)def client.basic(user: String, password: String) -> Http.Header:  Http.H{"Authorization", "Basic " ++ B64.b64.encode(user ++ ":" ++ password)}