xref: /aosp_15_r20/external/googleapis/google/api/routing.proto (revision d5c09012810ac0c9f33fe448fb6da8260d444cc9)
1// Copyright 2023 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
15syntax = "proto3";
16
17package google.api;
18
19import "google/protobuf/descriptor.proto";
20
21option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
22option java_multiple_files = true;
23option java_outer_classname = "RoutingProto";
24option java_package = "com.google.api";
25option objc_class_prefix = "GAPI";
26
27extend google.protobuf.MethodOptions {
28  // See RoutingRule.
29  google.api.RoutingRule routing = 72295729;
30}
31
32// Specifies the routing information that should be sent along with the request
33// in the form of routing header.
34// **NOTE:** All service configuration rules follow the "last one wins" order.
35//
36// The examples below will apply to an RPC which has the following request type:
37//
38// Message Definition:
39//
40//     message Request {
41//       // The name of the Table
42//       // Values can be of the following formats:
43//       // - `projects/<project>/tables/<table>`
44//       // - `projects/<project>/instances/<instance>/tables/<table>`
45//       // - `region/<region>/zones/<zone>/tables/<table>`
46//       string table_name = 1;
47//
48//       // This value specifies routing for replication.
49//       // It can be in the following formats:
50//       // - `profiles/<profile_id>`
51//       // - a legacy `profile_id` that can be any string
52//       string app_profile_id = 2;
53//     }
54//
55// Example message:
56//
57//     {
58//       table_name: projects/proj_foo/instances/instance_bar/table/table_baz,
59//       app_profile_id: profiles/prof_qux
60//     }
61//
62// The routing header consists of one or multiple key-value pairs. Every key
63// and value must be percent-encoded, and joined together in the format of
64// `key1=value1&key2=value2`.
65// In the examples below I am skipping the percent-encoding for readablity.
66//
67// Example 1
68//
69// Extracting a field from the request to put into the routing header
70// unchanged, with the key equal to the field name.
71//
72// annotation:
73//
74//     option (google.api.routing) = {
75//       // Take the `app_profile_id`.
76//       routing_parameters {
77//         field: "app_profile_id"
78//       }
79//     };
80//
81// result:
82//
83//     x-goog-request-params: app_profile_id=profiles/prof_qux
84//
85// Example 2
86//
87// Extracting a field from the request to put into the routing header
88// unchanged, with the key different from the field name.
89//
90// annotation:
91//
92//     option (google.api.routing) = {
93//       // Take the `app_profile_id`, but name it `routing_id` in the header.
94//       routing_parameters {
95//         field: "app_profile_id"
96//         path_template: "{routing_id=**}"
97//       }
98//     };
99//
100// result:
101//
102//     x-goog-request-params: routing_id=profiles/prof_qux
103//
104// Example 3
105//
106// Extracting a field from the request to put into the routing
107// header, while matching a path template syntax on the field's value.
108//
109// NB: it is more useful to send nothing than to send garbage for the purpose
110// of dynamic routing, since garbage pollutes cache. Thus the matching.
111//
112// Sub-example 3a
113//
114// The field matches the template.
115//
116// annotation:
117//
118//     option (google.api.routing) = {
119//       // Take the `table_name`, if it's well-formed (with project-based
120//       // syntax).
121//       routing_parameters {
122//         field: "table_name"
123//         path_template: "{table_name=projects/*/instances/*/**}"
124//       }
125//     };
126//
127// result:
128//
129//     x-goog-request-params:
130//     table_name=projects/proj_foo/instances/instance_bar/table/table_baz
131//
132// Sub-example 3b
133//
134// The field does not match the template.
135//
136// annotation:
137//
138//     option (google.api.routing) = {
139//       // Take the `table_name`, if it's well-formed (with region-based
140//       // syntax).
141//       routing_parameters {
142//         field: "table_name"
143//         path_template: "{table_name=regions/*/zones/*/**}"
144//       }
145//     };
146//
147// result:
148//
149//     <no routing header will be sent>
150//
151// Sub-example 3c
152//
153// Multiple alternative conflictingly named path templates are
154// specified. The one that matches is used to construct the header.
155//
156// annotation:
157//
158//     option (google.api.routing) = {
159//       // Take the `table_name`, if it's well-formed, whether
160//       // using the region- or projects-based syntax.
161//
162//       routing_parameters {
163//         field: "table_name"
164//         path_template: "{table_name=regions/*/zones/*/**}"
165//       }
166//       routing_parameters {
167//         field: "table_name"
168//         path_template: "{table_name=projects/*/instances/*/**}"
169//       }
170//     };
171//
172// result:
173//
174//     x-goog-request-params:
175//     table_name=projects/proj_foo/instances/instance_bar/table/table_baz
176//
177// Example 4
178//
179// Extracting a single routing header key-value pair by matching a
180// template syntax on (a part of) a single request field.
181//
182// annotation:
183//
184//     option (google.api.routing) = {
185//       // Take just the project id from the `table_name` field.
186//       routing_parameters {
187//         field: "table_name"
188//         path_template: "{routing_id=projects/*}/**"
189//       }
190//     };
191//
192// result:
193//
194//     x-goog-request-params: routing_id=projects/proj_foo
195//
196// Example 5
197//
198// Extracting a single routing header key-value pair by matching
199// several conflictingly named path templates on (parts of) a single request
200// field. The last template to match "wins" the conflict.
201//
202// annotation:
203//
204//     option (google.api.routing) = {
205//       // If the `table_name` does not have instances information,
206//       // take just the project id for routing.
207//       // Otherwise take project + instance.
208//
209//       routing_parameters {
210//         field: "table_name"
211//         path_template: "{routing_id=projects/*}/**"
212//       }
213//       routing_parameters {
214//         field: "table_name"
215//         path_template: "{routing_id=projects/*/instances/*}/**"
216//       }
217//     };
218//
219// result:
220//
221//     x-goog-request-params:
222//     routing_id=projects/proj_foo/instances/instance_bar
223//
224// Example 6
225//
226// Extracting multiple routing header key-value pairs by matching
227// several non-conflicting path templates on (parts of) a single request field.
228//
229// Sub-example 6a
230//
231// Make the templates strict, so that if the `table_name` does not
232// have an instance information, nothing is sent.
233//
234// annotation:
235//
236//     option (google.api.routing) = {
237//       // The routing code needs two keys instead of one composite
238//       // but works only for the tables with the "project-instance" name
239//       // syntax.
240//
241//       routing_parameters {
242//         field: "table_name"
243//         path_template: "{project_id=projects/*}/instances/*/**"
244//       }
245//       routing_parameters {
246//         field: "table_name"
247//         path_template: "projects/*/{instance_id=instances/*}/**"
248//       }
249//     };
250//
251// result:
252//
253//     x-goog-request-params:
254//     project_id=projects/proj_foo&instance_id=instances/instance_bar
255//
256// Sub-example 6b
257//
258// Make the templates loose, so that if the `table_name` does not
259// have an instance information, just the project id part is sent.
260//
261// annotation:
262//
263//     option (google.api.routing) = {
264//       // The routing code wants two keys instead of one composite
265//       // but will work with just the `project_id` for tables without
266//       // an instance in the `table_name`.
267//
268//       routing_parameters {
269//         field: "table_name"
270//         path_template: "{project_id=projects/*}/**"
271//       }
272//       routing_parameters {
273//         field: "table_name"
274//         path_template: "projects/*/{instance_id=instances/*}/**"
275//       }
276//     };
277//
278// result (is the same as 6a for our example message because it has the instance
279// information):
280//
281//     x-goog-request-params:
282//     project_id=projects/proj_foo&instance_id=instances/instance_bar
283//
284// Example 7
285//
286// Extracting multiple routing header key-value pairs by matching
287// several path templates on multiple request fields.
288//
289// NB: note that here there is no way to specify sending nothing if one of the
290// fields does not match its template. E.g. if the `table_name` is in the wrong
291// format, the `project_id` will not be sent, but the `routing_id` will be.
292// The backend routing code has to be aware of that and be prepared to not
293// receive a full complement of keys if it expects multiple.
294//
295// annotation:
296//
297//     option (google.api.routing) = {
298//       // The routing needs both `project_id` and `routing_id`
299//       // (from the `app_profile_id` field) for routing.
300//
301//       routing_parameters {
302//         field: "table_name"
303//         path_template: "{project_id=projects/*}/**"
304//       }
305//       routing_parameters {
306//         field: "app_profile_id"
307//         path_template: "{routing_id=**}"
308//       }
309//     };
310//
311// result:
312//
313//     x-goog-request-params:
314//     project_id=projects/proj_foo&routing_id=profiles/prof_qux
315//
316// Example 8
317//
318// Extracting a single routing header key-value pair by matching
319// several conflictingly named path templates on several request fields. The
320// last template to match "wins" the conflict.
321//
322// annotation:
323//
324//     option (google.api.routing) = {
325//       // The `routing_id` can be a project id or a region id depending on
326//       // the table name format, but only if the `app_profile_id` is not set.
327//       // If `app_profile_id` is set it should be used instead.
328//
329//       routing_parameters {
330//         field: "table_name"
331//         path_template: "{routing_id=projects/*}/**"
332//       }
333//       routing_parameters {
334//          field: "table_name"
335//          path_template: "{routing_id=regions/*}/**"
336//       }
337//       routing_parameters {
338//         field: "app_profile_id"
339//         path_template: "{routing_id=**}"
340//       }
341//     };
342//
343// result:
344//
345//     x-goog-request-params: routing_id=profiles/prof_qux
346//
347// Example 9
348//
349// Bringing it all together.
350//
351// annotation:
352//
353//     option (google.api.routing) = {
354//       // For routing both `table_location` and a `routing_id` are needed.
355//       //
356//       // table_location can be either an instance id or a region+zone id.
357//       //
358//       // For `routing_id`, take the value of `app_profile_id`
359//       // - If it's in the format `profiles/<profile_id>`, send
360//       // just the `<profile_id>` part.
361//       // - If it's any other literal, send it as is.
362//       // If the `app_profile_id` is empty, and the `table_name` starts with
363//       // the project_id, send that instead.
364//
365//       routing_parameters {
366//         field: "table_name"
367//         path_template: "projects/*/{table_location=instances/*}/tables/*"
368//       }
369//       routing_parameters {
370//         field: "table_name"
371//         path_template: "{table_location=regions/*/zones/*}/tables/*"
372//       }
373//       routing_parameters {
374//         field: "table_name"
375//         path_template: "{routing_id=projects/*}/**"
376//       }
377//       routing_parameters {
378//         field: "app_profile_id"
379//         path_template: "{routing_id=**}"
380//       }
381//       routing_parameters {
382//         field: "app_profile_id"
383//         path_template: "profiles/{routing_id=*}"
384//       }
385//     };
386//
387// result:
388//
389//     x-goog-request-params:
390//     table_location=instances/instance_bar&routing_id=prof_qux
391message RoutingRule {
392  // A collection of Routing Parameter specifications.
393  // **NOTE:** If multiple Routing Parameters describe the same key
394  // (via the `path_template` field or via the `field` field when
395  // `path_template` is not provided), "last one wins" rule
396  // determines which Parameter gets used.
397  // See the examples for more details.
398  repeated RoutingParameter routing_parameters = 2;
399}
400
401// A projection from an input message to the GRPC or REST header.
402message RoutingParameter {
403  // A request field to extract the header key-value pair from.
404  string field = 1;
405
406  // A pattern matching the key-value field. Optional.
407  // If not specified, the whole field specified in the `field` field will be
408  // taken as value, and its name used as key. If specified, it MUST contain
409  // exactly one named segment (along with any number of unnamed segments) The
410  // pattern will be matched over the field specified in the `field` field, then
411  // if the match is successful:
412  // - the name of the single named segment will be used as a header name,
413  // - the match value of the segment will be used as a header value;
414  // if the match is NOT successful, nothing will be sent.
415  //
416  // Example:
417  //
418  //               -- This is a field in the request message
419  //              |   that the header value will be extracted from.
420  //              |
421  //              |                     -- This is the key name in the
422  //              |                    |   routing header.
423  //              V                    |
424  //     field: "table_name"           v
425  //     path_template: "projects/*/{table_location=instances/*}/tables/*"
426  //                                                ^            ^
427  //                                                |            |
428  //       In the {} brackets is the pattern that --             |
429  //       specifies what to extract from the                    |
430  //       field as a value to be sent.                          |
431  //                                                             |
432  //      The string in the field must match the whole pattern --
433  //      before brackets, inside brackets, after brackets.
434  //
435  // When looking at this specific example, we can see that:
436  // - A key-value pair with the key `table_location`
437  //   and the value matching `instances/*` should be added
438  //   to the x-goog-request-params routing header.
439  // - The value is extracted from the request message's `table_name` field
440  //   if it matches the full pattern specified:
441  //   `projects/*/instances/*/tables/*`.
442  //
443  // **NB:** If the `path_template` field is not provided, the key name is
444  // equal to the field name, and the whole field should be sent as a value.
445  // This makes the pattern for the field and the value functionally equivalent
446  // to `**`, and the configuration
447  //
448  //     {
449  //       field: "table_name"
450  //     }
451  //
452  // is a functionally equivalent shorthand to:
453  //
454  //     {
455  //       field: "table_name"
456  //       path_template: "{table_name=**}"
457  //     }
458  //
459  // See Example 1 for more details.
460  string path_template = 2;
461}
462