Configuring a gRPC API Service

gRPC API Configuration is a specification that lets you define the behavior of a gRPC API service, including authentication, documentation, logging and more. Its official schema is defined by the .proto message google.api.Service and works with both REST and gRPC APIs.

gRPC API Configuration is a rich and mature specification used for Google production services, such as Cloud Logging, Cloud Vision, Cloud Bigtable, IAM, and more.

gRPC API Configuration is typically written as .YAML files that accompany the API interface definition, which is defined in .proto files using protocol buffers.

For reference documentation on the available configuration options, see the gRPC API Configuration Reference.

Configuration overview

A gRPC API Configuration specifies how a set of APIs is exposed as an API service. The configuration includes:

  • the name of the service
  • one or more DNS addresses to which requests are sent
  • which APIs are served
  • how the callers are authenticated
  • how the APIs are accessed via HTTP REST

A gRPC API Configuration is always accompanied by .proto files defining the surface of the API service, including methods, parameters, and return types. You can find out more about how to define a gRPC API surface on the gRPC site.

gRPC API Configuration consists of multiple configuration aspects: documentation (for service documentation text), http (for transcoding rules), auth (for authentication rules), usage (for usage rules such as API key validation), and endpoints (for Google Endpoints-specific settings). Depending on the behavior you want for your service, you use the appropriate aspects in your gRPC API Configuration.

Each aspect schema is typically defined by its own .proto message: for example, HTTP configuration is defined in the http configuration proto message.

Basic configuration

Let's look at how gRPC API Configuration works with a simple example. Our sample Bookstore service has its API surface definition in bookstore.proto and its basic gRPC API Configuration in api_config.yaml:

syntax = "proto3";

package endpoints.examples.bookstore;

option java_multiple_files = true;
option java_outer_classname = "BookstoreProto";
option java_package = "com.google.endpoints.examples.bookstore";

import "google/protobuf/empty.proto";

service Bookstore {
  rpc ListShelves(google.protobuf.Empty) returns (ListShelvesResponse) {}
  rpc CreateShelf(CreateShelfRequest) returns (Shelf) {}
  rpc GetShelf(GetShelfRequest) returns (Shelf) {}
  rpc DeleteShelf(DeleteShelfRequest) returns (google.protobuf.Empty) {}
  rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) {}
  rpc CreateBook(CreateBookRequest) returns (Book) {}
  rpc GetBook(GetBookRequest) returns (Book) {}
  rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {}
}

message Shelf {
  int64 id = 1;
  string theme = 2;
}

message Book {
  int64 id = 1;
  string author = 2;
  string title = 3;
}

...
type: google.api.Service
config_version: 3

name: bookstore.endpoints.<MY_PROJECT_ID>.cloud.goog

title: Bookstore gRPC API
apis:
- name: endpoints.examples.bookstore.Bookstore

This is the simplest possible configuration: it defines an API service named bookstore.endpoints.<MY_PROJECT_ID>.cloud.goog, and specifies that the service exposes the API endpoints.examples.bookstore.Bookstore, as defined in our .proto. It also provides a descriptive title that will appear for our Bookstore service in the Google Cloud Platform Console. See the complete Github versions of each file for more detailed comments.

To find out how to deploy and use the Bookstore, see our gRPC tutorials.

Rules and selectors

In some cases, you may need the ability to associate configuration with individual elements of a service - for example, to enforce authentication on certain methods but not others. To permit that, some of the sections use configuration rules to indicate which elements configuration applies to. A configuration rule uses a selector pattern to identify the elements that the configuration applies to. A selector is a comma-separated list of qualified names of service, method, message, field, enum or enum values. The last segment of the name can be *, which matches any suffix, indicating a wildcard. Wildcards are only allowed at the end and for a whole segment of the qualified name, i.e. foo.* is ok, but not foo.b* or foo.*.bar. To specify a default for all applicable elements, the whole pattern * is used.

Example 1 (affecting entire service):

usage:
  rules:
  # Allow unregistered calls for all methods.
  - selector: "*"
    allow_unregistered_calls: true

Example 2 (affecting a single method):

usage:
  rules: # IMPORTANT: ONLY LAST MATCHING RULE IS APPLIED
  # Disable API key validation on just the ListShelves method
  # while requiring an API key for the rest of the API.
  - selector: "*"
    allow_unregistered_calls: false
  - selector: "endpoints.examples.bookstore.BookStore.ListShelves"
    allow_unregistered_calls: true

The above example shows how to disable API key validation on just the ListShelves method while requiring an API key for the rest of the API.

Rules are evaluated sequentially, the last matching one in declaration order is taken.

Using multiple YAML files

It's sometimes useful to use different YAML files to configure different features for the same service, allowing ease of reuse and modification for different environments. For instance, in our Bookstore example above, we specified its basic configuration in api_config.yaml and its HTTP rules in api_config_http.yaml. This lets us deploy the HTTP rules only if we want to turn on JSON/HTTP to gRPC transcoding for the Bookstore.

If you use multiple YAML files to author a gRPC API Configuration, when the configuration is deployed each file is converted to google.api.Service proto messages, then all messages are merged using proto merging semantics. That is, all singular scalar fields in the latter instance replace those in the former (so if you provide different singular values for the same rule in two files, the value in the second file you specify when deploying the configuration is used), singular embedded messages are merged, and repeated fields are concatenated.

Note that like rules in general, merging is order sensitive, since one config overrides settings in another.

Annotations (HTTP rules only)

As an alternative to using a YAML file for configuring HTTP options, you can configure them directly in your .proto file, using the options mechanism.

API annotations are defined in annotations.proto.

Use annotations if the configuration option is intended to be invariant over all usages of the protocol buffer API definition. For example, if an API has one single implementation, or all implementations are required to have the same HTTP interface, the HTTP configuration could be annotated in the .proto.

If a configuration option is provided both in the .proto file and a YAML configuration file, the YAML configuration overrides the annotation.

Example annotation in a .proto file:

rpc ListShelves(google.protobuf.Empty) returns (ListShelvesResponse) {
    option (google.api.http) = { get: "/v1/shelves" };
}

# The above .proto annotation is equivalent to the following .YAML
# gRPC API configuration:

http:
  rules:
  - selector: endpoints.examples.bookstore.BookStore.ListShelves
    get: '/v1/shelves'

Configuration validation

When you combine your gRPC API Configuration and .proto file(s) to create your service’s runtime configuration, the configuration is validated. This process flags any errors and warnings that arise from your configuration.

Warnings are divided into regular and linter warnings. Linter warnings use an identifier of the form <group>-<rule>, where <group> indicates the configuration group, and <rule> the particular linter rule. For example, below the group is versioning and the rule is http-version-prefix:

WARNING: bookstore.proto:51:3: (lint) versioning-http-version-prefix: method
'endpoints.examples.bookstore.BookStore.ListShelves' has a different version prefix in HTTP path ('v2')
than api version 'v1'.

You can suppress linter warnings by adding a directive to the documentation of an API element. This can either be done in documentation in the proto or in documentation provided in the YAML file. For example, the following suppresses the above warning:

service Bookstore {
  // Returns an object.
  // (== suppress_warning versioning-http-version-prefix ==)
  rpc ListShelves(google.protobuf.Empty) returns (ListShelvesResponse) {
      option (google.api.http) = { get: "/v1/shelves" };
  }
}

To suppress warnings for an entire group, you can use a wildcard (*) instead of rule names. For example, versioning-* suppresses all warnings related to the versioning group.

Suppression directives attached to parent elements also apply to all children. For example, the following example suppresses all 'versioning' group warnings on all methods within the service:

// (== suppress_warning versioning-* ==)
service Bookstore {
  // Returns an object.
  rpc ListShelves(google.protobuf.Empty) returns (ListShelvesResponse) {
      option (google.api.http) = { get: "/v1/shelves" };
  }
}

To globally suppress a warning, attach it to the overview documentation of the gRPC API configuration:

type: google.api.Service
name: your_api.endpoints.<producer-project-id>.cloud.goog
title: Bookstore gRPC API
apis:
- name: endpoints.examples.bookstore.BookStore
documentation:
    overview: |
      A simple Bookstore gRPC API.
      (== suppress_warning documentation-presence ==)

Note that directives in documentation like suppress_warning must appear on their own line, otherwise they will not be recognized. YAML block literal markers like > remove all newlines, so if you used overview: > in the above example, the suppression would not work. For more information on block literals in YAML, see Block literals.

Monitor your resources on the go

Get the Google Cloud Console app to help you manage your projects.

Send feedback about...

Cloud Endpoints with gRPC