@@ -47,6 +47,7 @@ pub struct ErrorMetadata {
47
47
#[ derive( Debug , Clone , PartialEq , Eq ) ]
48
48
pub enum ErrorCode {
49
49
BadRequest ,
50
+ Conflict ,
50
51
Unauthenticated ,
51
52
AuthUpdateFailed ,
52
53
Forbidden ,
@@ -99,6 +100,23 @@ impl ErrorMetadata {
99
100
}
100
101
}
101
102
103
+ /// Conflict. Maps to 409 in HTTP.
104
+ ///
105
+ /// The short_msg should be a CapitalCamelCased describing the error (eg
106
+ /// DuplicateInstallation). The msg should be a descriptive message targeted
107
+ /// toward the developer.
108
+ pub fn conflict (
109
+ short_msg : impl Into < Cow < ' static , str > > ,
110
+ msg : impl Into < Cow < ' static , str > > ,
111
+ ) -> Self {
112
+ Self {
113
+ code : ErrorCode :: Conflict ,
114
+ short_msg : short_msg. into ( ) ,
115
+ msg : msg. into ( ) ,
116
+ source : None ,
117
+ }
118
+ }
119
+
102
120
/// Resource not found. Maps to 404 in HTTP. This is not considered
103
121
/// a deterministic user error. It should typically be used when the
104
122
/// resource can't be currently found, e.g. the backend is not currently
@@ -440,6 +458,7 @@ impl ErrorMetadata {
440
458
pub fn is_deterministic_user_error ( & self ) -> bool {
441
459
match self . code {
442
460
ErrorCode :: BadRequest
461
+ | ErrorCode :: Conflict
443
462
| ErrorCode :: PaginationLimit
444
463
| ErrorCode :: Unauthenticated
445
464
| ErrorCode :: AuthUpdateFailed
@@ -473,6 +492,7 @@ impl ErrorMetadata {
473
492
match self . code {
474
493
ErrorCode :: ClientDisconnect => None ,
475
494
ErrorCode :: BadRequest
495
+ | ErrorCode :: Conflict
476
496
| ErrorCode :: NotFound
477
497
| ErrorCode :: PaginationLimit
478
498
| ErrorCode :: Forbidden
@@ -505,6 +525,7 @@ impl ErrorMetadata {
505
525
fn metric_server_error_label_value ( & self ) -> Option < & ' static str > {
506
526
match self . code {
507
527
ErrorCode :: BadRequest
528
+ | ErrorCode :: Conflict
508
529
| ErrorCode :: PaginationLimit
509
530
| ErrorCode :: Unauthenticated
510
531
| ErrorCode :: AuthUpdateFailed
@@ -529,6 +550,7 @@ impl ErrorMetadata {
529
550
pub fn custom_metric ( & self ) -> Option < & ' static IntCounter > {
530
551
match self . code {
531
552
ErrorCode :: BadRequest => Some ( & crate :: metrics:: BAD_REQUEST_ERROR_TOTAL ) ,
553
+ ErrorCode :: Conflict => None ,
532
554
ErrorCode :: ClientDisconnect => Some ( & crate :: metrics:: CLIENT_DISCONNECT_ERROR_TOTAL ) ,
533
555
ErrorCode :: RateLimited => Some ( & crate :: metrics:: RATE_LIMITED_ERROR_TOTAL ) ,
534
556
ErrorCode :: Unauthenticated | ErrorCode :: AuthUpdateFailed => {
@@ -561,9 +583,10 @@ impl ErrorMetadata {
561
583
ErrorCode :: OperationalInternalServerError => Some ( CloseCode :: Error ) ,
562
584
// These ones are client errors - so no close code - the client
563
585
// will handle and close the connection instead.
564
- ErrorCode :: BadRequest | ErrorCode :: Unauthenticated | ErrorCode :: AuthUpdateFailed => {
565
- None
566
- } ,
586
+ ErrorCode :: BadRequest
587
+ | ErrorCode :: Unauthenticated
588
+ | ErrorCode :: AuthUpdateFailed
589
+ | ErrorCode :: Conflict => None ,
567
590
} ?;
568
591
// According to the WebSocket protocol specification (RFC 6455), the reason
569
592
// string (if present) is limited to 123 bytes. This is because the
@@ -582,6 +605,7 @@ impl ErrorCode {
582
605
fn http_status_code ( & self ) -> StatusCode {
583
606
match self {
584
607
ErrorCode :: BadRequest | ErrorCode :: PaginationLimit => StatusCode :: BAD_REQUEST ,
608
+ ErrorCode :: Conflict => StatusCode :: CONFLICT ,
585
609
// HTTP has the unfortunate naming of 401 as unauthorized when it's
586
610
// really about authentication.
587
611
// https://stackoverflow.com/questions/3297048/403-forbidden-vs-401-unauthorized-http-responses
@@ -602,6 +626,7 @@ impl ErrorCode {
602
626
pub fn grpc_status_code ( & self ) -> tonic:: Code {
603
627
match self {
604
628
ErrorCode :: BadRequest => tonic:: Code :: InvalidArgument ,
629
+ ErrorCode :: Conflict => tonic:: Code :: AlreadyExists ,
605
630
ErrorCode :: Unauthenticated | ErrorCode :: AuthUpdateFailed => {
606
631
tonic:: Code :: Unauthenticated
607
632
} ,
@@ -940,6 +965,7 @@ mod proptest {
940
965
fn arbitrary_with ( ( ) : Self :: Parameters ) -> Self :: Strategy {
941
966
any :: < ErrorCode > ( ) . prop_map ( |ec| match ec {
942
967
ErrorCode :: BadRequest => ErrorMetadata :: bad_request ( "bad" , "request" ) ,
968
+ ErrorCode :: Conflict => ErrorMetadata :: conflict ( "conflict" , "conflict" ) ,
943
969
ErrorCode :: NotFound => ErrorMetadata :: not_found ( "not" , "found" ) ,
944
970
ErrorCode :: PaginationLimit => {
945
971
ErrorMetadata :: pagination_limit ( "pagination" , "limit" )
0 commit comments