1 use std::{collections::HashMap, time}; 2 3 use super::std_messages::{ 4 BadRequest, DebugInfo, ErrorInfo, FieldViolation, Help, HelpLink, LocalizedMessage, 5 PreconditionFailure, PreconditionViolation, QuotaFailure, QuotaViolation, RequestInfo, 6 ResourceInfo, RetryInfo, 7 }; 8 9 pub(crate) mod vec; 10 11 /// Groups the standard error messages structs. Provides associated 12 /// functions and methods to setup and edit each error message independently. 13 /// Used when extracting error details from `tonic::Status`, and when 14 /// creating a `tonic::Status` with error details. 15 #[non_exhaustive] 16 #[derive(Clone, Debug, Default)] 17 pub struct ErrorDetails { 18 /// This field stores [`RetryInfo`] data, if any. 19 pub(crate) retry_info: Option<RetryInfo>, 20 21 /// This field stores [`DebugInfo`] data, if any. 22 pub(crate) debug_info: Option<DebugInfo>, 23 24 /// This field stores [`QuotaFailure`] data, if any. 25 pub(crate) quota_failure: Option<QuotaFailure>, 26 27 /// This field stores [`ErrorInfo`] data, if any. 28 pub(crate) error_info: Option<ErrorInfo>, 29 30 /// This field stores [`PreconditionFailure`] data, if any. 31 pub(crate) precondition_failure: Option<PreconditionFailure>, 32 33 /// This field stores [`BadRequest`] data, if any. 34 pub(crate) bad_request: Option<BadRequest>, 35 36 /// This field stores [`RequestInfo`] data, if any. 37 pub(crate) request_info: Option<RequestInfo>, 38 39 /// This field stores [`ResourceInfo`] data, if any. 40 pub(crate) resource_info: Option<ResourceInfo>, 41 42 /// This field stores [`Help`] data, if any. 43 pub(crate) help: Option<Help>, 44 45 /// This field stores [`LocalizedMessage`] data, if any. 46 pub(crate) localized_message: Option<LocalizedMessage>, 47 } 48 49 impl ErrorDetails { 50 /// Generates an [`ErrorDetails`] struct with all fields set to `None`. 51 /// 52 /// # Examples 53 /// 54 /// ``` 55 /// use tonic_types::ErrorDetails; 56 /// 57 /// let err_details = ErrorDetails::new(); 58 /// ``` new() -> Self59 pub fn new() -> Self { 60 Self::default() 61 } 62 63 /// Generates an [`ErrorDetails`] struct with [`RetryInfo`] details and 64 /// remaining fields set to `None`. 65 /// 66 /// # Examples 67 /// 68 /// ``` 69 /// use std::time::Duration; 70 /// use tonic_types::ErrorDetails; 71 /// 72 /// let err_details = ErrorDetails::with_retry_info(Some(Duration::from_secs(5))); 73 /// ``` with_retry_info(retry_delay: Option<time::Duration>) -> Self74 pub fn with_retry_info(retry_delay: Option<time::Duration>) -> Self { 75 ErrorDetails { 76 retry_info: Some(RetryInfo::new(retry_delay)), 77 ..ErrorDetails::new() 78 } 79 } 80 81 /// Generates an [`ErrorDetails`] struct with [`DebugInfo`] details and 82 /// remaining fields set to `None`. 83 /// 84 /// # Examples 85 /// 86 /// ``` 87 /// use tonic_types::ErrorDetails; 88 /// 89 /// let err_stack = vec!["...".into(), "...".into()]; 90 /// 91 /// let err_details = ErrorDetails::with_debug_info(err_stack, "error details"); 92 /// ``` with_debug_info( stack_entries: impl Into<Vec<String>>, detail: impl Into<String>, ) -> Self93 pub fn with_debug_info( 94 stack_entries: impl Into<Vec<String>>, 95 detail: impl Into<String>, 96 ) -> Self { 97 ErrorDetails { 98 debug_info: Some(DebugInfo::new(stack_entries, detail)), 99 ..ErrorDetails::new() 100 } 101 } 102 103 /// Generates an [`ErrorDetails`] struct with [`QuotaFailure`] details and 104 /// remaining fields set to `None`. 105 /// 106 /// # Examples 107 /// 108 /// ``` 109 /// use tonic_types::{ErrorDetails, QuotaViolation}; 110 /// 111 /// let err_details = ErrorDetails::with_quota_failure(vec![ 112 /// QuotaViolation::new("subject 1", "description 1"), 113 /// QuotaViolation::new("subject 2", "description 2"), 114 /// ]); 115 /// ``` with_quota_failure(violations: impl Into<Vec<QuotaViolation>>) -> Self116 pub fn with_quota_failure(violations: impl Into<Vec<QuotaViolation>>) -> Self { 117 ErrorDetails { 118 quota_failure: Some(QuotaFailure::new(violations)), 119 ..ErrorDetails::new() 120 } 121 } 122 123 /// Generates an [`ErrorDetails`] struct with [`QuotaFailure`] details (one 124 /// [`QuotaViolation`] set) and remaining fields set to `None`. 125 /// 126 /// # Examples 127 /// 128 /// ``` 129 /// use tonic_types::ErrorDetails; 130 /// 131 /// let err_details = ErrorDetails::with_quota_failure_violation("subject", "description"); 132 /// ``` with_quota_failure_violation( subject: impl Into<String>, description: impl Into<String>, ) -> Self133 pub fn with_quota_failure_violation( 134 subject: impl Into<String>, 135 description: impl Into<String>, 136 ) -> Self { 137 ErrorDetails { 138 quota_failure: Some(QuotaFailure::with_violation(subject, description)), 139 ..ErrorDetails::new() 140 } 141 } 142 143 /// Generates an [`ErrorDetails`] struct with [`ErrorInfo`] details and 144 /// remaining fields set to `None`. 145 /// 146 /// # Examples 147 /// 148 /// ``` 149 /// use std::collections::HashMap; 150 /// use tonic_types::ErrorDetails; 151 /// 152 /// let mut metadata: HashMap<String, String> = HashMap::new(); 153 /// metadata.insert("instanceLimitPerRequest".into(), "100".into()); 154 /// 155 /// let err_details = ErrorDetails::with_error_info("reason", "domain", metadata); 156 /// ``` with_error_info( reason: impl Into<String>, domain: impl Into<String>, metadata: impl Into<HashMap<String, String>>, ) -> Self157 pub fn with_error_info( 158 reason: impl Into<String>, 159 domain: impl Into<String>, 160 metadata: impl Into<HashMap<String, String>>, 161 ) -> Self { 162 ErrorDetails { 163 error_info: Some(ErrorInfo::new(reason, domain, metadata)), 164 ..ErrorDetails::new() 165 } 166 } 167 168 /// Generates an [`ErrorDetails`] struct with [`PreconditionFailure`] 169 /// details and remaining fields set to `None`. 170 /// 171 /// # Examples 172 /// 173 /// ``` 174 /// use tonic_types::{ErrorDetails, PreconditionViolation}; 175 /// 176 /// let err_details = ErrorDetails::with_precondition_failure(vec![ 177 /// PreconditionViolation::new( 178 /// "violation type 1", 179 /// "subject 1", 180 /// "description 1", 181 /// ), 182 /// PreconditionViolation::new( 183 /// "violation type 2", 184 /// "subject 2", 185 /// "description 2", 186 /// ), 187 /// ]); 188 /// ``` with_precondition_failure(violations: impl Into<Vec<PreconditionViolation>>) -> Self189 pub fn with_precondition_failure(violations: impl Into<Vec<PreconditionViolation>>) -> Self { 190 ErrorDetails { 191 precondition_failure: Some(PreconditionFailure::new(violations)), 192 ..ErrorDetails::new() 193 } 194 } 195 196 /// Generates an [`ErrorDetails`] struct with [`PreconditionFailure`] 197 /// details (one [`PreconditionViolation`] set) and remaining fields set to 198 /// `None`. 199 /// 200 /// # Examples 201 /// 202 /// ``` 203 /// use tonic_types::ErrorDetails; 204 /// 205 /// let err_details = ErrorDetails::with_precondition_failure_violation( 206 /// "violation type", 207 /// "subject", 208 /// "description", 209 /// ); 210 /// ``` with_precondition_failure_violation( violation_type: impl Into<String>, subject: impl Into<String>, description: impl Into<String>, ) -> Self211 pub fn with_precondition_failure_violation( 212 violation_type: impl Into<String>, 213 subject: impl Into<String>, 214 description: impl Into<String>, 215 ) -> Self { 216 ErrorDetails { 217 precondition_failure: Some(PreconditionFailure::with_violation( 218 violation_type, 219 subject, 220 description, 221 )), 222 ..ErrorDetails::new() 223 } 224 } 225 226 /// Generates an [`ErrorDetails`] struct with [`BadRequest`] details and 227 /// remaining fields set to `None`. 228 /// 229 /// # Examples 230 /// 231 /// ``` 232 /// use tonic_types::{ErrorDetails, FieldViolation}; 233 /// 234 /// let err_details = ErrorDetails::with_bad_request(vec![ 235 /// FieldViolation::new("field_1", "description 1"), 236 /// FieldViolation::new("field_2", "description 2"), 237 /// ]); 238 /// ``` with_bad_request(field_violations: impl Into<Vec<FieldViolation>>) -> Self239 pub fn with_bad_request(field_violations: impl Into<Vec<FieldViolation>>) -> Self { 240 ErrorDetails { 241 bad_request: Some(BadRequest::new(field_violations)), 242 ..ErrorDetails::new() 243 } 244 } 245 246 /// Generates an [`ErrorDetails`] struct with [`BadRequest`] details (one 247 /// [`FieldViolation`] set) and remaining fields set to `None`. 248 /// 249 /// # Examples 250 /// 251 /// ``` 252 /// use tonic_types::ErrorDetails; 253 /// 254 /// let err_details = ErrorDetails::with_bad_request_violation( 255 /// "field", 256 /// "description", 257 /// ); 258 /// ``` with_bad_request_violation( field: impl Into<String>, description: impl Into<String>, ) -> Self259 pub fn with_bad_request_violation( 260 field: impl Into<String>, 261 description: impl Into<String>, 262 ) -> Self { 263 ErrorDetails { 264 bad_request: Some(BadRequest::with_violation(field, description)), 265 ..ErrorDetails::new() 266 } 267 } 268 269 /// Generates an [`ErrorDetails`] struct with [`RequestInfo`] details and 270 /// remaining fields set to `None`. 271 /// 272 /// # Examples 273 /// 274 /// ``` 275 /// use tonic_types::ErrorDetails; 276 /// 277 /// let err_details = ErrorDetails::with_request_info( 278 /// "request_id", 279 /// "serving_data", 280 /// ); 281 /// ``` with_request_info( request_id: impl Into<String>, serving_data: impl Into<String>, ) -> Self282 pub fn with_request_info( 283 request_id: impl Into<String>, 284 serving_data: impl Into<String>, 285 ) -> Self { 286 ErrorDetails { 287 request_info: Some(RequestInfo::new(request_id, serving_data)), 288 ..ErrorDetails::new() 289 } 290 } 291 292 /// Generates an [`ErrorDetails`] struct with [`ResourceInfo`] details and 293 /// remaining fields set to `None`. 294 /// 295 /// # Examples 296 /// 297 /// ``` 298 /// use tonic_types::ErrorDetails; 299 /// 300 /// let err_details = ErrorDetails::with_resource_info( 301 /// "res_type", 302 /// "res_name", 303 /// "owner", 304 /// "description", 305 /// ); 306 /// ``` with_resource_info( resource_type: impl Into<String>, resource_name: impl Into<String>, owner: impl Into<String>, description: impl Into<String>, ) -> Self307 pub fn with_resource_info( 308 resource_type: impl Into<String>, 309 resource_name: impl Into<String>, 310 owner: impl Into<String>, 311 description: impl Into<String>, 312 ) -> Self { 313 ErrorDetails { 314 resource_info: Some(ResourceInfo::new( 315 resource_type, 316 resource_name, 317 owner, 318 description, 319 )), 320 ..ErrorDetails::new() 321 } 322 } 323 324 /// Generates an [`ErrorDetails`] struct with [`Help`] details and 325 /// remaining fields set to `None`. 326 /// 327 /// # Examples 328 /// 329 /// ``` 330 /// use tonic_types::{ErrorDetails, HelpLink}; 331 /// 332 /// let err_details = ErrorDetails::with_help(vec![ 333 /// HelpLink::new("description of link a", "resource-a.example.local"), 334 /// HelpLink::new("description of link b", "resource-b.example.local"), 335 /// ]); 336 /// ``` with_help(links: impl Into<Vec<HelpLink>>) -> Self337 pub fn with_help(links: impl Into<Vec<HelpLink>>) -> Self { 338 ErrorDetails { 339 help: Some(Help::new(links)), 340 ..ErrorDetails::new() 341 } 342 } 343 344 /// Generates an [`ErrorDetails`] struct with [`Help`] details (one 345 /// [`HelpLink`] set) and remaining fields set to `None`. 346 /// 347 /// # Examples 348 /// 349 /// ``` 350 /// use tonic_types::ErrorDetails; 351 /// 352 /// let err_details = ErrorDetails::with_help_link( 353 /// "description of link a", 354 /// "resource-a.example.local" 355 /// ); 356 /// ``` with_help_link(description: impl Into<String>, url: impl Into<String>) -> Self357 pub fn with_help_link(description: impl Into<String>, url: impl Into<String>) -> Self { 358 ErrorDetails { 359 help: Some(Help::with_link(description, url)), 360 ..ErrorDetails::new() 361 } 362 } 363 364 /// Generates an [`ErrorDetails`] struct with [`LocalizedMessage`] details 365 /// and remaining fields set to `None`. 366 /// 367 /// # Examples 368 /// 369 /// ``` 370 /// use tonic_types::ErrorDetails; 371 /// 372 /// let err_details = ErrorDetails::with_localized_message( 373 /// "en-US", 374 /// "message for the user" 375 /// ); 376 /// ``` with_localized_message(locale: impl Into<String>, message: impl Into<String>) -> Self377 pub fn with_localized_message(locale: impl Into<String>, message: impl Into<String>) -> Self { 378 ErrorDetails { 379 localized_message: Some(LocalizedMessage::new(locale, message)), 380 ..ErrorDetails::new() 381 } 382 } 383 384 /// Get [`RetryInfo`] details, if any. retry_info(&self) -> Option<&RetryInfo>385 pub fn retry_info(&self) -> Option<&RetryInfo> { 386 self.retry_info.as_ref() 387 } 388 389 /// Get [`DebugInfo`] details, if any. debug_info(&self) -> Option<&DebugInfo>390 pub fn debug_info(&self) -> Option<&DebugInfo> { 391 self.debug_info.as_ref() 392 } 393 394 /// Get [`QuotaFailure`] details, if any. quota_failure(&self) -> Option<&QuotaFailure>395 pub fn quota_failure(&self) -> Option<&QuotaFailure> { 396 self.quota_failure.as_ref() 397 } 398 399 /// Get [`ErrorInfo`] details, if any. error_info(&self) -> Option<&ErrorInfo>400 pub fn error_info(&self) -> Option<&ErrorInfo> { 401 self.error_info.as_ref() 402 } 403 404 /// Get [`PreconditionFailure`] details, if any. precondition_failure(&self) -> Option<&PreconditionFailure>405 pub fn precondition_failure(&self) -> Option<&PreconditionFailure> { 406 self.precondition_failure.as_ref() 407 } 408 409 /// Get [`BadRequest`] details, if any. bad_request(&self) -> Option<&BadRequest>410 pub fn bad_request(&self) -> Option<&BadRequest> { 411 self.bad_request.as_ref() 412 } 413 414 /// Get [`RequestInfo`] details, if any. request_info(&self) -> Option<&RequestInfo>415 pub fn request_info(&self) -> Option<&RequestInfo> { 416 self.request_info.as_ref() 417 } 418 419 /// Get [`ResourceInfo`] details, if any. resource_info(&self) -> Option<&ResourceInfo>420 pub fn resource_info(&self) -> Option<&ResourceInfo> { 421 self.resource_info.as_ref() 422 } 423 424 /// Get [`Help`] details, if any. help(&self) -> Option<&Help>425 pub fn help(&self) -> Option<&Help> { 426 self.help.as_ref() 427 } 428 429 /// Get [`LocalizedMessage`] details, if any. localized_message(&self) -> Option<&LocalizedMessage>430 pub fn localized_message(&self) -> Option<&LocalizedMessage> { 431 self.localized_message.as_ref() 432 } 433 434 /// Set [`RetryInfo`] details. Can be chained with other `.set_` and 435 /// `.add_` [`ErrorDetails`] methods. 436 /// 437 /// # Examples 438 /// 439 /// ``` 440 /// use std::time::Duration; 441 /// use tonic_types::ErrorDetails; 442 /// 443 /// let mut err_details = ErrorDetails::new(); 444 /// 445 /// err_details.set_retry_info(Some(Duration::from_secs(5))); 446 /// ``` set_retry_info(&mut self, retry_delay: Option<time::Duration>) -> &mut Self447 pub fn set_retry_info(&mut self, retry_delay: Option<time::Duration>) -> &mut Self { 448 self.retry_info = Some(RetryInfo::new(retry_delay)); 449 self 450 } 451 452 /// Set [`DebugInfo`] details. Can be chained with other `.set_` and 453 /// `.add_` [`ErrorDetails`] methods. 454 /// 455 /// # Examples 456 /// 457 /// ``` 458 /// use tonic_types::ErrorDetails; 459 /// 460 /// let mut err_details = ErrorDetails::new(); 461 /// 462 /// let err_stack = vec!["...".into(), "...".into()]; 463 /// 464 /// err_details.set_debug_info(err_stack, "error details"); 465 /// ``` set_debug_info( &mut self, stack_entries: impl Into<Vec<String>>, detail: impl Into<String>, ) -> &mut Self466 pub fn set_debug_info( 467 &mut self, 468 stack_entries: impl Into<Vec<String>>, 469 detail: impl Into<String>, 470 ) -> &mut Self { 471 self.debug_info = Some(DebugInfo::new(stack_entries, detail)); 472 self 473 } 474 475 /// Set [`QuotaFailure`] details. Can be chained with other `.set_` and 476 /// `.add_` [`ErrorDetails`] methods. 477 /// 478 /// # Examples 479 /// 480 /// ``` 481 /// use tonic_types::{ErrorDetails, QuotaViolation}; 482 /// 483 /// let mut err_details = ErrorDetails::new(); 484 /// 485 /// err_details.set_quota_failure(vec![ 486 /// QuotaViolation::new("subject 1", "description 1"), 487 /// QuotaViolation::new("subject 2", "description 2"), 488 /// ]); 489 /// ``` set_quota_failure(&mut self, violations: impl Into<Vec<QuotaViolation>>) -> &mut Self490 pub fn set_quota_failure(&mut self, violations: impl Into<Vec<QuotaViolation>>) -> &mut Self { 491 self.quota_failure = Some(QuotaFailure::new(violations)); 492 self 493 } 494 495 /// Adds a [`QuotaViolation`] to [`QuotaFailure`] details. Sets 496 /// [`QuotaFailure`] details if it is not set yet. Can be chained with 497 /// other `.set_` and `.add_` [`ErrorDetails`] methods. 498 /// 499 /// # Examples 500 /// 501 /// ``` 502 /// use tonic_types::ErrorDetails; 503 /// 504 /// let mut err_details = ErrorDetails::new(); 505 /// 506 /// err_details.add_quota_failure_violation("subject", "description"); 507 /// ``` add_quota_failure_violation( &mut self, subject: impl Into<String>, description: impl Into<String>, ) -> &mut Self508 pub fn add_quota_failure_violation( 509 &mut self, 510 subject: impl Into<String>, 511 description: impl Into<String>, 512 ) -> &mut Self { 513 match &mut self.quota_failure { 514 Some(quota_failure) => { 515 quota_failure.add_violation(subject, description); 516 } 517 None => { 518 self.quota_failure = Some(QuotaFailure::with_violation(subject, description)); 519 } 520 }; 521 self 522 } 523 524 /// Returns `true` if [`QuotaFailure`] is set and its `violations` vector 525 /// is not empty, otherwise returns `false`. 526 /// 527 /// # Examples 528 /// 529 /// ``` 530 /// use tonic_types::ErrorDetails; 531 /// 532 /// let mut err_details = ErrorDetails::with_quota_failure(vec![]); 533 /// 534 /// assert_eq!(err_details.has_quota_failure_violations(), false); 535 /// 536 /// err_details.add_quota_failure_violation("subject", "description"); 537 /// 538 /// assert_eq!(err_details.has_quota_failure_violations(), true); 539 /// ``` has_quota_failure_violations(&self) -> bool540 pub fn has_quota_failure_violations(&self) -> bool { 541 if let Some(quota_failure) = &self.quota_failure { 542 return !quota_failure.violations.is_empty(); 543 } 544 false 545 } 546 547 /// Set [`ErrorInfo`] details. Can be chained with other `.set_` and 548 /// `.add_` [`ErrorDetails`] methods. 549 /// 550 /// # Examples 551 /// 552 /// ``` 553 /// use std::collections::HashMap; 554 /// use tonic_types::ErrorDetails; 555 /// 556 /// let mut err_details = ErrorDetails::new(); 557 /// 558 /// let mut metadata: HashMap<String, String> = HashMap::new(); 559 /// metadata.insert("instanceLimitPerRequest".into(), "100".into()); 560 /// 561 /// err_details.set_error_info("reason", "example.local", metadata); 562 /// ``` set_error_info( &mut self, reason: impl Into<String>, domain: impl Into<String>, metadata: impl Into<HashMap<String, String>>, ) -> &mut Self563 pub fn set_error_info( 564 &mut self, 565 reason: impl Into<String>, 566 domain: impl Into<String>, 567 metadata: impl Into<HashMap<String, String>>, 568 ) -> &mut Self { 569 self.error_info = Some(ErrorInfo::new(reason, domain, metadata)); 570 self 571 } 572 573 /// Set [`PreconditionFailure`] details. Can be chained with other `.set_` 574 /// and `.add_` [`ErrorDetails`] methods. 575 /// 576 /// # Examples 577 /// 578 /// ``` 579 /// use tonic_types::{ErrorDetails, PreconditionViolation}; 580 /// 581 /// let mut err_details = ErrorDetails::new(); 582 /// 583 /// err_details.set_precondition_failure(vec![ 584 /// PreconditionViolation::new( 585 /// "violation type 1", 586 /// "subject 1", 587 /// "description 1", 588 /// ), 589 /// PreconditionViolation::new( 590 /// "violation type 2", 591 /// "subject 2", 592 /// "description 2", 593 /// ), 594 /// ]); 595 /// ``` set_precondition_failure( &mut self, violations: impl Into<Vec<PreconditionViolation>>, ) -> &mut Self596 pub fn set_precondition_failure( 597 &mut self, 598 violations: impl Into<Vec<PreconditionViolation>>, 599 ) -> &mut Self { 600 self.precondition_failure = Some(PreconditionFailure::new(violations)); 601 self 602 } 603 604 /// Adds a [`PreconditionViolation`] to [`PreconditionFailure`] details. 605 /// Sets [`PreconditionFailure`] details if it is not set yet. Can be 606 /// chained with other `.set_` and `.add_` [`ErrorDetails`] methods. 607 /// 608 /// # Examples 609 /// 610 /// ``` 611 /// use tonic_types::ErrorDetails; 612 /// 613 /// let mut err_details = ErrorDetails::new(); 614 /// 615 /// err_details.add_precondition_failure_violation( 616 /// "violation type", 617 /// "subject", 618 /// "description" 619 /// ); 620 /// ``` add_precondition_failure_violation( &mut self, violation_type: impl Into<String>, subject: impl Into<String>, description: impl Into<String>, ) -> &mut Self621 pub fn add_precondition_failure_violation( 622 &mut self, 623 violation_type: impl Into<String>, 624 subject: impl Into<String>, 625 description: impl Into<String>, 626 ) -> &mut Self { 627 match &mut self.precondition_failure { 628 Some(precondition_failure) => { 629 precondition_failure.add_violation(violation_type, subject, description); 630 } 631 None => { 632 self.precondition_failure = Some(PreconditionFailure::with_violation( 633 violation_type, 634 subject, 635 description, 636 )); 637 } 638 }; 639 self 640 } 641 642 /// Returns `true` if [`PreconditionFailure`] is set and its `violations` 643 /// vector is not empty, otherwise returns `false`. 644 /// 645 /// # Examples 646 /// 647 /// ``` 648 /// use tonic_types::ErrorDetails; 649 /// 650 /// let mut err_details = ErrorDetails::with_precondition_failure(vec![]); 651 /// 652 /// assert_eq!(err_details.has_precondition_failure_violations(), false); 653 /// 654 /// err_details.add_precondition_failure_violation( 655 /// "violation type", 656 /// "subject", 657 /// "description" 658 /// ); 659 /// 660 /// assert_eq!(err_details.has_precondition_failure_violations(), true); 661 /// ``` has_precondition_failure_violations(&self) -> bool662 pub fn has_precondition_failure_violations(&self) -> bool { 663 if let Some(precondition_failure) = &self.precondition_failure { 664 return !precondition_failure.violations.is_empty(); 665 } 666 false 667 } 668 669 /// Set [`BadRequest`] details. Can be chained with other `.set_` and 670 /// `.add_` [`ErrorDetails`] methods. 671 /// 672 /// # Examples 673 /// 674 /// ``` 675 /// use tonic_types::{ErrorDetails, FieldViolation}; 676 /// 677 /// let mut err_details = ErrorDetails::new(); 678 /// 679 /// err_details.set_bad_request(vec![ 680 /// FieldViolation::new("field_1", "description 1"), 681 /// FieldViolation::new("field_2", "description 2"), 682 /// ]); 683 /// ``` set_bad_request(&mut self, violations: impl Into<Vec<FieldViolation>>) -> &mut Self684 pub fn set_bad_request(&mut self, violations: impl Into<Vec<FieldViolation>>) -> &mut Self { 685 self.bad_request = Some(BadRequest::new(violations)); 686 self 687 } 688 689 /// Adds a [`FieldViolation`] to [`BadRequest`] details. Sets 690 /// [`BadRequest`] details if it is not set yet. Can be chained with other 691 /// `.set_` and `.add_` [`ErrorDetails`] methods. 692 /// 693 /// # Examples 694 /// 695 /// ``` 696 /// use tonic_types::ErrorDetails; 697 /// 698 /// let mut err_details = ErrorDetails::new(); 699 /// 700 /// err_details.add_bad_request_violation("field", "description"); 701 /// ``` add_bad_request_violation( &mut self, field: impl Into<String>, description: impl Into<String>, ) -> &mut Self702 pub fn add_bad_request_violation( 703 &mut self, 704 field: impl Into<String>, 705 description: impl Into<String>, 706 ) -> &mut Self { 707 match &mut self.bad_request { 708 Some(bad_request) => { 709 bad_request.add_violation(field, description); 710 } 711 None => { 712 self.bad_request = Some(BadRequest::with_violation(field, description)); 713 } 714 }; 715 self 716 } 717 718 /// Returns `true` if [`BadRequest`] is set and its `field_violations` 719 /// vector is not empty, otherwise returns `false`. 720 /// 721 /// # Examples 722 /// 723 /// ``` 724 /// use tonic_types::ErrorDetails; 725 /// 726 /// let mut err_details = ErrorDetails::with_bad_request(vec![]); 727 /// 728 /// assert_eq!(err_details.has_bad_request_violations(), false); 729 /// 730 /// err_details.add_bad_request_violation("field", "description"); 731 /// 732 /// assert_eq!(err_details.has_bad_request_violations(), true); 733 /// ``` has_bad_request_violations(&self) -> bool734 pub fn has_bad_request_violations(&self) -> bool { 735 if let Some(bad_request) = &self.bad_request { 736 return !bad_request.field_violations.is_empty(); 737 } 738 false 739 } 740 741 /// Set [`RequestInfo`] details. Can be chained with other `.set_` and 742 /// `.add_` [`ErrorDetails`] methods. 743 /// 744 /// # Examples 745 /// 746 /// ``` 747 /// use tonic_types::ErrorDetails; 748 /// 749 /// let mut err_details = ErrorDetails::new(); 750 /// 751 /// err_details.set_request_info("request_id", "serving_data"); 752 /// ``` set_request_info( &mut self, request_id: impl Into<String>, serving_data: impl Into<String>, ) -> &mut Self753 pub fn set_request_info( 754 &mut self, 755 request_id: impl Into<String>, 756 serving_data: impl Into<String>, 757 ) -> &mut Self { 758 self.request_info = Some(RequestInfo::new(request_id, serving_data)); 759 self 760 } 761 762 /// Set [`ResourceInfo`] details. Can be chained with other `.set_` and 763 /// `.add_` [`ErrorDetails`] methods. 764 /// 765 /// # Examples 766 /// 767 /// ``` 768 /// use tonic_types::ErrorDetails; 769 /// 770 /// let mut err_details = ErrorDetails::new(); 771 /// 772 /// err_details.set_resource_info("res_type", "res_name", "owner", "description"); 773 /// ``` set_resource_info( &mut self, resource_type: impl Into<String>, resource_name: impl Into<String>, owner: impl Into<String>, description: impl Into<String>, ) -> &mut Self774 pub fn set_resource_info( 775 &mut self, 776 resource_type: impl Into<String>, 777 resource_name: impl Into<String>, 778 owner: impl Into<String>, 779 description: impl Into<String>, 780 ) -> &mut Self { 781 self.resource_info = Some(ResourceInfo::new( 782 resource_type, 783 resource_name, 784 owner, 785 description, 786 )); 787 self 788 } 789 790 /// Set [`Help`] details. Can be chained with other `.set_` and `.add_` 791 /// [`ErrorDetails`] methods. 792 /// 793 /// # Examples 794 /// 795 /// ``` 796 /// use tonic_types::{ErrorDetails, HelpLink}; 797 /// 798 /// let mut err_details = ErrorDetails::new(); 799 /// 800 /// err_details.set_help(vec![ 801 /// HelpLink::new("description of link a", "resource-a.example.local"), 802 /// HelpLink::new("description of link b", "resource-b.example.local"), 803 /// ]); 804 /// ``` set_help(&mut self, links: impl Into<Vec<HelpLink>>) -> &mut Self805 pub fn set_help(&mut self, links: impl Into<Vec<HelpLink>>) -> &mut Self { 806 self.help = Some(Help::new(links)); 807 self 808 } 809 810 /// Adds a [`HelpLink`] to [`Help`] details. Sets [`Help`] details if it is 811 /// not set yet. Can be chained with other `.set_` and `.add_` 812 /// [`ErrorDetails`] methods. 813 /// 814 /// # Examples 815 /// 816 /// ``` 817 /// use tonic_types::ErrorDetails; 818 /// 819 /// let mut err_details = ErrorDetails::new(); 820 /// 821 /// err_details.add_help_link("description of link", "resource.example.local"); 822 /// ``` add_help_link( &mut self, description: impl Into<String>, url: impl Into<String>, ) -> &mut Self823 pub fn add_help_link( 824 &mut self, 825 description: impl Into<String>, 826 url: impl Into<String>, 827 ) -> &mut Self { 828 match &mut self.help { 829 Some(help) => { 830 help.add_link(description, url); 831 } 832 None => { 833 self.help = Some(Help::with_link(description, url)); 834 } 835 }; 836 self 837 } 838 839 /// Returns `true` if [`Help`] is set and its `links` vector is not empty, 840 /// otherwise returns `false`. 841 /// 842 /// # Examples 843 /// 844 /// ``` 845 /// use tonic_types::ErrorDetails; 846 /// 847 /// let mut err_details = ErrorDetails::with_help(vec![]); 848 /// 849 /// assert_eq!(err_details.has_help_links(), false); 850 /// 851 /// err_details.add_help_link("description of link", "resource.example.local"); 852 /// 853 /// assert_eq!(err_details.has_help_links(), true); 854 /// ``` has_help_links(&self) -> bool855 pub fn has_help_links(&self) -> bool { 856 if let Some(help) = &self.help { 857 return !help.links.is_empty(); 858 } 859 false 860 } 861 862 /// Set [`LocalizedMessage`] details. Can be chained with other `.set_` and 863 /// `.add_` [`ErrorDetails`] methods. 864 /// 865 /// # Examples 866 /// 867 /// ``` 868 /// use tonic_types::ErrorDetails; 869 /// 870 /// let mut err_details = ErrorDetails::new(); 871 /// 872 /// err_details.set_localized_message("en-US", "message for the user"); 873 /// ``` set_localized_message( &mut self, locale: impl Into<String>, message: impl Into<String>, ) -> &mut Self874 pub fn set_localized_message( 875 &mut self, 876 locale: impl Into<String>, 877 message: impl Into<String>, 878 ) -> &mut Self { 879 self.localized_message = Some(LocalizedMessage::new(locale, message)); 880 self 881 } 882 } 883