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

TypedClients.pudu

Pudu62 lines2.7 KB

GitHub ↗
1/** @Examples.TypedClients.Program — a typed client reading and writing JSON values */2module TypedClients34import 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.Json as Json10import Std.Option as Option11import PuduLangHttpClient.Client as Client12import PuduLangHttpClient.Client.Json as JsonClient13import PuduLangHttpClient.Factory.Builder as Builder14import PuduLangHttpClient.Factory as Factory15import PuduLangHttpClient as HttpClient16import PuduLangHttpClient.Response as Response1718/** @Examples.TypedClients.Todo — one item, written and read through derived implementations */19type Todo = { id: Int, title: Str, done: Bool } derives Json.Encode, Json.Decode2021/** @Examples.TypedClients.Todos — a typed client: the operations of one remote service */22type Todos = { client: Client.Client }2324/// The item with an identifier.25fn find(todos: &Todos, id: Int) -> HttpClient.Outcome[Todo] { JsonClient.getFromJson(&todos.client, "todos/" + show(id)) }2627/// The item as the service stored it.28fn add(todos: &Todos, todo: &Todo) -> HttpClient.Outcome[Todo] {29  let response = Response.ensureSuccess(JsonClient.postAsJson(&todos.client, "todos", todo) ?) ?30  Response.readAs(&response)31}3233/// Starts a local service of items and answers its address.34fn serve() -> (Server.Running, Str) {35  let running = match Server.start("127.0.0.1", 0) {36    case Ok(found) => found37    case Err(problem) => panic(show(problem))38  }39  let server = Server.server(&Route.routing(&[40        Route.get("/todos/:id", |request: Route.Request| Reply.json(200, "\{\"id\":" + Option.unwrapOr(Route.param(&request, "id"), "0") + ",\"title\":\"water the plants\",\"done\":false\}")),41        Route.post("/todos", |request: Route.Request| Reply.json(201, Route.body(&request)))42      ]))43  let _serving = Concurrent.start(fn() -> () { let _ran = Server.run(&server, &running, 0) })44  (running, "http://127.0.0.1:" + show(Server.portOf(&running)) + "/")45}4647/// Reads one item and adds another through a typed client, answering 0 when both round-trip.48fn main() -> Int {49  let (running, base) = serve()50  let factory = match Factory.build([Builder.named("todos").withBaseAddress(base)]) {51    case Ok(built) => built52    case Err(invalid) => panic(Factory.explain(&invalid))53  }54  let todos = Factory.typed(&factory, "todos", |client: Client.Client| Todos{client: client})55  let found = find(&todos, 7)56  let added = add(&todos, &Todo{id: 8, title: "write the docs", done: true})57  let _said = Io.writeLine(show(found) + "\n" + show(added))58  Factory.dispose(&factory)59  let _stopped = Server.stop(&running)60  if found == Ok(Todo{id: 7, title: "water the plants", done: false}) && added == Ok(Todo{id: 8, title: "write the docs", done: true}) { 0 } else { 1 }61}62