diff --git a/src/apkallone.gleam b/src/apkallone.gleam index e40b731..1532117 100644 --- a/src/apkallone.gleam +++ b/src/apkallone.gleam @@ -10,6 +10,8 @@ pub type Client { pub type Error { BadInstance FetchError(error: Dynamic) - ResponseError(status: Int) + UnexpectedStatus(status: Int) + UnexpectedContentType(content_type: String) + MissingContentType DecodeError(error: DecodeError) } diff --git a/src/apkallone/internal.gleam b/src/apkallone/internal.gleam index f039caa..e18e0e4 100644 --- a/src/apkallone/internal.gleam +++ b/src/apkallone/internal.gleam @@ -3,7 +3,9 @@ import gleam/http/request.{type Request} import gleam/http/response.{type Response} import gleam/httpc import gleam/json +import gleam/pair import gleam/result +import gleam/string import apkallone.{type Client, type Error} @@ -22,14 +24,14 @@ pub fn prepare_request( } pub fn send_request(req: Request(String)) -> Result(Response(String), Error) { - use req <- result.try( + use res <- result.try( httpc.send(req) |> result.map_error(apkallone.FetchError), ) - case req.status { - 200 -> Ok(req) - other -> Error(apkallone.ResponseError(other)) + case res.status { + 200 -> Ok(res) + other -> Error(apkallone.UnexpectedStatus(other)) } } @@ -37,7 +39,30 @@ pub fn decode_response( res: Response(String), decoder: Decoder(a), ) -> Result(a, Error) { + use <- require_content_type(res, "application/json") + res.body |> json.decode(decoder) |> result.map_error(apkallone.DecodeError) } + +fn require_content_type( + res: Response(String), + expected_type: String, + fun: fn() -> Result(a, Error), +) -> Result(a, Error) { + use actual_type <- result.try( + response.get_header(res, "content-type") + |> result.replace_error(apkallone.MissingContentType), + ) + + let actual_type = + string.split_once(actual_type, on: ";") + |> result.map(pair.first) + |> result.unwrap(or: actual_type) + + case actual_type == expected_type { + True -> fun() + False -> Error(apkallone.UnexpectedContentType(actual_type)) + } +}