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