A custom error type gives a Rust function one error type to return when its operations can fail in different ways. For example, parsing a number can return ParseIntError, while opening or writing a file can return std::io::Error. A function declared to return only ParseIntError cannot propagate both with ?; an application-defined enum can represent both failures. section 5.2
For a web service, define the error enum in an errors.rs module. Give it variants for the failures handlers must distinguish, such as database, Actix, and not-found errors. Implement From for underlying error types so ? can propagate them as the custom type, then return that type from database-access functions and route handlers. section 5.3 section 5.7
Listing 5.1 Error handling: part 1
use actix_web::{error, http::StatusCode, HttpResponse, Result};
use serde::Serialize;
use sqlx::error::Error as SQLxError;
use std::fmt;
#[derive(Debug, Serialize)]
pub enum EzyTutorError { #1
DBError(String),
ActixError(String),
NotFound(String),
}
#[derive(Debug, Serialize)]
pub struct MyErrorResponse { #2
error_message: String,
}
The enum separates internal failure categories from the response structure that carries a client-facing error_message. section 5.3
Implement Actix Web’s ResponseError for the enum to turn returned errors into HTTP responses. Database and Actix errors map to HTTP 500; not-found errors map to HTTP 404. Build a JSON response with an appropriate message. The demonstrated mapping logs internal messages while returning shorter messages for server errors. section 5.3
Listing 5.3 Error handling: part 3
impl error::ResponseError for EzyTutorError {
fn status_code(&self) -> StatusCode { #1
match self {
EzyTutorError::DBError(msg) | EzyTutorError::ActixError(msg) => {
StatusCode::INTERNAL_SERVER_ERROR
}
EzyTutorError::NotFound(msg) => StatusCode::NOT_FOUND,
}
}
fn error_response(&self) -> HttpResponse { #2
HttpResponse::build(self.status_code()).json(MyErrorResponse {
error_message: self.error_response(),
})
}
}
The ResponseError implementation supplies both the status code and the JSON response body. section 5.3
Propagate a course-insertion error
A database function returns Result<Course, EzyTutorError> and uses ? after the SQL insert. Its route handler returns Result<HttpResponse, EzyTutorError>, mapping a successful Course to an OK JSON response while leaving errors for Actix to convert. A handler test unwraps the successful result and checks for HTTP 200; the service can also be exercised with a POST request and cargo test. section 5.6
The same approach extends to a server-rendered registration application: its error enum adds a template-error variant alongside database, Actix, and not-found variants. Form-input errors can instead lead the handler to re-render the form with a suitable message. section 8.1 section 8.4




