///|
struct Reader[T](async () -> T?)

///|
pub fn[T] Reader::new(f : async () -> T?) -> Reader[T] {
  Reader(f)
}

///|
pub async fn[T] Reader::read(self : Reader[T]) -> T? {
  (self.0)()
}

///|
pub struct Response {
  status_code : Int
  reason_phrase : String
  headers : Array[String]
  body : Reader[String]
}

///|
pub fn Response::new(
  status_code~ : Int,
  reason_phrase~ : String,
  headers~ : Array[String],
  body~ : Reader[String],
) -> Response {
  { status_code, reason_phrase, headers, body }
}

///|
pub(all) enum HttpMethod {
  Post
}

///|
pub(open) trait HttpClient {
  async fetch(
    self : Self,
    url~ : String,
    method_~ : HttpMethod,
    headers~ : Map[String, String],
    body~ : String,
  ) -> Response
}