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

Request.pudu

Pudu121 lines5.1 KB

GitHub ↗
1/** @HttpClient.Request.Module — what a client sends, built before anything is sent */2module PuduLangHttpClient.Request34import Std.Http as Http5import PuduLangHttpClient.Content as Content6import PuduLangHttpClient.Domain.Headers as Headers7import PuduLangHttpClient.Domain.Version as Version8import PuduLangHttpClient.Options as Options910/** @HttpClient.Request.Receiver — takes each piece of a streamed body; `false` stops reading */11export type Receiver = fn(Bytes) -> Bool1213/** @HttpClient.Request.Request — a method, an address, headers, an optional body, and options */14export type Request = {15  method: Http.Method,16  uri: Str,17  version: Http.Version,18  versionPolicy: Version.Policy,19  headers: Array[(Str, Str)],20  content: Option[Content.Content],21  options: Options.Options,22  receiver: Option[Receiver]23}2425/// A request with a method and an address, sent as HTTP/1.1 or lower, with nothing else.26export fn create(method: Http.Method, uri: Str) -> Request {27  Request {28    method: method,29    uri: uri,30    version: Http.Http11,31    versionPolicy: Version.OrLower,32    headers: [],33    content: None,34    options: Options.empty(),35    receiver: None36  }37}3839/// A `GET` request.40export fn get(uri: Str) -> Request { create(Http.Get, uri) }4142/// A `HEAD` request.43export fn head(uri: Str) -> Request { create(Http.Head, uri) }4445/// A `DELETE` request.46export fn delete(uri: Str) -> Request { create(Http.Delete, uri) }4748/// A `POST` request carrying a body.49export fn post(uri: Str, content: Content.Content) -> Request { Request{..create(Http.Post, uri), content: Some(content)} }5051/// A `PUT` request carrying a body.52export fn put(uri: Str, content: Content.Content) -> Request { Request{..create(Http.Put, uri), content: Some(content)} }5354/// A `PATCH` request carrying a body.55export fn patch(uri: Str, content: Content.Content) -> Request { Request{..create(Http.Patch, uri), content: Some(content)} }5657/// The first value of a header, among the request's own headers and then its body's.58export fn header(request: &Request, name: Str) -> Option[Str] {59  match Headers.get(&request.headers, name) {60    case Some(found) => Some(found)61    case None => {62      let content = request.content ?63      Headers.get(&content.headers, name)64    }65  }66}6768/// The value of an option, when it is set.69export fn option[T](request: &Request, name: &Options.Key[T]) -> Option[T] { Options.get(&request.options, name) }7071/** @HttpClient.Request.Shaping — a request changed one decision at a time */72export trait Shaping {73  /// The request with a header value added after any the name has.74  fn withHeader(self: &Self, name: Str, value: Str) -> Self75  /// The request with every value of a header replaced by one.76  fn setHeader(self: &Self, name: Str, value: Str) -> Self77  /// The request without a header.78  fn removeHeader(self: &Self, name: Str) -> Self79  /// The request carrying a body.80  fn withContent(self: &Self, content: Content.Content) -> Self81  /// The request sent with a protocol version under a policy.82  fn withVersion(self: &Self, version: Http.Version, policy: Version.Policy) -> Self83  /// The request carrying an option for its handlers.84  fn withOption[T](self: &Self, name: &Options.Key[T], value: T) -> Self85  /// The request whose body is handed to a receiver as it arrives instead of being buffered.86  fn withReceiver(self: &Self, receiver: Receiver) -> Self87  /// The request authorized with a bearer token.88  fn withBearer(self: &Self, token: Str) -> Self89  /// The request asking for a media type.90  fn accepting(self: &Self, mediaType: Str) -> Self91}9293impl Shaping for Request {94  /// The request with a header value added after any the name has.95  fn withHeader(self: &Self, name: Str, value: Str) -> Self { Request{..*self, headers: Headers.add(&self.headers, name, value)} }9697  /// The request with every value of a header replaced by one.98  fn setHeader(self: &Self, name: Str, value: Str) -> Self { Request{..*self, headers: Headers.set(&self.headers, name, value)} }99100  /// The request without a header.101  fn removeHeader(self: &Self, name: Str) -> Self { Request{..*self, headers: Headers.remove(&self.headers, name)} }102103  /// The request carrying a body.104  fn withContent(self: &Self, content: Content.Content) -> Self { Request{..*self, content: Some(content)} }105106  /// The request sent with a protocol version under a policy.107  fn withVersion(self: &Self, version: Http.Version, policy: Version.Policy) -> Self { Request{..*self, version: version, versionPolicy: policy} }108109  /// The request carrying an option for its handlers.110  fn withOption[T](self: &Self, name: &Options.Key[T], value: T) -> Self { Request{..*self, options: Options.set(&self.options, name, value)} }111112  /// The request whose body is handed to a receiver as it arrives instead of being buffered.113  fn withReceiver(self: &Self, receiver: Receiver) -> Self { Request{..*self, receiver: Some(receiver)} }114115  /// The request authorized with a bearer token.116  fn withBearer(self: &Self, token: Str) -> Self { self.setHeader("authorization", Http.bearerAuth(token)) }117118  /// The request asking for a media type.119  fn accepting(self: &Self, mediaType: Str) -> Self { self.withHeader("accept", mediaType) }120}121