
Response.pudu
Pudu98 lines4.0 KB
1/** @HttpClient.Response.Module — what came back, and the request that produced it */2module PuduLangHttpClient.Response34import Std.Http as Http5import Std.Json as Json6import PuduLangHttpClient.Content as Content7import PuduLangHttpClient.Domain.Headers as Headers8import PuduLangHttpClient.Domain.RetryAfter as RetryAfter9import PuduLangHttpClient as HttpClient10import PuduLangHttpClient.Request as Request1112/** @HttpClient.Response.Response — a status, headers, a body, trailers, and the final request */13export type Response = {14 status: Http.Status,15 version: Http.Version,16 headers: Array[(Str, Str)],17 content: Content.Content,18 trailers: Array[(Str, Str)],19 request: Request.Request20}212223export fn answer(request: &Request.Request, code: Int) -> Response {24 Response{status: Http.status(code), version: Http.Http11, headers: [], content: Content.empty(), trailers: [], request: *request}25}262728export fn isSuccess(response: &Response) -> Bool { Http.isSuccess(&response.status) }293031export fn ensureSuccess(response: Response) -> HttpClient.Outcome[Response] {32 if isSuccess(&response) { Ok(response) } else { Err(HttpClient.Unsuccessful(response.status.code, response.status.reason)) }33}343536export fn header(response: &Response, name: Str) -> Option[Str] {37 match Headers.get(&response.headers, name) {38 case Some(found) => Some(found)39 case None => Headers.get(&response.content.headers, name)40 }41}424344export fn headerValues(response: &Response, name: Str) -> Array[Str] {45 Headers.values(&response.headers, name).concat(Headers.values(&response.content.headers, name))46}474849export fn text(response: &Response) -> HttpClient.Outcome[Str] { Content.readText(&response.content) }505152export fn bytes(response: &Response) -> Bytes { response.content.payload }535455export fn json(response: &Response) -> HttpClient.Outcome[Json.Json] { Content.readJson(&response.content) }565758export fn readAs[T: Json.Decode](response: &Response) -> HttpClient.Outcome[T] { Content.readAs(&response.content) }59606162export fn retryAfter(response: &Response, now: Int) -> Option[Int] {63 let value = header(response, "retry-after") ?64 RetryAfter.delay(value, now)65}6667/** @HttpClient.Response.Answering — a response built one decision at a time, for stubs and tests */68export trait Answering {69 70 fn withHeader(self: &Self, name: Str, value: Str) -> Self71 72 fn withContent(self: &Self, content: Content.Content) -> Self73 74 fn withText(self: &Self, body: Str) -> Self75 76 fn withJson(self: &Self, value: &Json.Json) -> Self77}7879impl Answering for Response {80 81 fn withHeader(self: &Self, name: Str, value: Str) -> Self {82 if Headers.isContentHeader(name) {83 Response{..*self, content: Content.Content{..self.content, headers: Headers.add(&self.content.headers, name, value)}}84 } else {85 Response{..*self, headers: Headers.add(&self.headers, name, value)}86 }87 }8889 90 fn withContent(self: &Self, content: Content.Content) -> Self { Response{..*self, content: content} }9192 93 fn withText(self: &Self, body: Str) -> Self { self.withContent(Content.plain(body)) }9495 96 fn withJson(self: &Self, value: &Json.Json) -> Self { self.withContent(Content.json(value)) }97}98