Skip to main content

tonic_types/
lib.rs

1/*
2 *
3 * Copyright 2025 gRPC authors.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 */
24
25//! A collection of useful protobuf types that can be used with `tonic`.
26//!
27//! This crate also introduces the [`StatusExt`] trait and implements it in
28//! [`tonic::Status`], allowing the implementation of the
29//! [gRPC Richer Error Model] with [`tonic`] in a convenient way.
30//!
31//! # Usage
32//!
33//! Useful protobuf types are available through the [`pb`] module. They can be
34//! imported and worked with directly.
35//!
36//! The [`StatusExt`] trait adds associated functions to [`tonic::Status`] that
37//! can be used on the server side to create a status with error details, which
38//! can then be returned to gRPC clients. Moreover, the trait also adds methods
39//! to [`tonic::Status`] that can be used by a tonic client to extract error
40//! details, and handle them with ease.
41//!
42//! # Getting Started
43//!
44//! ```toml
45//! [dependencies]
46//! tonic = <tonic-version>
47//! tonic-types = <tonic-types-version>
48//! ```
49//!
50//! # Examples
51//!
52//! The examples below cover a basic use case of the [gRPC Richer Error Model].
53//! More complete server and client implementations are provided in the
54//! **Richer Error example**, located in the main repo [examples] directory.
55//!
56//! ## Server Side: Generating [`tonic::Status`] with an [`ErrorDetails`] struct
57//!
58//! ```
59//! use tonic::{Code, Status};
60//! use tonic_types::{ErrorDetails, StatusExt};
61//!
62//! # async fn endpoint() -> Result<tonic::Response<()>, Status> {
63//! // ...
64//! // Inside a gRPC server endpoint that returns `Result<Response<T>, Status>`
65//!
66//! // Create empty `ErrorDetails` struct
67//! let mut err_details = ErrorDetails::new();
68//!
69//! // Add error details conditionally
70//! # let some_condition = true;
71//! if some_condition {
72//!     err_details.add_bad_request_violation(
73//!         "field_a",
74//!         "description of why the field_a is invalid"
75//!     );
76//! }
77//!
78//! # let other_condition = true;
79//! if other_condition {
80//!     err_details.add_bad_request_violation(
81//!         "field_b",
82//!         "description of why the field_b is invalid",
83//!     );
84//! }
85//!
86//! // Check if any error details were set and return error status if so
87//! if err_details.has_bad_request_violations() {
88//!     // Add additional error details if necessary
89//!     err_details
90//!         .add_help_link("description of link", "https://resource.example.local")
91//!         .set_localized_message("en-US", "message for the user");
92//!
93//!     let status = Status::with_error_details(
94//!         Code::InvalidArgument,
95//!         "bad request",
96//!         err_details,
97//!     );
98//!     return Err(status);
99//! }
100//!
101//! // Handle valid request
102//! // ...
103//! # Ok(tonic::Response::new(()))
104//! # }
105//! ```
106//!
107//! ## Client Side: Extracting an [`ErrorDetails`] struct from `tonic::Status`
108//!
109//! ```
110//! use tonic::{Response, Status};
111//! use tonic_types::StatusExt;
112//!
113//! // ...
114//! // Where `req_result` was returned by a gRPC client endpoint method
115//! fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {
116//!     match req_result {
117//!         Ok(response) => {
118//!             // Handle successful response
119//!         },
120//!         Err(status) => {
121//!             let err_details = status.get_error_details();
122//!             if let Some(bad_request) = err_details.bad_request() {
123//!                 // Handle bad_request details
124//!             }
125//!             if let Some(help) = err_details.help() {
126//!                 // Handle help details
127//!             }
128//!             if let Some(localized_message) = err_details.localized_message() {
129//!                 // Handle localized_message details
130//!             }
131//!         }
132//!     };
133//! }
134//! ```
135//!
136//! # Working with different error message types
137//!
138//! Multiple examples are provided at the [`ErrorDetails`] doc. Instructions
139//! about how to use the fields of the standard error message types correctly
140//! are provided at [error_details.proto].
141//!
142//! # Alternative `tonic::Status` associated functions and methods
143//!
144//! In the [`StatusExt`] doc, an alternative way of interacting with
145//! [`tonic::Status`] is presented, using vectors of error details structs
146//! wrapped with the [`ErrorDetail`] enum. This approach can provide more
147//! control over the vector of standard error messages that will be generated or
148//! that was received, if necessary. To see how to adopt this approach, please
149//! check the [`StatusExt::with_error_details_vec`] and
150//! [`StatusExt::get_error_details_vec`] docs, and also the main repo's
151//! [Richer Error example] directory.
152//!
153//! Besides that, multiple examples with alternative error details extraction
154//! methods are provided in the [`StatusExt`] doc, which can be specially
155//! useful if only one type of standard error message is being handled by the
156//! client. For example, using [`StatusExt::get_details_bad_request`] is a
157//! more direct way of extracting a [`BadRequest`] error message from
158//! [`tonic::Status`].
159//!
160//! [`tonic::Status`]: https://docs.rs/tonic/latest/tonic/struct.Status.html
161//! [`tonic`]: https://docs.rs/tonic/latest/tonic/
162//! [gRPC Richer Error Model]: https://www.grpc.io/docs/guides/error/
163//! [examples]: https://github.com/grpc/grpc-rust/tree/master/examples
164//! [error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto
165//! [Richer Error example]: https://github.com/grpc/grpc-rust/tree/master/examples/src/richer-error
166
167#![doc(
168    html_logo_url = "https://raw.githubusercontent.com/tokio-rs/website/master/public/img/icons/tonic.svg"
169)]
170#![doc(issue_tracker_base_url = "https://github.com/grpc/grpc-rust/issues/")]
171
172mod generated {
173    #![allow(unreachable_pub)]
174    #![allow(rustdoc::invalid_html_tags)]
175    #[rustfmt::skip]
176    pub mod google_rpc;
177    #[rustfmt::skip]
178    pub mod types_fds;
179
180    pub use types_fds::FILE_DESCRIPTOR_SET;
181
182    #[cfg(test)]
183    mod tests {
184        use super::FILE_DESCRIPTOR_SET;
185        use prost::Message as _;
186
187        #[test]
188        fn file_descriptor_set_is_valid() {
189            prost_types::FileDescriptorSet::decode(FILE_DESCRIPTOR_SET).unwrap();
190        }
191    }
192}
193
194/// Useful protobuf types
195pub mod pb {
196    pub use crate::generated::{FILE_DESCRIPTOR_SET, google_rpc::*};
197}
198
199pub use pb::Status;
200
201mod richer_error;
202
203pub use richer_error::{
204    BadRequest, DebugInfo, ErrorDetail, ErrorDetails, ErrorInfo, FieldViolation, Help, HelpLink,
205    LocalizedMessage, PreconditionFailure, PreconditionViolation, QuotaFailure, QuotaViolation,
206    RequestInfo, ResourceInfo, RetryInfo, RpcStatusExt, StatusExt,
207};
208
209mod sealed {
210    pub trait Sealed {}
211}