@@ -27,8 +27,11 @@ type HTTPClientOptions struct {
27
27
// Defaults to [http.DefaultClient.Do].
28
28
HTTPCaller func (* http.Request ) (* http.Response , error )
29
29
// A [Serializer] to customize client serialization behavior.
30
- // By default the client handles, JSONables, byte slices, and nil.
30
+ // By default the client handles JSONables, byte slices, and nil.
31
31
Serializer Serializer
32
+ // A [FailureConverter] to convert a [Failure] instance to and from an [error]. Defaults to
33
+ // [DefaultFailureConverter].
34
+ FailureConverter FailureConverter
32
35
}
33
36
34
37
// User-Agent header set on HTTP requests.
@@ -114,6 +117,9 @@ func NewHTTPClient(options HTTPClientOptions) (*HTTPClient, error) {
114
117
if options .Serializer == nil {
115
118
options .Serializer = defaultSerializer
116
119
}
120
+ if options .FailureConverter == nil {
121
+ options .FailureConverter = defaultFailureConverter
122
+ }
117
123
118
124
return & HTTPClient {
119
125
options : options ,
@@ -267,17 +273,18 @@ func (c *HTTPClient) StartOperation(
267
273
return nil , err
268
274
}
269
275
270
- failure , err := failureFromResponse (response , body )
276
+ failure , err := c . failureFromResponse (response , body )
271
277
if err != nil {
272
278
return nil , err
273
279
}
274
280
281
+ failureErr := c .options .FailureConverter .FailureToError (failure )
275
282
return nil , & UnsuccessfulOperationError {
276
- State : state ,
277
- Failure : failure ,
283
+ State : state ,
284
+ Cause : failureErr ,
278
285
}
279
286
default :
280
- return nil , bestEffortHandlerErrorFromResponse (response , body )
287
+ return nil , c . bestEffortHandlerErrorFromResponse (response , body )
281
288
}
282
289
}
283
290
@@ -393,7 +400,7 @@ func operationInfoFromResponse(response *http.Response, body []byte) (*Operation
393
400
return & info , nil
394
401
}
395
402
396
- func failureFromResponse (response * http.Response , body []byte ) (Failure , error ) {
403
+ func ( c * HTTPClient ) failureFromResponse (response * http.Response , body []byte ) (Failure , error ) {
397
404
if ! isMediaTypeJSON (response .Header .Get ("Content-Type" )) {
398
405
return Failure {}, newUnexpectedResponseError (fmt .Sprintf ("invalid response content type: %q" , response .Header .Get ("Content-Type" )), response , body )
399
406
}
@@ -402,43 +409,49 @@ func failureFromResponse(response *http.Response, body []byte) (Failure, error)
402
409
return failure , err
403
410
}
404
411
405
- func failureFromResponseOrDefault (response * http.Response , body []byte , defaultMessage string ) Failure {
406
- failure , err := failureFromResponse (response , body )
412
+ func ( c * HTTPClient ) failureFromResponseOrDefault (response * http.Response , body []byte , defaultMessage string ) Failure {
413
+ failure , err := c . failureFromResponse (response , body )
407
414
if err != nil {
408
415
failure .Message = defaultMessage
409
416
}
410
417
return failure
411
418
}
412
419
413
- func bestEffortHandlerErrorFromResponse (response * http.Response , body []byte ) error {
420
+ func (c * HTTPClient ) failureErrorFromResponseOrDefault (response * http.Response , body []byte , defaultMessage string ) error {
421
+ failure := c .failureFromResponseOrDefault (response , body , defaultMessage )
422
+ failureErr := c .options .FailureConverter .FailureToError (failure )
423
+ return failureErr
424
+ }
425
+
426
+ func (c * HTTPClient ) bestEffortHandlerErrorFromResponse (response * http.Response , body []byte ) error {
414
427
switch response .StatusCode {
415
428
case http .StatusBadRequest :
416
- failure := failureFromResponseOrDefault (response , body , "bad request" )
417
- return & HandlerError {Type : HandlerErrorTypeBadRequest , Failure : & failure }
429
+ failureErr := c . failureErrorFromResponseOrDefault (response , body , "bad request" )
430
+ return & HandlerError {Type : HandlerErrorTypeBadRequest , Cause : failureErr }
418
431
case http .StatusUnauthorized :
419
- failure := failureFromResponseOrDefault (response , body , "unauthenticated" )
420
- return & HandlerError {Type : HandlerErrorTypeUnauthenticated , Failure : & failure }
432
+ failureErr := c . failureErrorFromResponseOrDefault (response , body , "unauthenticated" )
433
+ return & HandlerError {Type : HandlerErrorTypeUnauthenticated , Cause : failureErr }
421
434
case http .StatusForbidden :
422
- failure := failureFromResponseOrDefault (response , body , "unauthorized" )
423
- return & HandlerError {Type : HandlerErrorTypeUnauthorized , Failure : & failure }
435
+ failureErr := c . failureErrorFromResponseOrDefault (response , body , "unauthorized" )
436
+ return & HandlerError {Type : HandlerErrorTypeUnauthorized , Cause : failureErr }
424
437
case http .StatusNotFound :
425
- failure := failureFromResponseOrDefault (response , body , "not found" )
426
- return & HandlerError {Type : HandlerErrorTypeNotFound , Failure : & failure }
438
+ failureErr := c . failureErrorFromResponseOrDefault (response , body , "not found" )
439
+ return & HandlerError {Type : HandlerErrorTypeNotFound , Cause : failureErr }
427
440
case http .StatusTooManyRequests :
428
- failure := failureFromResponseOrDefault (response , body , "resource exhausted" )
429
- return & HandlerError {Type : HandlerErrorTypeResourceExhausted , Failure : & failure }
441
+ failureErr := c . failureErrorFromResponseOrDefault (response , body , "resource exhausted" )
442
+ return & HandlerError {Type : HandlerErrorTypeResourceExhausted , Cause : failureErr }
430
443
case http .StatusInternalServerError :
431
- failure := failureFromResponseOrDefault (response , body , "internal error" )
432
- return & HandlerError {Type : HandlerErrorTypeInternal , Failure : & failure }
444
+ failureErr := c . failureErrorFromResponseOrDefault (response , body , "internal error" )
445
+ return & HandlerError {Type : HandlerErrorTypeInternal , Cause : failureErr }
433
446
case http .StatusNotImplemented :
434
- failure := failureFromResponseOrDefault (response , body , "not implemented" )
435
- return & HandlerError {Type : HandlerErrorTypeNotImplemented , Failure : & failure }
447
+ failureErr := c . failureErrorFromResponseOrDefault (response , body , "not implemented" )
448
+ return & HandlerError {Type : HandlerErrorTypeNotImplemented , Cause : failureErr }
436
449
case http .StatusServiceUnavailable :
437
- failure := failureFromResponseOrDefault (response , body , "unavailable" )
438
- return & HandlerError {Type : HandlerErrorTypeUnavailable , Failure : & failure }
450
+ failureErr := c . failureErrorFromResponseOrDefault (response , body , "unavailable" )
451
+ return & HandlerError {Type : HandlerErrorTypeUnavailable , Cause : failureErr }
439
452
case StatusUpstreamTimeout :
440
- failure := failureFromResponseOrDefault (response , body , "upstream timeout" )
441
- return & HandlerError {Type : HandlerErrorTypeUpstreamTimeout , Failure : & failure }
453
+ failureErr := c . failureErrorFromResponseOrDefault (response , body , "upstream timeout" )
454
+ return & HandlerError {Type : HandlerErrorTypeUpstreamTimeout , Cause : failureErr }
442
455
default :
443
456
return newUnexpectedResponseError (fmt .Sprintf ("unexpected response status: %q" , response .Status ), response , body )
444
457
}
0 commit comments