-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Description
I raised this question on the chat, but I think it's worth a proper issue to discuss options…
Current situation and pain points
Currently, to be notified of an error response we need to either:
- Check the
.status_codemanually:
if response.status_code == 404:
print("Not found")
if response.is_error:
print("Error")- Call
.raise_for_status():
response.raise_for_status() # Raises an HTTPErrorThis is mostly in line with what Requests does, but I'd argue we can do better.
In particular, there's a very basic use case we could address better: make a request, then handle any 4xx/5xx.
There are mostly two ways to do this currently:
- Inspect the
.status_code:
import httpx
r = httpx.get("https://httpbin.org/status/500")
if r.status_code == 500:
...- Call
.raise_for_status()to get a properHTTPError:
import httpx
def fetch(url):
r = httpx.get(url)
r.raise_for_status()
return r
try:
r = fetch("https://httpbin.org/status/500")
except httpx.HTTPError as exc:
if exc.response.status_code == 500:
...I think we can argue this looks somewhat clunky. It forces the user to add a .raise_for_status() line basically everywhere — probably as a wrapper around an HTTPX call — otherwise they'd start processing responses they think are valid, when they're actually errors.
Possible future situation
What if request methods automatically raised an HTTPError if we get an error response? Sounds sensible?
import httpx
try:
r = httpx.get("https://httpbin.org/status/500")
except httpx.HTTPError as exc:
print(exc.response.status_code)
# Deal with 500...This would allow users to have to think about error handling, as they'd be getting HTTPError exceptions thrown at them when hosts aren't able to satisfy the request. We can also easily add a "manual mode" without breaking backwards compat after 1.0…
Planning
If we think this is reasonable, the way I'd see us implement this is:
- Switch to raise an error as the default behavior before 1.0.
- This would be done via a
raise_for_status=Trueflag, probably on the client constructor at first. - Switch the docs to document the new default behavior, and document
raise_for_status=False+response.raise_for_status/response.is_erroras a more low-level/manual way of handling things. - Later on (i.e. after 1.0), we could extend this to allow a
Callable[[int], bool]too, allowing to do things likeraise_for_status=lambda s: 500 <= s < 600so that 4xx error responses don't raise anHTTPError. (Sounds fancy, but I can see this feature request turning up at some point.)