@@ -80,7 +80,7 @@ impl<T> std::ops::DerefMut for Validated<T> {
8080pub struct ValidatedFut < T : FromRequest > {
8181 req : actix_web:: HttpRequest ,
8282 fut : <T as FromRequest >:: Future ,
83- error_handler : Option < ValidatorErrHandler > ,
83+ error_handler : Option < ValidationErrHandler > ,
8484}
8585impl < T > Future for ValidatedFut < T >
8686where
@@ -132,7 +132,7 @@ where
132132 payload : & mut actix_web:: dev:: Payload ,
133133 ) -> Self :: Future {
134134 let error_handler = req
135- . app_data :: < ValidatorErrorHandler > ( )
135+ . app_data :: < ValidationErrorHandler > ( )
136136 . map ( |h| h. handler . clone ( ) ) ;
137137
138138 let fut = T :: from_request ( req, payload) ;
@@ -184,29 +184,30 @@ impl ResponseError for Error {
184184 }
185185}
186186
187- pub type ValidatorErrHandler =
187+ pub type ValidationErrHandler =
188188 Arc < dyn Fn ( Vec < ValidationError > , & HttpRequest ) -> actix_web:: Error + Send + Sync > ;
189189
190- struct ValidatorErrorHandler {
191- handler : ValidatorErrHandler ,
190+ struct ValidationErrorHandler {
191+ handler : ValidationErrHandler ,
192192}
193193
194- pub trait ValidatorErrorHandlerExt {
195- fn validator_error_handler ( self , handler : ValidatorErrHandler ) -> Self ;
194+ pub trait ValidationErrorHandlerExt {
195+ fn validation_error_handler ( self , handler : ValidationErrHandler ) -> Self ;
196196}
197197
198- impl < T > ValidatorErrorHandlerExt for App < T >
198+ impl < T > ValidationErrorHandlerExt for App < T >
199199where
200200 T : ServiceFactory < ServiceRequest , Config = ( ) , Error = actix_web:: Error , InitError = ( ) > ,
201201{
202- fn validator_error_handler ( self , handler : ValidatorErrHandler ) -> Self {
203- self . app_data ( ValidatorErrorHandler { handler } )
202+ fn validation_error_handler ( self , handler : ValidationErrHandler ) -> Self {
203+ self . app_data ( ValidationErrorHandler { handler } )
204204 }
205205}
206206
207207#[ cfg( test) ]
208208mod test {
209209 use super :: * ;
210+ use actix_web:: web:: Bytes ;
210211 use actix_web:: { http:: header:: ContentType , post, test, web:: Json , App , Responder } ;
211212 use serde:: { Deserialize , Serialize } ;
212213
@@ -227,14 +228,14 @@ mod test {
227228 }
228229 }
229230
231+ #[ post( "/" ) ]
232+ async fn endpoint ( v : Validated < Json < ExamplePayload > > ) -> impl Responder {
233+ assert ! ( v. name. len( ) > 4 ) ;
234+ HttpResponse :: Ok ( ) . body ( ( ) )
235+ }
236+
230237 #[ actix_web:: test]
231238 async fn should_validate_simple ( ) {
232- #[ post( "/" ) ]
233- async fn endpoint ( v : Validated < Json < ExamplePayload > > ) -> impl Responder {
234- assert ! ( v. name. len( ) > 4 ) ;
235- HttpResponse :: Ok ( ) . body ( ( ) )
236- }
237-
238239 let app = test:: init_service ( App :: new ( ) . service ( endpoint) ) . await ;
239240
240241 // Valid request
@@ -259,4 +260,78 @@ mod test {
259260 let resp = test:: call_service ( & app, req) . await ;
260261 assert_eq ! ( resp. status( ) . as_u16( ) , 400 ) ;
261262 }
263+
264+ #[ actix_web:: test]
265+ async fn should_respond_with_errors_correctly ( ) {
266+ let app = test:: init_service ( App :: new ( ) . service ( endpoint) ) . await ;
267+
268+ // Invalid request
269+ let req = test:: TestRequest :: post ( )
270+ . uri ( "/" )
271+ . insert_header ( ContentType :: plaintext ( ) )
272+ . set_json ( ExamplePayload {
273+ name : "1234" . to_string ( ) ,
274+ } )
275+ . to_request ( ) ;
276+ let result = test:: call_and_read_body ( & app, req) . await ;
277+ assert_eq ! (
278+ result,
279+ Bytes :: from_static( b"Validation errors in fields:\n \t name not long enough" )
280+ ) ;
281+ }
282+
283+ #[ derive( Debug , Serialize , Error ) ]
284+ struct CustomErrorResponse {
285+ custom_message : String ,
286+ errors : Vec < String > ,
287+ }
288+
289+ impl Display for CustomErrorResponse {
290+ fn fmt ( & self , _f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
291+ unimplemented ! ( )
292+ }
293+ }
294+
295+ impl ResponseError for CustomErrorResponse {
296+ fn status_code ( & self ) -> actix_web:: http:: StatusCode {
297+ actix_web:: http:: StatusCode :: BAD_REQUEST
298+ }
299+
300+ fn error_response ( & self ) -> HttpResponse < actix_web:: body:: BoxBody > {
301+ HttpResponse :: build ( self . status_code ( ) ) . body ( serde_json:: to_string ( self ) . unwrap ( ) )
302+ }
303+ }
304+
305+ fn error_handler ( errors : Vec < ValidationError > , _: & HttpRequest ) -> actix_web:: Error {
306+ CustomErrorResponse {
307+ custom_message : "My custom message" . to_string ( ) ,
308+ errors : errors. iter ( ) . map ( |err| err. message . clone ( ) ) . collect ( ) ,
309+ }
310+ . into ( )
311+ }
312+
313+ #[ actix_web:: test]
314+ async fn should_use_allow_custom_error_responses ( ) {
315+ let app = test:: init_service (
316+ App :: new ( )
317+ . service ( endpoint)
318+ . validation_error_handler ( Arc :: new ( error_handler) ) ,
319+ )
320+ . await ;
321+
322+ let req = test:: TestRequest :: post ( )
323+ . uri ( "/" )
324+ . insert_header ( ContentType :: plaintext ( ) )
325+ . set_json ( ExamplePayload {
326+ name : "1234" . to_string ( ) ,
327+ } )
328+ . to_request ( ) ;
329+ let result = test:: call_and_read_body ( & app, req) . await ;
330+ assert_eq ! (
331+ result,
332+ Bytes :: from_static(
333+ b"{\" custom_message\" :\" My custom message\" ,\" errors\" :[\" name not long enough\" ]}"
334+ )
335+ ) ;
336+ }
262337}
0 commit comments