//// Finch API wrapper module. //// //// See the [Finch documentation](https://hexdocs.pm/finch) for additional //// information about the functions. import gleam/result import gleam import gleam/uri import gleam/erlang/atom.{Atom} import gleam/http import gleam/http/request as gleam_request import gleam/http/response as gleam_response import finch/headers.{Headers} import finch/stream.{StreamFun} import finch/otp.{InstanceOptions, OnStart} // Finch's HTTP method type type Method { Head Get Put Post Patch Delete Options } pub type RequestOption { PoolTimeout(ms: Int) RequestTimeout(ms: Int) } pub type RequestOptions = List(RequestOption) /// Finch request, use `build/2` to create one from a Gleam request. pub type Request type Response /// Exception returned by Finch in case of request errors. pub type Exception /// Build a Finch request that can be run with `request/2` or `stream/5`. /// /// Note, the HTTP methods CONNECT, TRACE, and `Other(String)` are not /// supported, and will be converted to GET. pub fn build( req: gleam_request.Request(String), opts: RequestOptions, ) -> Request { let url_str = req |> gleam_request.to_uri() |> uri.to_string() build_ext( gleam_method_to_finch_method(req.method), url_str, req.headers, req.body, opts, ) } @external(erlang, "Elixir.Finch", "build") fn build_ext( method method: Method, url url: String, headers headers: Headers, body body: String, opts opts: RequestOptions, ) -> Request /// Send a request using the Finch instance with the given name. pub fn request( req: Request, name: Atom, ) -> Result(gleam_response.Response(String), Exception) { use resp <- result.then(do_request(req, name)) gleam.Ok(gleam_response.Response( body: response_body(resp), headers: response_headers(resp), status: response_status(resp), )) } @external(erlang, "Elixir.Finch", "request") fn do_request(req req: Request, name name: Atom) -> Result(Response, Exception) /// Stream a request using the Finch instance with the given name. @external(erlang, "Elixir.Finch", "stream") pub fn stream( req req: Request, name name: Atom, acc acc: a, fun fun: StreamFun(a), opts opts: RequestOptions, ) -> Result(a, Exception) /// Start a new Finch instance with the given options. @external(erlang, "Elixir.Finch", "start_link") pub fn start_link(opts opts: InstanceOptions) -> OnStart fn response_body(resp: Response) -> String { get_response_body(resp, Body) } fn response_headers(resp: Response) -> Headers { get_response_headers(resp, Headers) } fn response_status(resp: Response) -> Int { get_response_status(resp, Status) } fn gleam_method_to_finch_method(method: http.Method) -> Method { case method { http.Get -> Get http.Head -> Head http.Post -> Post http.Put -> Put http.Patch -> Patch http.Delete -> Delete http.Options -> Options _other -> Get } } type ResponseBodyKey { Body } type ResponseHeadersKey { Headers } type ResponseStatusKey { Status } @external(erlang, "Elixir.Map", "fetch!") fn get_response_body(resp resp: Response, key key: ResponseBodyKey) -> String @external(erlang, "Elixir.Map", "fetch!") fn get_response_status(resp resp: Response, key key: ResponseStatusKey) -> Int @external(erlang, "Elixir.Map", "fetch!") fn get_response_headers( resp resp: Response, key key: ResponseHeadersKey, ) -> Headers