http-rs / surf

Fast and friendly HTTP client framework for async Rust
https://docs.rs/surf
Apache License 2.0
1.46k stars 119 forks source link

status code handling question #173

Open rbtcollins opened 4 years ago

rbtcollins commented 4 years ago

I would ask this in chat but see #172 :/

recv_json seems to not check req.status for either is_success or for ==200. I'll happily grant that there are cases where API servers send some sort of sum type back Enum { Success(IP), Failure(ErrorDescription) }

(and that Enum, Success and Failure are all invisible on the wire and just made up to talk about this).

Anyhow, point is I grant that we might want to get JSON back in both success and error cases, but it is probably not the same JSON; Even if it is via the use of a Sum type, thats not always possible, because some API servers throw plain text errors.

And then you get the truely bad cases, where the error documents look the same as the success documents, and the only hint is that the results are not as long as one expected plus the HTTP status code is actually set to something useful.

So I guess my question is this: is there some way, for my paranoia to let me actually have surf check that the result was 200 before it parses the JSON, or do I have to forgo the convenience methods and write my own equivalents that check for HTTP status?

Also - it would be super super super helpful if the docs made clear which methods in surf take shortcuts like this and which don't. I'm not criticising the choice - I can see the pragmatism of 'if it deserialises, it is good data, and that way users don't need to deal with a whole class of errors'... but on the other hand, it can already throw, so :shrug:

bbigras commented 3 years ago

I have a similar case. I get JSON errors but I'm pretty sure I'm actually getting "429 Too Many Requests".

goto-bus-stop commented 3 years ago

recv_json is a shorthand for

client.send(req).await?
    .body_json().await?

So you can do this by executing those two functions:

let mut res = client.send(req).await?;
if res.status() != StatusCode::Ok {
  return an error
}
let deserialized = res.body_json().await?;

It would def be helpful to note this in docs for the recv_* methods.

bbigras commented 3 years ago

Oh nice, thanks!