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