Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-httpclient

Named HTTP clients for Pudu: a client factory, delegating handlers, pooled keep-alive connections, handler lifetimes, logging, and resilience

0.1.1Apache-2.01

InstallClose

SharedClient.pudu

Pudu60 lines2.5 KB

GitHub ↗
1/** @Examples.SharedClient.Program — one client configured once and used from several places */2module SharedClient34import Std.Concurrent as Concurrent5import Std.Http.Server.Reply as Reply6import Std.Http.Server.Route as Route7import Std.Http.Server as Server8import Std.Io as Io9import Std.Result as Result10import PuduLangHttpClient.Client as Client11import PuduLangHttpClient.Content as Content12import PuduLangHttpClient as HttpClient13import PuduLangHttpClient.Response as Response14import PuduLangHttpClient.Transport as Transport1516/** @Examples.SharedClient.Catalog — a part of the program that reads the catalog */17type Catalog = { http: Client.Client }1819/** @Examples.SharedClient.Orders — another part that places orders through the same client */20type Orders = { http: Client.Client }2122/// The catalog's items.23fn items(catalog: &Catalog) -> HttpClient.Outcome[Str] { Client.getText(&catalog.http, "items") }2425/// The status of placing an order.26fn place(orders: &Orders, sku: Str) -> HttpClient.Outcome[Int] {27  Result.map(Client.post(&orders.http, "orders", Content.plain(sku)), |response: Response.Response| response.status.code)28}2930/// Starts a local shop and answers its address.31fn serve() -> (Server.Running, Str) {32  let running = match Server.start("127.0.0.1", 0) {33    case Ok(found) => found34    case Err(problem) => panic(show(problem))35  }36  let server = Server.server(&Route.routing(&[37        Route.get("/items", |_request: Route.Request| Reply.text(200, "tea,cake")),38        Route.post("/orders", |_request: Route.Request| Reply.text(201, "placed"))39      ]))40  let _serving = Concurrent.start(fn() -> () { let _ran = Server.run(&server, &running, 0) })41  (running, "http://127.0.0.1:" + show(Server.portOf(&running)) + "/")42}4344/// Configures one client at startup, hands it to two parts of the program, and answers 0 when both45/// were served over one kept-alive connection.46fn main() -> Int {47  let (running, base) = serve()48  let transport = Transport.create(Transport.defaults().withPooledConnectionLifetime(120000).withMaxConnectionsPerServer(16))49  let http = Client.over(&transport).withBaseAddress(base).withDefaultHeader("user-agent", "shop/1.0").withTimeout(10000)50  let catalog = Catalog{http: http}51  let orders = Orders{http: http}52  let listed = items(&catalog)53  let placed = place(&orders, "tea")54  let stats = Transport.statistics(&transport)55  let _said = Io.writeLine(show(listed) + " " + show(placed) + " over " + show(stats.opened) + " connection")56  Transport.close(&transport)57  let _stopped = Server.stop(&running)58  if listed == Ok("tea,cake") && placed == Ok(201) && stats.opened == 1 { 0 } else { 1 }59}60