1# tonic-types 2 3A collection of useful protobuf types that can be used with `tonic`. 4 5This crate also introduces the [`StatusExt`] trait and implements it in 6[`tonic::Status`], allowing the implementation of the [gRPC Richer Error Model] 7with [`tonic`] in a convenient way. 8 9## Usage 10 11Useful protobuf types are available through the [`pb`] module. They can be 12imported and worked with directly. 13 14The [`StatusExt`] trait adds associated functions to [`tonic::Status`] that can 15be used on the server side to create a status with error details, which can then 16be returned to gRPC clients. Moreover, the trait also adds methods to 17[`tonic::Status`] that can be used by a tonic client to extract error details, 18and handle them with ease. 19 20## Examples 21 22The examples bellow cover a basic use case of the [gRPC Richer Error Model]. 23More complete server and client implementations are provided in the 24**Richer Error example**, located in the main repo [examples] directory. 25 26### Server Side: Generating [`tonic::Status`] with an [`ErrorDetails`] struct 27 28```rust 29use tonic::{Code, Status}; 30use tonic_types::{ErrorDetails, StatusExt}; 31 32// ... 33// Inside a gRPC server endpoint that returns `Result<Response<T>, Status>` 34 35// Create empty `ErrorDetails` struct 36let mut err_details = ErrorDetails::new(); 37 38// Add error details conditionally 39if some_condition { 40 err_details.add_bad_request_violation( 41 "field_a", 42 "description of why the field_a is invalid" 43 ); 44} 45 46if other_condition { 47 err_details.add_bad_request_violation( 48 "field_b", 49 "description of why the field_b is invalid", 50 ); 51} 52 53// Check if any error details were set and return error status if so 54if err_details.has_bad_request_violations() { 55 // Add additional error details if necessary 56 err_details 57 .add_help_link("description of link", "https://resource.example.local") 58 .set_localized_message("en-US", "message for the user"); 59 60 let status = Status::with_error_details( 61 Code::InvalidArgument, 62 "bad request", 63 err_details, 64 ); 65 return Err(status); 66} 67 68// Handle valid request 69// ... 70``` 71 72### Client Side: Extracting an [`ErrorDetails`] struct from [`tonic::Status`] 73 74```rust 75use tonic::{Response, Status}; 76use tonic_types::StatusExt; 77 78// ... 79// Where `req_result` was returned by a gRPC client endpoint method 80fn handle_request_result<T>(req_result: Result<Response<T>, Status>) { 81 match req_result { 82 Ok(response) => { 83 // Handle successful response 84 }, 85 Err(status) => { 86 let err_details = status.get_error_details(); 87 if let Some(bad_request) = err_details.bad_request() { 88 // Handle bad_request details 89 } 90 if let Some(help) = err_details.help() { 91 // Handle help details 92 } 93 if let Some(localized_message) = err_details.localized_message() { 94 // Handle localized_message details 95 } 96 } 97 }; 98} 99``` 100 101## Working with different error message types 102 103Multiple examples are provided at the [`ErrorDetails`] doc. Instructions about 104how to use the fields of the standard error message types correctly are provided 105at [error_details.proto]. 106 107## Alternative `tonic::Status` associated functions and methods 108 109In the [`StatusExt`] doc, an alternative way of interacting with 110[`tonic::Status`] is presented, using vectors of error details structs wrapped 111with the [`ErrorDetail`] enum. This approach can provide more control over the 112vector of standard error messages that will be generated or that was received, 113if necessary. To see how to adopt this approach, please check the 114[`StatusExt::with_error_details_vec`] and [`StatusExt::get_error_details_vec`] 115docs, and also the main repo's [Richer Error example] directory. 116 117Besides that, multiple examples with alternative error details extraction 118methods are provided in the [`StatusExt`] doc, which can be specially 119useful if only one type of standard error message is being handled by the 120client. For example, using [`StatusExt::get_details_bad_request`] is a 121more direct way of extracting a [`BadRequest`] error message from 122[`tonic::Status`]. 123 124[`tonic::Status`]: https://docs.rs/tonic/latest/tonic/struct.Status.html 125[`tonic`]: https://docs.rs/tonic/latest/tonic/ 126[gRPC Richer Error Model]: https://www.grpc.io/docs/guides/error/ 127[`pb`]: https://docs.rs/tonic-types/latest/tonic_types/pb/index.html 128[`StatusExt`]: https://docs.rs/tonic-types/latest/tonic_types/trait.StatusExt.html 129[examples]: https://github.com/hyperium/tonic/tree/master/examples 130[`ErrorDetails`]: https://docs.rs/tonic-types/latest/tonic_types/struct.ErrorDetails.html 131[error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto 132[`ErrorDetail`]: https://docs.rs/tonic-types/latest/tonic_types/enum.ErrorDetail.html 133[`StatusExt::with_error_details_vec`]: https://docs.rs/tonic-types/latest/tonic_types/trait.StatusExt.html#tymethod.with_error_details_vec 134[`StatusExt::get_error_details_vec`]: https://docs.rs/tonic-types/latest/tonic_types/trait.StatusExt.html#tymethod.get_error_details_vec 135[Richer Error example]: https://github.com/hyperium/tonic/tree/master/examples/src/richer-error 136[`StatusExt::get_details_bad_request`]: https://docs.rs/tonic-types/latest/tonic_types/trait.StatusExt.html#tymethod.get_details_bad_request 137[`BadRequest`]: https://docs.rs/tonic-types/latest/tonic_types/struct.BadRequest.html