I would like to craft a function which does HTTP call and returns either successful result parsed body or an error of one of the following kinds:
- specific application error if status code is not successful (see marker in code sample below) OR
- returns hyper::Error if it is underlying transport problem
I have got a function doing this and currently it returns hyper:Error everywhere, because I do not know how to transform it correctly to an error of mixed error type. I have seen examples like this but it smells, in my opinion (what if I will need to mix many more other error types from other crates, eg. from many nested dependencies?)
What is the best practice to solve the problem like this?
fn connect(&self) -> Result<(), hyper::Error> { // TODO some other different error type should be here?
let mut core = Core::new()?;
let client= Client::new(&core.handle());
....
let mut req: Request<hyper::Body> = Request::new(hyper::Method::Post, login_url);
....
let work = client.request(req)
.and_then(|res| {
let result = if res.status() == hyper::StatusCode::Created {
Adapter::get_body(res.body())
}
else {
// HERE I WOULD LIKE TO USE MY CUSTOM ERROR TYPE INSTEAD
// but use hyper error for now to have something working
Box::new(futures::future::err(hyper::Error::TooLarge))
};
result
})
.map(|res| {
let login_response: LoginResponse = serde_json::from_str(res.deref()).unwrap();
println!("{:?}", login_response)
});
let result = core.run(work);
// an example of error handling block,
// where I intend to print different status messages depending on kind of an error
// this block will be global in main() function to handle various types of errors from other places
match result {
Ok(v) => {
println!("Result: {:?}", v);
}
Err(hyper::error::Error::Io(e)) => {
println!("IO Error: {}", e);
}
Err(e) => { // TODO match on application specific codes
println!("Error: {}", e);
println!("Error: {:?}", e.cause().map(|e| {
e
}));
}
};
Ok(())
}
fn get_body(body: hyper::Body) -> Box<Future<Item=String, Error=hyper::Error>> {
let full_body = body.concat2()
.map(|chunk| {
let v = chunk.to_vec();
String::from_utf8_lossy(&v).to_string()
});
Box::new(full_body)
}