//// 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 external type Request external type Response /// Exception returned by Finch in case of request errors. pub external 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 fn build_ext( method: Method, url: String, headers: Headers, body: String, opts: RequestOptions, ) -> Request = "Elixir.Finch" "build" /// 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 fn do_request(req: Request, name: Atom) -> Result(Response, Exception) = "Elixir.Finch" "request" /// Stream a request using the Finch instance with the given name. pub external fn stream( req: Request, name: Atom, acc: a, fun: StreamFun(a), opts: RequestOptions, ) -> Result(a, Exception) = "Elixir.Finch" "stream" /// Start a new Finch instance with the given options. pub external fn start_link(opts: InstanceOptions) -> OnStart = "Elixir.Finch" "start_link" 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 fn get_response_body(resp: Response, key: ResponseBodyKey) -> String = "Elixir.Map" "fetch!" external fn get_response_status(resp: Response, key: ResponseStatusKey) -> Int = "Elixir.Map" "fetch!" external fn get_response_headers( resp: Response, key: ResponseHeadersKey, ) -> Headers = "Elixir.Map" "fetch!"