Reputation: 5534
I'm trying to implement std::io::Write
over HTTP and I'm not sure how to handle errors that do not have a counterpart in std::io::ErrorKind
.
Here's a short reproduction:
extern crate reqwest;
use std::io::Write;
use std::io::Result;
struct HttpClient {
// Some configurations (compression, certificates, timeouts)
}
impl Write for HttpClient {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
let client = ::reqwest::Client::builder().build()?;
let res = client.post("http://httpbin.org/post").body(buf).send()?;
Ok(buf.len())
}
fn flush(&mut self) -> Result<()> {
Ok(())
}
}
The compiler responds with 2 errors:
error[E0277]: the trait bound `std::io::Error: std::convert::From<reqwest::Error>` is not satisfied
--> src/main.rs:12:22
|
12 | let client = ::reqwest::Client::builder().build()?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<reqwest::Error>` is not implemented for `std::io::Error`
|
= help: the following implementations were found:
<std::io::Error as std::convert::From<std::io::ErrorKind>>
<std::io::Error as std::convert::From<std::ffi::NulError>>
<std::io::Error as std::convert::From<std::io::IntoInnerError<W>>>
<std::io::Error as std::convert::From<serde_json::error::Error>>
<std::io::Error as std::convert::From<openssl::error::ErrorStack>>
= note: required by `std::convert::From::from`
error[E0277]: the trait bound `std::io::Error: std::convert::From<reqwest::Error>` is not satisfied
--> src/main.rs:13:19
|
13 | let res = client.post("http://httpbin.org/post").body(buf).send()?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<reqwest::Error>` is not implemented for `std::io::Error`
|
= help: the following implementations were found:
<std::io::Error as std::convert::From<std::io::ErrorKind>>
<std::io::Error as std::convert::From<std::ffi::NulError>>
<std::io::Error as std::convert::From<std::io::IntoInnerError<W>>>
<std::io::Error as std::convert::From<serde_json::error::Error>>
<std::io::Error as std::convert::From<openssl::error::ErrorStack>>
= note: required by `std::convert::From::from`
There's a couple of things I could do, but I'm not happy with either of them:
Use map_err
to map reqwest::Error
to std::io::Error
- This is not always trivial. For example, how would I map TooManyRedirects
? I could use std::io::ErrorKind::Other
but it doesn't feel right.
Define my own error type MyError
and implement std::convert::From
for reqwest::Error
to MyError
and for MyError
to std::io::Error
- This raises the same concerns from before - not all errors are easily convertible.
Are there any other better options here?
Upvotes: 0
Views: 615
Reputation: 431139
Using io::Error
is the only thing you can do because that's the contract that the trait requires. Everything else just boils down to details and ergonomics.
io::Error::new
accepts an io::ErrorKind
and something that can be converted into an error::Error
.
I'd probably write a function that transforms your domain error into a io::Error
by calling io::Error::new
and then use this new function in map_err
everywhere. I'd start by cramming everything into ErrorKind::Other
until I found a reason that a specific Reqwest error should be something else.
Will your consumers really care about something specifically being too many redirects? By construction, the answer must be "no" because they might be operating on a File
or a TcpSocket
, neither of which have such a concept.
I don't believe I would create a wrapper error type in this case; I can't see how it would provide any value. It would require extra type annotations that you get "for free" with a function.
This is not always trivial.
That is correct — gluing two wildly different pieces together sometimes doesn't line up exactly the way we want. That's part of what makes programming both exciting and terrible.
Upvotes: 1