API Configuration

This code generator relies on some configuration not specified in many published protocol buffers.

Warning

In fact, this is intended to serve as a reference implementation for proposed configuration, so as of this writing it is not published anywhere, and is subject to change.

This plugin will successfully publish a library on a valid protobuf API even without any additional information set, but may require some post-processing work by a human in this case before the resulting client library will work.

Look for values enclosed by <<< and >>> to quickly spot these. As of this writing, these are the SERVICE_ADDRESS and OAUTH_SCOPES constants defined in base.py files.

Reading further assumes you are at least nominally familiar with protocol buffers and their syntax. You may not be familiar with options yet; it is recommended to read up on them before continuing. (As a note, no need to learn about creating custom options; being able to set options that are already defined is sufficient.)

Annotations and Imports

As mentioned above, this tool uses a interface specification that is currently experimental.

When specifying an annotation, your proto will need to import the file where the annotation is defined. If you try to use an annotation without importing the dependency proto, then protoc will give you an error.

These protos live on the input-contract branch in the api-common-protos repository.

Your best bet is to likely clone this repository:

$ git clone git@github.com:googleapis/api-common-protos.git
$ cd api-common-protos
$ git checkout --track -b input-contract origin/input-contract

Once this is done, you will need to specify the root of this repository on disk as a --proto_path whenever invoking protoc.

API Client Information

The most important piece of information this plugin requires is information about the client library itself: what should it be called, what is its proper namespace, and so on.

This is rolled up into a structure called Metadata, and the annotation is defined in google/api/metadata.proto.

The option may be defined as a full structure at the top level of the proto file. It is recommended that this be declared other under option directives, and above services or messages.

This annotation is optional, and you may not need it. The generator will infer a proper name, namespace and version from the package statement:

// This will come out to be:
//   package namespace: ['Acme', 'Manufacturing']
//   package name: 'Anvils'
//   version: 'v1'
package acme.manufacturing.anvils.v1;

If the inferred package name is wrong for some reason, then the annotation is important.

package acme.anvils.v1;

// The namespace provided here will take precedence over the
// inferred one.
option (google.api.metadata) = {
  "package_namespace": ["Acme", "Manufacturing"]
};

Note

The google.api.metadata annotation can be used to specify a namespace or name, but the version must be specified in the proto package.

Service Information

In order to properly connect to an API, the client library needs to know where the API service is running, as well as what (if anything) else is required in order to properly connect.

This plugin understands two options for this, which are also defined in google/api/metadata.proto. Rather than being options on top level files, however, these are both options on services. If an API defines more than one service, these options do not need to match between them.

The first option is the host where the service can be reached:

service AnvilService {
  option (google.api.default_host) = "anvils.acme.com"
}

The second option is any oauth scopes which are needed. Google’s auth libraries (such as google-auth in Python, which code generated by this plugin uses) expect that credentials declare what scopes they believe they need, and the auth libraries do the right thing in the situation where authorization is needed, access has been revoked, and so on.

service AnvilService {
  option (google.api.oauth) = {
    scopes: ["https://anvils.acme.com/auth/browse-anvils",
             "https://anvils.acme.com/auth/drop-anvils"]
  };
}

Long-Running Operations

Occasionally, API requests may take a long time. In this case, APIs may run a task in the background and provide the client with a token to retrieve the result later.

The google.longrunning.Operation message is intended for this purpose. It is defined in google/longrunning/operations.proto and can be used as the return type of an RPC.

However, when doing this, the ultimate return type is lost. Therefore, it is important to annotate the return type (and metadata type, if applicable) so that client libraries are able to deserialize the message.

import "google/api/annotations.proto";

package acme.anvils.v1;

service AnvilService {
  rpc DeliverAnvil(DeliverAnvilRequest)
      returns (google.longrunning.Operation) {
    option (google.api.operation) = {
      response_type: "acme.anvils.v1.DeliverAnvilResponse"
      metadata_type: "acme.anvils.v1.DeliverAnvilMetadata"
    };
  }
}