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}