Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tonic-types): add ability to extract rich error details from google.rpc.Status #1430

Merged
merged 4 commits into from Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion tonic-types/src/lib.rs
Expand Up @@ -180,7 +180,7 @@ mod richer_error;
pub use richer_error::{
BadRequest, DebugInfo, ErrorDetail, ErrorDetails, ErrorInfo, FieldViolation, Help, HelpLink,
LocalizedMessage, PreconditionFailure, PreconditionViolation, QuotaFailure, QuotaViolation,
RequestInfo, ResourceInfo, RetryInfo, StatusExt,
RequestInfo, ResourceInfo, RetryInfo, RpcStatusExt, StatusExt,
};

mod sealed {
Expand Down
266 changes: 201 additions & 65 deletions tonic-types/src/richer_error/mod.rs

Large diffs are not rendered by default.

65 changes: 44 additions & 21 deletions tonic-types/src/richer_error/std_messages/bad_request.rs
@@ -1,6 +1,8 @@
use prost::{DecodeError, Message};
use prost_types::Any;

use crate::richer_error::FromAnyRef;

use super::super::{pb, FromAny, IntoAny};

/// Used at the `field_violations` field of the [`BadRequest`] struct.
Expand All @@ -26,6 +28,24 @@ impl FieldViolation {
}
}

impl From<pb::bad_request::FieldViolation> for FieldViolation {
fn from(value: pb::bad_request::FieldViolation) -> Self {
FieldViolation {
field: value.field,
description: value.description,
}
}
}

impl From<FieldViolation> for pb::bad_request::FieldViolation {
fn from(value: FieldViolation) -> Self {
pb::bad_request::FieldViolation {
field: value.field,
description: value.description,
}
}
}

/// Used to encode/decode the `BadRequest` standard error message described in
/// [error_details.proto]. Describes violations in a client request. Focuses
/// on the syntactic aspects of the request.
Expand Down Expand Up @@ -81,16 +101,7 @@ impl BadRequest {

impl IntoAny for BadRequest {
fn into_any(self) -> Any {
let detail_data = pb::BadRequest {
field_violations: self
.field_violations
.into_iter()
.map(|v| pb::bad_request::FieldViolation {
field: v.field,
description: v.description,
})
.collect(),
};
let detail_data: pb::BadRequest = self.into();

Any {
type_url: BadRequest::TYPE_URL.to_string(),
Expand All @@ -100,22 +111,34 @@ impl IntoAny for BadRequest {
}

impl FromAny for BadRequest {
#[inline]
fn from_any(any: Any) -> Result<Self, DecodeError> {
FromAnyRef::from_any_ref(&any)
}
}

impl FromAnyRef for BadRequest {
fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {
let buf: &[u8] = &any.value;
let bad_req = pb::BadRequest::decode(buf)?;

let bad_req = BadRequest {
field_violations: bad_req
.field_violations
.into_iter()
.map(|v| FieldViolation {
field: v.field,
description: v.description,
})
.collect(),
};
Ok(bad_req.into())
}
}

Ok(bad_req)
impl From<pb::BadRequest> for BadRequest {
fn from(value: pb::BadRequest) -> Self {
BadRequest {
field_violations: value.field_violations.into_iter().map(Into::into).collect(),
}
}
}

impl From<BadRequest> for pb::BadRequest {
fn from(value: BadRequest) -> Self {
pb::BadRequest {
field_violations: value.field_violations.into_iter().map(Into::into).collect(),
}
}
}

Expand Down
33 changes: 26 additions & 7 deletions tonic-types/src/richer_error/std_messages/debug_info.rs
@@ -1,6 +1,8 @@
use prost::{DecodeError, Message};
use prost_types::Any;

use crate::richer_error::FromAnyRef;

use super::super::{pb, FromAny, IntoAny};

/// Used to encode/decode the `DebugInfo` standard error message described in
Expand Down Expand Up @@ -37,10 +39,7 @@ impl DebugInfo {

impl IntoAny for DebugInfo {
fn into_any(self) -> Any {
let detail_data = pb::DebugInfo {
stack_entries: self.stack_entries,
detail: self.detail,
};
let detail_data: pb::DebugInfo = self.into();

Any {
type_url: DebugInfo::TYPE_URL.to_string(),
Expand All @@ -50,16 +49,36 @@ impl IntoAny for DebugInfo {
}

impl FromAny for DebugInfo {
#[inline]
fn from_any(any: Any) -> Result<Self, DecodeError> {
FromAnyRef::from_any_ref(&any)
}
}

impl FromAnyRef for DebugInfo {
fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {
let buf: &[u8] = &any.value;
let debug_info = pb::DebugInfo::decode(buf)?;

let debug_info = DebugInfo {
Ok(debug_info.into())
}
}

impl From<pb::DebugInfo> for DebugInfo {
fn from(debug_info: pb::DebugInfo) -> Self {
DebugInfo {
stack_entries: debug_info.stack_entries,
detail: debug_info.detail,
};
}
}
}

Ok(debug_info)
impl From<DebugInfo> for pb::DebugInfo {
fn from(debug_info: DebugInfo) -> Self {
pb::DebugInfo {
stack_entries: debug_info.stack_entries,
detail: debug_info.detail,
}
}
}

Expand Down
35 changes: 27 additions & 8 deletions tonic-types/src/richer_error/std_messages/error_info.rs
Expand Up @@ -3,6 +3,8 @@ use std::collections::HashMap;
use prost::{DecodeError, Message};
use prost_types::Any;

use crate::richer_error::FromAnyRef;

use super::super::{pb, FromAny, IntoAny};

/// Used to encode/decode the `ErrorInfo` standard error message described in
Expand Down Expand Up @@ -53,11 +55,7 @@ impl ErrorInfo {

impl IntoAny for ErrorInfo {
fn into_any(self) -> Any {
let detail_data = pb::ErrorInfo {
reason: self.reason,
domain: self.domain,
metadata: self.metadata,
};
let detail_data: pb::ErrorInfo = self.into();

Any {
type_url: ErrorInfo::TYPE_URL.to_string(),
Expand All @@ -67,17 +65,38 @@ impl IntoAny for ErrorInfo {
}

impl FromAny for ErrorInfo {
#[inline]
fn from_any(any: Any) -> Result<Self, DecodeError> {
FromAnyRef::from_any_ref(&any)
}
}

impl FromAnyRef for ErrorInfo {
fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {
let buf: &[u8] = &any.value;
let error_info = pb::ErrorInfo::decode(buf)?;

let error_info = ErrorInfo {
Ok(error_info.into())
}
}

impl From<pb::ErrorInfo> for ErrorInfo {
fn from(error_info: pb::ErrorInfo) -> Self {
ErrorInfo {
reason: error_info.reason,
domain: error_info.domain,
metadata: error_info.metadata,
};
}
}
}

Ok(error_info)
impl From<ErrorInfo> for pb::ErrorInfo {
fn from(error_info: ErrorInfo) -> Self {
pb::ErrorInfo {
reason: error_info.reason,
domain: error_info.domain,
metadata: error_info.metadata,
}
}
}

Expand Down
65 changes: 44 additions & 21 deletions tonic-types/src/richer_error/std_messages/help.rs
@@ -1,6 +1,8 @@
use prost::{DecodeError, Message};
use prost_types::Any;

use crate::richer_error::FromAnyRef;

use super::super::{pb, FromAny, IntoAny};

/// Used at the `links` field of the [`Help`] struct. Describes a URL link.
Expand All @@ -23,6 +25,24 @@ impl HelpLink {
}
}

impl From<pb::help::Link> for HelpLink {
fn from(value: pb::help::Link) -> Self {
HelpLink {
description: value.description,
url: value.url,
}
}
}

impl From<HelpLink> for pb::help::Link {
fn from(value: HelpLink) -> Self {
pb::help::Link {
description: value.description,
url: value.url,
}
}
}

/// Used to encode/decode the `Help` standard error message described in
/// [error_details.proto]. Provides links to documentation or for performing
/// an out-of-band action.
Expand Down Expand Up @@ -77,16 +97,7 @@ impl Help {

impl IntoAny for Help {
fn into_any(self) -> Any {
let detail_data = pb::Help {
links: self
.links
.into_iter()
.map(|v| pb::help::Link {
description: v.description,
url: v.url,
})
.collect(),
};
let detail_data: pb::Help = self.into();

Any {
type_url: Help::TYPE_URL.to_string(),
Expand All @@ -96,22 +107,34 @@ impl IntoAny for Help {
}

impl FromAny for Help {
#[inline]
fn from_any(any: Any) -> Result<Self, DecodeError> {
FromAnyRef::from_any_ref(&any)
}
}

impl FromAnyRef for Help {
fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {
let buf: &[u8] = &any.value;
let help = pb::Help::decode(buf)?;

let help = Help {
links: help
.links
.into_iter()
.map(|v| HelpLink {
description: v.description,
url: v.url,
})
.collect(),
};
Ok(help.into())
}
}

Ok(help)
impl From<pb::Help> for Help {
fn from(value: pb::Help) -> Self {
Help {
links: value.links.into_iter().map(Into::into).collect(),
}
}
}

impl From<Help> for pb::Help {
fn from(value: Help) -> Self {
pb::Help {
links: value.links.into_iter().map(Into::into).collect(),
}
}
}

Expand Down
33 changes: 26 additions & 7 deletions tonic-types/src/richer_error/std_messages/loc_message.rs
@@ -1,6 +1,8 @@
use prost::{DecodeError, Message};
use prost_types::Any;

use crate::richer_error::FromAnyRef;

use super::super::{pb, FromAny, IntoAny};

/// Used to encode/decode the `LocalizedMessage` standard error message
Expand Down Expand Up @@ -41,10 +43,7 @@ impl LocalizedMessage {

impl IntoAny for LocalizedMessage {
fn into_any(self) -> Any {
let detail_data = pb::LocalizedMessage {
locale: self.locale,
message: self.message,
};
let detail_data: pb::LocalizedMessage = self.into();

Any {
type_url: LocalizedMessage::TYPE_URL.to_string(),
Expand All @@ -54,16 +53,36 @@ impl IntoAny for LocalizedMessage {
}

impl FromAny for LocalizedMessage {
#[inline]
fn from_any(any: Any) -> Result<Self, DecodeError> {
FromAnyRef::from_any_ref(&any)
}
}

impl FromAnyRef for LocalizedMessage {
fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {
let buf: &[u8] = &any.value;
let loc_message = pb::LocalizedMessage::decode(buf)?;

let loc_message = LocalizedMessage {
Ok(loc_message.into())
}
}

impl From<pb::LocalizedMessage> for LocalizedMessage {
fn from(loc_message: pb::LocalizedMessage) -> Self {
LocalizedMessage {
locale: loc_message.locale,
message: loc_message.message,
};
}
}
}

Ok(loc_message)
impl From<LocalizedMessage> for pb::LocalizedMessage {
fn from(loc_message: LocalizedMessage) -> Self {
pb::LocalizedMessage {
locale: loc_message.locale,
message: loc_message.message,
}
}
}

Expand Down