@@ -36,8 +36,8 @@ pub enum Error {
3636 ///
3737 /// For a good API, the other status codes should also ideally map to some sort of JSON body
3838 /// that the frontend can deal with, but I do admit sometimes I've just gotten lazy and
39- /// returned a plain error message if I can get away with just using distinct status codes
40- /// without deviating too much from their specifications .
39+ /// returned a plain error message if there were few enough error modes for a route
40+ /// that the frontend could infer the error from the status code alone .
4141 #[ error( "error in the request body" ) ]
4242 UnprocessableEntity {
4343 errors : HashMap < Cow < ' static , str > , Vec < Cow < ' static , str > > > ,
@@ -48,12 +48,15 @@ pub enum Error {
4848 /// Via the generated `From<sqlx::Error> for Error` impl,
4949 /// this allows using `?` on database calls in handler functions without a manual mapping step.
5050 ///
51+ /// I highly recommend creating an error type like this if only to make handler function code
52+ /// nicer; code in Actix-web projects that we started before I settled on this pattern is
53+ /// filled with `.map_err(ErrInternalServerError)?` which is a *ton* of unnecessary noise.
54+ ///
5155 /// The actual error message isn't returned to the client for security reasons.
5256 /// It should be logged instead.
5357 ///
5458 /// Note that this could also contain database constraint errors, which should usually
55- /// be transformed into client errors (e.g. `422 Unprocessable Entity`).
56- ///
59+ /// be transformed into client errors (e.g. `422 Unprocessable Entity` or `409 Conflict`).
5760 /// See `ResultExt` below for a convenient way to do this.
5861 #[ error( "an error occurred with the database" ) ]
5962 Sqlx ( #[ from] sqlx:: Error ) ,
@@ -62,7 +65,8 @@ pub enum Error {
6265 ///
6366 /// `anyhow::Error` is used in a few places to capture context and backtraces
6467 /// on unrecoverable (but technically non-fatal) errors which could be highly useful for
65- /// debugging.
68+ /// debugging. We use it a lot in our code for background tasks or making API calls
69+ /// to external services so we can use `.context()` to refine the logged error.
6670 ///
6771 /// Via the generated `From<anyhow::Error> for Error` impl, this allows the
6872 /// use of `?` in handler functions to automatically convert `anyhow::Error` into a response.
@@ -124,7 +128,7 @@ impl IntoResponse for Error {
124128 errors : HashMap < Cow < ' static , str > , Vec < Cow < ' static , str > > > ,
125129 }
126130
127- ( StatusCode :: UNPROCESSABLE_ENTITY , Json ( Errors { errors } ) ) . into_response ( )
131+ return ( StatusCode :: UNPROCESSABLE_ENTITY , Json ( Errors { errors } ) ) . into_response ( ) ;
128132 }
129133 Self :: Unauthorized => (
130134 self . status_code ( ) ,
@@ -137,17 +141,30 @@ impl IntoResponse for Error {
137141 //
138142 // However, at Launchbadge we try to adhere to web standards wherever possible,
139143 // if nothing else than to try to act as a vanguard of sanity on the web.
140- //
141- // "Your scientists were so preoccupied with whether or not they *could*,
142- // they didn't stop to think if they *should*."
143144 [ ( WWW_AUTHENTICATE , HeaderValue :: from_static ( "Token" ) ) ]
144145 . into_iter ( )
145146 . collect :: < HeaderMap > ( ) ,
146147 self . to_string ( ) ,
147148 )
148149 . into_response ( ) ,
149- other => ( other. status_code ( ) , other. to_string ( ) ) . into_response ( ) ,
150+
151+ Self :: Sqlx ( e) => {
152+ // TODO: we probably want to use `tracing` instead
153+ // so that this gets linked to the HTTP request by `TraceLayer`.
154+ log:: error!( "SQLx error: {:?}" , e) ;
155+ }
156+
157+ Self :: Anyhow ( e) => {
158+ // TODO: we probably want to use `tracing` instead
159+ // so that this gets linked to the HTTP request by `TraceLayer`.
160+ log:: error!( "Generic error: {:?}" , e) ;
161+ }
162+
163+ // Other errors get mapped normally.
164+ _ => ( ) ,
150165 }
166+
167+ ( self . status_code ( ) , self . to_string ( ) ) . into_response ( )
151168 }
152169}
153170
0 commit comments