Any call we make against a Google API is charged against a project quota. Depending on the API that we’re using, that project quota might limit the frequency of calls, the total number of calls, or even the number of calls per user.
But which project’s quota is it that’s being charged? To find out, we need to distinguish between two classes of APIs:
Although there’s no definite way to find out whether an API is resource-oriented or not, we can get a pretty good clue by looking at the API’s URLs: If the URLs contain a project ID or project number, then odds are that we’re dealing with a resource-oriented API; otherwise, it’s probably a non-resource-oriented API.
Non-resource-oriented APIs are APIs that don’t have any clear association with a Google project.
Most non-Cloud APIs like Maps fall into this bucket. But there are also a few Cloud APIs like the OS Login API or Resource Manager API that don’t have a clear association with a resource project and are therefore considered non-resource-oriented APIs.
Note that this distinction applies to an entire API, not to individual resources/methods.
Resource project, client project, or user project
Whether an API is resource-oriented or not determines how it charges quotas:
The default behavior of resource-oriented APIs is that they charge quota against the resource project. That’s the project that contains the resource which the API call operates on.
To allow that to happen, we have to enable the respective API in the resource project.
For non-resource-oriented APIs, charging a resource project isn’t an option. For those APIs, the default is therefore to charge the client project. That’s the project that contains:
- the OAuth client ID (if we’re authenticating as a user),
- the service account (if we’re authenticating a service account), or
- the API key (if we’re not using an OAuth).
For that to work, we have to enable the respective API in the client project.
We can override these defaults and instruct the API to charge a user project instead. To do that, we have to add a
header to our HTTP request that contains:
a caller-specified project for quota and billing purposes. The caller must have
serviceusage.services.usepermission on the project.
Charging gcloud usage
gcloud, the default quota-charging behavior means that:
gcloud compute instances list –project my-projectis charged against
my-project, because the Compute Engine API is a resource-oriented API.
gcloud projects listis charged against some Google-owned project that contains
gcloud’s OAuth Client ID because the Resource Manager API is a non-resource oriented API.
gcloud also provides a
parameter, which lets us specify a:
… Google Cloud project that will be charged quota for operations performed in gcloud. If you need to operate on one project, but need quota against a different project, you can use this flag to specify the billing project.
That sounds a lot like the definition of the
X-Goog-User-Project header. And indeed, that’s exactly what
gcloud uses under the hood:
> gcloud projects list --billing-project my-billing-project --log-http … ==== request start ==== uri: https://cloudresourcemanager.googleapis.com/v1/projects?alt=json&filter=lifecycleState%3AACTIVE&pageSize=500 method: GET == headers start == b'X-Goog-User-Project': b'my-billing-project' <--- !! b'accept': b'application/json' b'accept-encoding': b'gzip, deflate' b'authorization': --- Token Redacted --- b'content-length': b'0' b'user-agent': b'google-cloud-sdk gcloud/…' == headers end == …