Skip to content

Commit 3e40d81

Browse files
authored
feat(types): Add gRPC Richer Error Model support (BadRequest) (#1068)
* types: add tonic as dependency, add error_details.proto * types: add BadRequest support from flemosr/tonic-richer-error * types: adjust code following suggestions Adjustments following suggestions by @LucioFranco in #1068. Adjust style, remove unecessary prints, avoid glob imports, apply `non_exhaustive` to `ErrorDetails` and `ErrorDetail`, avoid pub fields in `ErrorDetails`, adjust `WithErrorDetails::with_error_details_vec` args, add `gen_details_bytes`. * types: add generated protobuf code As suggested by @LucioFranco in #1068 (comment). This avoids the need for consumers to have `protoc` in their path. Implemented following changes in #1065. * types: add custom metadata support This allows consumers to provide custom metadata when creating a `Status` with error details. * types: adjust code following suggestions Adjustments following suggestions by @LucioFranco in #1068. Move `error_details_vec` mod into `error_details` mod, adjust doc comments, rename `WithErrorDetails` trait to `StatusExt`.
1 parent ee3d0df commit 3e40d81

File tree

11 files changed

+1358
-7
lines changed

11 files changed

+1358
-7
lines changed

tonic-types/Cargo.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ version = "0.6.0"
1717
[dependencies]
1818
prost = "0.11"
1919
prost-types = "0.11"
20+
tonic = {version = "0.8", path = "../tonic"}
2021

21-
[build-dependencies]
22-
prost-build = "0.11"
22+
[dev-dependencies]
23+
tonic-build = {version = "0.8", path = "../tonic-build", features = ["prost"]}

tonic-types/build.rs

-3
This file was deleted.

tonic-types/proto/error_details.proto

+250
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
// Copyright 2020 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
syntax = "proto3";
16+
17+
package google.rpc;
18+
19+
import "google/protobuf/duration.proto";
20+
21+
option go_package = "google.golang.org/genproto/googleapis/rpc/errdetails;errdetails";
22+
option java_multiple_files = true;
23+
option java_outer_classname = "ErrorDetailsProto";
24+
option java_package = "com.google.rpc";
25+
option objc_class_prefix = "RPC";
26+
27+
// Describes when the clients can retry a failed request. Clients could ignore
28+
// the recommendation here or retry when this information is missing from error
29+
// responses.
30+
//
31+
// It's always recommended that clients should use exponential backoff when
32+
// retrying.
33+
//
34+
// Clients should wait until `retry_delay` amount of time has passed since
35+
// receiving the error response before retrying. If retrying requests also
36+
// fail, clients should use an exponential backoff scheme to gradually increase
37+
// the delay between retries based on `retry_delay`, until either a maximum
38+
// number of retries have been reached or a maximum retry delay cap has been
39+
// reached.
40+
message RetryInfo {
41+
// Clients should wait at least this long between retrying the same request.
42+
google.protobuf.Duration retry_delay = 1;
43+
}
44+
45+
// Describes additional debugging info.
46+
message DebugInfo {
47+
// The stack trace entries indicating where the error occurred.
48+
repeated string stack_entries = 1;
49+
50+
// Additional debugging information provided by the server.
51+
string detail = 2;
52+
}
53+
54+
// Describes how a quota check failed.
55+
//
56+
// For example if a daily limit was exceeded for the calling project,
57+
// a service could respond with a QuotaFailure detail containing the project
58+
// id and the description of the quota limit that was exceeded. If the
59+
// calling project hasn't enabled the service in the developer console, then
60+
// a service could respond with the project id and set `service_disabled`
61+
// to true.
62+
//
63+
// Also see RetryInfo and Help types for other details about handling a
64+
// quota failure.
65+
message QuotaFailure {
66+
// A message type used to describe a single quota violation. For example, a
67+
// daily quota or a custom quota that was exceeded.
68+
message Violation {
69+
// The subject on which the quota check failed.
70+
// For example, "clientip:<ip address of client>" or "project:<Google
71+
// developer project id>".
72+
string subject = 1;
73+
74+
// A description of how the quota check failed. Clients can use this
75+
// description to find more about the quota configuration in the service's
76+
// public documentation, or find the relevant quota limit to adjust through
77+
// developer console.
78+
//
79+
// For example: "Service disabled" or "Daily Limit for read operations
80+
// exceeded".
81+
string description = 2;
82+
}
83+
84+
// Describes all quota violations.
85+
repeated Violation violations = 1;
86+
}
87+
88+
// Describes the cause of the error with structured details.
89+
//
90+
// Example of an error when contacting the "pubsub.googleapis.com" API when it
91+
// is not enabled:
92+
// ```json
93+
// { "reason": "API_DISABLED"
94+
// "domain": "googleapis.com"
95+
// "metadata": {
96+
// "resource": "projects/123",
97+
// "service": "pubsub.googleapis.com"
98+
// }
99+
// }
100+
// ```
101+
// This response indicates that the pubsub.googleapis.com API is not enabled.
102+
//
103+
// Example of an error that is returned when attempting to create a Spanner
104+
// instance in a region that is out of stock:
105+
// ```json
106+
// { "reason": "STOCKOUT"
107+
// "domain": "spanner.googleapis.com",
108+
// "metadata": {
109+
// "availableRegions": "us-central1,us-east2"
110+
// }
111+
// }
112+
// ```
113+
message ErrorInfo {
114+
// The reason of the error. This is a constant value that identifies the
115+
// proximate cause of the error. Error reasons are unique within a particular
116+
// domain of errors. This should be at most 63 characters and match
117+
// /[A-Z0-9_]+/.
118+
string reason = 1;
119+
120+
// The logical grouping to which the "reason" belongs. The error domain
121+
// is typically the registered service name of the tool or product that
122+
// generates the error. Example: "pubsub.googleapis.com". If the error is
123+
// generated by some common infrastructure, the error domain must be a
124+
// globally unique value that identifies the infrastructure. For Google API
125+
// infrastructure, the error domain is "googleapis.com".
126+
string domain = 2;
127+
128+
// Additional structured details about this error.
129+
//
130+
// Keys should match /[a-zA-Z0-9-_]/ and be limited to 64 characters in
131+
// length. When identifying the current value of an exceeded limit, the units
132+
// should be contained in the key, not the value. For example, rather than
133+
// {"instanceLimit": "100/request"}, should be returned as,
134+
// {"instanceLimitPerRequest": "100"}, if the client exceeds the number of
135+
// instances that can be created in a single (batch) request.
136+
map<string, string> metadata = 3;
137+
}
138+
139+
// Describes what preconditions have failed.
140+
//
141+
// For example, if an RPC failed because it required the Terms of Service to be
142+
// acknowledged, it could list the terms of service violation in the
143+
// PreconditionFailure message.
144+
message PreconditionFailure {
145+
// A message type used to describe a single precondition failure.
146+
message Violation {
147+
// The type of PreconditionFailure. We recommend using a service-specific
148+
// enum type to define the supported precondition violation subjects. For
149+
// example, "TOS" for "Terms of Service violation".
150+
string type = 1;
151+
152+
// The subject, relative to the type, that failed.
153+
// For example, "google.com/cloud" relative to the "TOS" type would indicate
154+
// which terms of service is being referenced.
155+
string subject = 2;
156+
157+
// A description of how the precondition failed. Developers can use this
158+
// description to understand how to fix the failure.
159+
//
160+
// For example: "Terms of service not accepted".
161+
string description = 3;
162+
}
163+
164+
// Describes all precondition violations.
165+
repeated Violation violations = 1;
166+
}
167+
168+
// Describes violations in a client request. This error type focuses on the
169+
// syntactic aspects of the request.
170+
message BadRequest {
171+
// A message type used to describe a single bad request field.
172+
message FieldViolation {
173+
// A path leading to a field in the request body. The value will be a
174+
// sequence of dot-separated identifiers that identify a protocol buffer
175+
// field. E.g., "field_violations.field" would identify this field.
176+
string field = 1;
177+
178+
// A description of why the request element is bad.
179+
string description = 2;
180+
}
181+
182+
// Describes all violations in a client request.
183+
repeated FieldViolation field_violations = 1;
184+
}
185+
186+
// Contains metadata about the request that clients can attach when filing a bug
187+
// or providing other forms of feedback.
188+
message RequestInfo {
189+
// An opaque string that should only be interpreted by the service generating
190+
// it. For example, it can be used to identify requests in the service's logs.
191+
string request_id = 1;
192+
193+
// Any data that was used to serve this request. For example, an encrypted
194+
// stack trace that can be sent back to the service provider for debugging.
195+
string serving_data = 2;
196+
}
197+
198+
// Describes the resource that is being accessed.
199+
message ResourceInfo {
200+
// A name for the type of resource being accessed, e.g. "sql table",
201+
// "cloud storage bucket", "file", "Google calendar"; or the type URL
202+
// of the resource: e.g. "type.googleapis.com/google.pubsub.v1.Topic".
203+
string resource_type = 1;
204+
205+
// The name of the resource being accessed. For example, a shared calendar
206+
// name: "[email protected]", if the current
207+
// error is [google.rpc.Code.PERMISSION_DENIED][google.rpc.Code.PERMISSION_DENIED].
208+
string resource_name = 2;
209+
210+
// The owner of the resource (optional).
211+
// For example, "user:<owner email>" or "project:<Google developer project
212+
// id>".
213+
string owner = 3;
214+
215+
// Describes what error is encountered when accessing this resource.
216+
// For example, updating a cloud project may require the `writer` permission
217+
// on the developer console project.
218+
string description = 4;
219+
}
220+
221+
// Provides links to documentation or for performing an out of band action.
222+
//
223+
// For example, if a quota check failed with an error indicating the calling
224+
// project hasn't enabled the accessed service, this can contain a URL pointing
225+
// directly to the right place in the developer console to flip the bit.
226+
message Help {
227+
// Describes a URL link.
228+
message Link {
229+
// Describes what the link offers.
230+
string description = 1;
231+
232+
// The URL of the link.
233+
string url = 2;
234+
}
235+
236+
// URL(s) pointing to additional information on handling the current error.
237+
repeated Link links = 1;
238+
}
239+
240+
// Provides a localized error message that is safe to return to the user
241+
// which can be attached to an RPC error.
242+
message LocalizedMessage {
243+
// The locale used following the specification defined at
244+
// http://www.rfc-editor.org/rfc/bcp/bcp47.txt.
245+
// Examples are: "en-US", "fr-CH", "es-MX"
246+
string locale = 1;
247+
248+
// The localized error message in the above locale.
249+
string message = 2;
250+
}

0 commit comments

Comments
 (0)