redlib
redlib copied to clipboard
Refactor: idiomatic `Result` types
- Throughout the project, all errors are coerced into Strings. This is very bad practice because:
- There is no option to handle the errors smoothly — display the error to the client, log it, that's it.
- No error propagation with the try operator (
?); the whole project is filled with boilerplate match statements. - Untyped rust is painful to work with.
- The type of BoxResponse:
type BoxResponse = Pin<Box<dyn Future<Output = Result<Response<Body>, String>> + Send>>;means that futures that return results with generic errors are a primitive in the program. The result is things like this:
async fn pwa_logo() -> Result<Response<Body>, String> {
Ok(
Response::builder()
.status(200)
.header("content-type", "image/png")
.body(include_bytes!("../static/logo.png").as_ref().into())
.unwrap_or_default(),
)
}
http::Error::Result<Response<Body>> is obviously the intended return type. Even better, since the function always returns Ok(_), it should return Response<Body>, however
This refactoring is crucial for readability and productivity. Hopefully, the only errors are the http error, hyper error, and the custom errors which are intended to be rendered to the client by the error boilerplate.
use hyper::{Body, Request, Response, Server};
use hyper::service::{make_service_fn, service_fn};
use std::convert::Infallible;
use std::net::SocketAddr;
async fn handle_request(req: Request<Body>) -> Result<Response<Body>, AppError> {
match req.uri().path() {
"/logo" => Ok(pwa_logo()), // Call the infallible version
_ => Err(AppError::Custom("Not Found".to_string())),
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
// Create a service that handles requests
let make_svc = make_service_fn(|_conn| async {
Ok::<_, Infallible>(service_fn(|req| async {
handle_request(req)
.await
.map_err(|e| e.into_response()) // Convert errors to responses
}))
});
let server = Server::bind(&addr).serve(make_svc);
println!("Server running on http://{}", addr);
server.await?;
Ok(())
}