Wrestling with ureq's approach to errors

ureq (an http client) has an... unorthodox approach to errors. Requests return Response objects right away, and to query for (non-http) errors one must use:

pub fn synthetic_error(&self) -> &Option<ureq::Error>

on the Response object.

I want to take that ureq::Error object out and place it in my own error struct, something like this:

if let Some(err) = response.synthetic_error() {
    return Err(MyErrorStruct::UreqError(err));
}

But try as I might, I can't get that Error from inside &Option<Error>. I have ownership of the Response object, and I can consume it at this point for the error.

Their error type also doesn't implement Clone.

What can I do to get the error out of that reference?
Minimal example here (won't compile on the playground, doesn't have that crate).

What I did was take the status and status_text responses returned from synthetic_error and transplant them into my own error type, like:

let resp = ureq::get(source).call();
match resp.synthetic_error() {
    None => {
        let reader = resp.into_reader();
        // do stuff with reader
        Ok(())
    }
    Some(err) => Err(Error::Ureq {
        status: err.status(),
        text: err.status_text().to_string(),
    }),
}

so I could take ownership of the error code and response text and display them properly if necessary.

A bit of a shame doing it that way though, because you lose the structure of its error type, and some of those errors are recoverable for my use-case.

I guess I'll either just fork it and make the error field accessible, or switch to a different library altogether (one with a more convencional approach to error handling).

Though overkill for my use case, I'd be interested in a ureq fork with proper, idiomatic error handling. Rust has a lot of HTTP client options, but many of them are in rough shape.

Yeah, I was going by that article as well. In addition to my issue with the errors, I also dislike ureq's decision to combine setting a message body with executing the request (i.e., there's no .set_body(..).send(), only a method to do both in one shot), which complicates a few things we're trying to do.

I decided to switch to attohttpc, I'm really liking its API design and the maintainers implemented support for timeouts, rustls, and more since the article came out.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.