Skip to content

Allow to define what successful/unsuccessful response statuses are #467

@jozuas

Description

@jozuas

I find that Req response handling requires a lot of boilerplate to handle due to the fact that all HTTP statuses are returned in the form of {:ok, %Req.Response{status: some_http_status, ...}}. While from the perspective of the library, Req has done its job, from the perspective of a user using Req, a non-200 HTTP status is often a failure case.

Example illustrating the point that all HTTP statuses are returned as {:ok, ...}:

iex(tp@127.0.0.1)1> Req.post("https://httpbin.org/bearer")
{:ok,
 %Req.Response{
   status: 405,
   headers: %{
     "access-control-allow-credentials" => ["true"],
     "access-control-allow-origin" => ["*"],
     "allow" => ["GET, OPTIONS, HEAD"],
     "connection" => ["keep-alive"],
     "content-type" => ["text/html"],
     "date" => ["Wed, 12 Mar 2025 18:17:58 GMT"],
     "server" => ["gunicorn/19.9.0"]
   },
   body: "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n<title>405 Method Not Allowed</title>\n<h1>Method Not Allowed</h1>\n<p>The method is not allowed for the requested URL.</p>\n",
   trailers: %{},
   private: %{}
 }}

This means that when I write code, I generally have to have 3 branches of pattern matching for response handling:

case Req.post("https://httpbin.org/bearer") do
  {:ok, %Req.Response{status: 200, body: body}} -> 
    # I do something with the body
    {:ok, result}

  {:ok, %Req.Response{status: status, body: body}} ->
    # I have to rewrap this response
    {:error, "Super useful error message or Exception struct"}

  {:error, exception} ->
    {:error, exception}
end

Now, if Req allowed to specify what the expected success status(es) are, this could end up being as simple as:

with {:ok, %Req.Response{status: 200, body: body}} <- Req.post("https://httpbin.org/bearer", success_http_codes: [200]) do
  # I do something with the body
end

Assuming that Req.post("https://httpbin.org/bearer", success_http_codes: [200]) would now return something like{:error, %Req.HTTPError{status: 405, body: body}}.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions