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"
};
}
}