Skip to content

Commit

Permalink
feat(tonic-types): add ability to extract rich error details from `go…
Browse files Browse the repository at this point in the history
…ogle.rpc.Status` (#1430)

* feat: add from impls to convert between std_messages <-> pb

* feat: add trait to extract error details from pb::Status

* style: cargo fmt

---------

Co-authored-by: Lucio Franco <luciofranco14@gmail.com>
  • Loading branch information
kyle-mccarthy and LucioFranco committed Aug 25, 2023
1 parent fa0ffbb commit 5fd635a
Show file tree
Hide file tree
Showing 12 changed files with 550 additions and 208 deletions.
2 changes: 1 addition & 1 deletion tonic-types/src/lib.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 5fd635a

Please sign in to comment.