Merge pull request #243 from sqrrrl/master
0.9 - core library rewrite (pull request 1 of 2)
This commit is contained in:
commit
986a47c30b
|
@ -0,0 +1,7 @@
|
|||
inherit_from: .rubocop_todo.yml
|
||||
|
||||
Metrics/LineLength:
|
||||
Max: 120
|
||||
|
||||
Style/FormatString:
|
||||
EnforcedStyle: sprintf
|
|
@ -0,0 +1,63 @@
|
|||
# This configuration was generated by `rubocop --auto-gen-config`
|
||||
# on 2015-03-25 23:30:36 -0700 using RuboCop version 0.29.1.
|
||||
# The point is for the user to remove these configuration records
|
||||
# one by one as the offenses are removed from the code base.
|
||||
# Note that changes in the inspected code, or installation of new
|
||||
# versions of RuboCop, may require this file to be generated again.
|
||||
|
||||
# Offense count: 19
|
||||
Metrics/AbcSize:
|
||||
Max: 79
|
||||
|
||||
# Offense count: 2
|
||||
# Configuration parameters: CountComments.
|
||||
Metrics/ClassLength:
|
||||
Max: 220
|
||||
|
||||
# Offense count: 5
|
||||
Metrics/CyclomaticComplexity:
|
||||
Max: 10
|
||||
|
||||
# Offense count: 99
|
||||
# Configuration parameters: AllowURI, URISchemes.
|
||||
Metrics/LineLength:
|
||||
Max: 127
|
||||
|
||||
# Offense count: 18
|
||||
# Configuration parameters: CountComments.
|
||||
Metrics/MethodLength:
|
||||
Max: 43
|
||||
|
||||
# Offense count: 1
|
||||
# Configuration parameters: CountKeywordArgs.
|
||||
Metrics/ParameterLists:
|
||||
Max: 6
|
||||
|
||||
# Offense count: 4
|
||||
Metrics/PerceivedComplexity:
|
||||
Max: 11
|
||||
|
||||
# Offense count: 14
|
||||
Style/Documentation:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
Style/EmptyLines:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 3
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
Style/EmptyLinesAroundClassBody:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 2
|
||||
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
|
||||
Style/Next:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 3
|
||||
# Cop supports --auto-correct.
|
||||
Style/RedundantSelf:
|
||||
Enabled: false
|
|
@ -3,15 +3,13 @@ rvm:
|
|||
- 2.2
|
||||
- 2.0.0
|
||||
- 2.1
|
||||
- 1.9.3
|
||||
- rbx-2
|
||||
- jruby
|
||||
- jruby-9000
|
||||
env:
|
||||
- RAILS_VERSION="~>3.2"
|
||||
- RAILS_VERSION="~>4.0.0"
|
||||
- RAILS_VERSION="~>4.1.0"
|
||||
- RAILS_VERSION="~>4.2.0"
|
||||
script: "bundle exec rake spec:all"
|
||||
script: "rake spec:all"
|
||||
before_install:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install idn
|
||||
|
|
11
.yardopts
11
.yardopts
|
@ -1,7 +1,12 @@
|
|||
--markup markdown
|
||||
--hide-void-return
|
||||
--no-private
|
||||
--verbose
|
||||
--markup-provider=redcarpet
|
||||
--markup=markdown
|
||||
lib/**/*.rb
|
||||
ext/**/*.c
|
||||
generated/**/*.rb
|
||||
-
|
||||
README.md
|
||||
CHANGELOG.md
|
||||
MIGRATING.md
|
||||
CONTRIBUTING.md
|
||||
LICENSE
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
# 0.9.0
|
||||
* WARNING: Please see [MIGRATING](MIGRATING.md) for important information.
|
||||
* API classes are now generated ahead of time instead of at runtime.
|
||||
* Drop support for Ruby versions < 2.0
|
||||
* Switch from Faraday to Hurley for HTTP client
|
||||
|
||||
# 0.8.6
|
||||
* Use discovered 'rootUrl' as base URI for services
|
||||
* Respect discovered methods with colons in path
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Contributor License Agreements
|
||||
|
||||
We'd love to accept your sample apps and patches! Before we can take them, we
|
||||
We'd love to accept your sample apps and patches! Before we can take them, we
|
||||
have to jump a couple of legal hurdles.
|
||||
|
||||
Please fill out either the individual or corporate Contributor License Agreement
|
||||
|
@ -29,4 +29,3 @@ accept your pull requests.
|
|||
1. Ensure that your code is clear and comprehensible.
|
||||
1. Ensure that your code has an appropriate set of unit tests which all pass.
|
||||
1. Submit a pull request.
|
||||
|
||||
|
|
30
Gemfile
30
Gemfile
|
@ -1,9 +1,35 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
# Specify your gem's dependencies in google-apis.gemspec
|
||||
gemspec
|
||||
|
||||
gem 'jruby-openssl', :platforms => :jruby
|
||||
|
||||
group :development do
|
||||
gem 'bundler', '~> 1.7'
|
||||
gem 'rake', '~> 10.0'
|
||||
gem 'rspec', '~> 3.1'
|
||||
gem 'json_spec', '~> 1.1'
|
||||
gem 'webmock', '~> 1.21'
|
||||
gem 'simplecov', '~> 0.9'
|
||||
gem 'coveralls', '~> 0.7.11'
|
||||
gem 'rubocop', '~> 0.29'
|
||||
gem 'launchy', '~> 2.4'
|
||||
end
|
||||
|
||||
platforms :jruby do
|
||||
group :development do
|
||||
gem 'jruby-openssl'
|
||||
end
|
||||
end
|
||||
|
||||
platforms :ruby do
|
||||
group :development do
|
||||
gem 'yard', '~> 0.8'
|
||||
gem 'redcarpet', '~> 3.2'
|
||||
gem 'github-markup', '~> 1.3'
|
||||
end
|
||||
end
|
||||
|
||||
if ENV['RAILS_VERSION']
|
||||
gem 'rails', ENV['RAILS_VERSION']
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
# Migrating from version `0.8.x` to `0.9`
|
||||
|
||||
Many changes and improvements have been made to the `google-api-ruby-client`
|
||||
library to bring it to `0.9`. If you are starting a new project or haven't used
|
||||
this library before version `0.9`, see the [README][readme] to get started
|
||||
as you won't need to migrate anything.
|
||||
|
||||
Code written against the `0.8.x` version of this library will not work with the `0.9`
|
||||
version without modification.
|
||||
|
||||
## Discovery
|
||||
|
||||
In `0.8.x` the library would "discover" APIs on the fly, introducing
|
||||
additional network calls and instability. That has been fixed in `0.9`.
|
||||
|
||||
To get the `drive` client in `0.8.x` required this:
|
||||
|
||||
```ruby
|
||||
require 'google/api_client'
|
||||
|
||||
client = Google::APIClient.new
|
||||
drive = client.discovered_api('drive', 'v2')
|
||||
```
|
||||
|
||||
In `0.9` the same thing can be accomplished like this:
|
||||
|
||||
```ruby
|
||||
require 'google/apis/drive_v2'
|
||||
|
||||
drive = Google::Apis::DriveV2::DriveService.new
|
||||
```
|
||||
|
||||
All APIs are immediately accessible without requiring additional network calls or runtime code generation.
|
||||
|
||||
## API Methods
|
||||
|
||||
The calling style for API methods has changed. In `0.8.x` all calls were via a generic `execute` method. In `0.9`
|
||||
the generated services have fully defined method signatures for all available methods.
|
||||
|
||||
To get a file using the Google Drive API in `0.8.x` required this:
|
||||
|
||||
```ruby
|
||||
file = client.execute(:api_method => drive.file.get, :parameters => { 'id' => 'abc123' })
|
||||
```
|
||||
|
||||
In `0.9` the same thing can be accomplished like this:
|
||||
|
||||
```ruby
|
||||
file = drive.get_file('abc123')
|
||||
```
|
||||
|
||||
Full API definitions including available methods, parameters, and data classes can be found in the `generated` directory.
|
||||
|
||||
## Authorization
|
||||
|
||||
In the 0.9 version of this library, the authentication and authorization code was moved
|
||||
to the new [googleauth](https://github.com/google/google-auth-library-ruby) library. While the new library provides
|
||||
significantly simpler APIs for some use cases, not all features have been migrated. Missing features
|
||||
are expected to be added by end of Q2 2015.
|
||||
|
||||
The underlying [Signet](https://github.com/google/signet) is still used for authorization. OAuth 2 credentials obtained
|
||||
previously will continue to work with the `0.9` version. OAuth 1 is no longer supported.
|
||||
|
||||
## Media uploads
|
||||
|
||||
Media uploads are significantly simpler in `0.9`.
|
||||
|
||||
The old `0.8.x` way of uploading media:
|
||||
|
||||
```ruby
|
||||
media = Google::APIClient::UploadIO.new('mymovie.m4v', 'video/mp4')
|
||||
metadata = {
|
||||
'title' => 'My movie',
|
||||
'description' => 'The best home movie ever made'
|
||||
}
|
||||
client.execute(:api_method => drive.files.insert,
|
||||
:parameters => { 'uploadType' => 'multipart' },
|
||||
:body_object => metadata,
|
||||
:media => media )
|
||||
```
|
||||
|
||||
The new way in `0.9` using `upload_source` and `content_type` parameters:
|
||||
|
||||
```ruby
|
||||
metadata = {
|
||||
title: 'My movie',
|
||||
description: 'The best home movie ever made'
|
||||
}
|
||||
drive.insert_file(metadata, upload_source: 'mymovie.m4v', content_type: 'video/mp4')
|
||||
```
|
||||
|
||||
`upload_source` can be either a path to a file, an `IO` stream, or a `StringIO` instance.
|
||||
|
||||
Uploads are resumable and will be automatically retried if interrupted.
|
||||
|
||||
## Media downloads
|
||||
|
||||
`0.9` introduces support for media downloads (`alt=media`). To download content, use the `download_dest` parameter:
|
||||
|
||||
```ruby
|
||||
drive.get_file('abc123', download_dest: '/tmp/myfile.txt')
|
||||
```
|
||||
|
||||
`download_dest` may be either a path to a file or an `IO` stream.
|
||||
|
||||
## Batch Requests
|
||||
|
||||
The old `0.8.x` way of performing batch requests:
|
||||
|
||||
```ruby
|
||||
client = Google::APIClient.new
|
||||
urlshortener = client.discovered_api('urlshortener')
|
||||
|
||||
batch = Google::APIClient::BatchRequest.new do |result|
|
||||
puts result.data
|
||||
end
|
||||
|
||||
batch.add(:api_method => urlshortener.url.insert,
|
||||
:body_object => { 'longUrl' => 'http://example.com/foo' })
|
||||
batch.add(:api_method => urlshortener.url.insert,
|
||||
:body_object => { 'longUrl' => 'http://example.com/bar' })
|
||||
client.execute(batch)
|
||||
```
|
||||
|
||||
In `0.9`, the equivalent code is:
|
||||
|
||||
```ruby
|
||||
require 'google/apis/urlshortner_v1'
|
||||
|
||||
urlshortener = Google::Apis::UrlshortenerV1::UrlshortenerService.new
|
||||
|
||||
urlshortener.batch do |urlshortener|
|
||||
urlshortner.insert_url({long_url: 'http://example.com/foo'}) do |res, err|
|
||||
puts res
|
||||
end
|
||||
urlshortner.insert_url({long_url: 'http://example.com/bar'}) do |res, err|
|
||||
puts res
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Or if sharing the same block:
|
||||
|
||||
```ruby
|
||||
require 'google/apis/urlshortner_v1'
|
||||
|
||||
urlshortener = Google::Apis::UrlshortenerV1::UrlshortenerService.new
|
||||
|
||||
callback = lambda { |res, err| puts res }
|
||||
urlshortener.batch do |urlshortener|
|
||||
urlshortner.insert_url({long_url: 'http://example.com/foo'}, &callback)
|
||||
urlshortner.insert_url({long_url: 'http://example.com/bar'}, &callback)
|
||||
end
|
||||
```
|
||||
|
||||
## JRuby
|
||||
|
||||
Jruby 1.7.4 in 2.0 compatibility mode is supported. To enable for a specific script:
|
||||
|
||||
```
|
||||
jruby --2.0 myscript.rb
|
||||
```
|
||||
|
||||
Or set as the default:
|
||||
|
||||
```
|
||||
export JRUBY_OPTS=--2.0
|
||||
```
|
||||
|
||||
JRuby 9000 will be supported once released.
|
||||
|
368
README.md
368
README.md
|
@ -1,218 +1,226 @@
|
|||
# Google API Client
|
||||
|
||||
<dl>
|
||||
<dt>Homepage</dt><dd><a href="http://www.github.com/google/google-api-ruby-client">http://www.github.com/google/google-api-ruby-client</a></dd>
|
||||
<dt>Authors</dt><dd>Bob Aman, <a href="mailto:sbazyl@google.com">Steven Bazyl</a></dd>
|
||||
<dt>Copyright</dt><dd>Copyright © 2011 Google, Inc.</dd>
|
||||
<dt>License</dt><dd>Apache 2.0</dd>
|
||||
</dl>
|
||||
|
||||
[![Build Status](https://secure.travis-ci.org/google/google-api-ruby-client.png)](http://travis-ci.org/google/google-api-ruby-client)
|
||||
[![Dependency Status](https://gemnasium.com/google/google-api-ruby-client.png)](https://gemnasium.com/google/google-api-ruby-client)
|
||||
|
||||
## Description
|
||||
|
||||
The Google API Ruby Client makes it trivial to discover and access supported
|
||||
APIs.
|
||||
|
||||
## Alpha
|
||||
|
||||
This library is in Alpha. We will make an effort to support the library, but we reserve the right to make incompatible changes when necessary.
|
||||
This library is in Alpha. We will make an effort to support the library, but we reserve the right to make incompatible
|
||||
changes when necessary.
|
||||
|
||||
## Install
|
||||
## Migrating from 0.8.x
|
||||
|
||||
Be sure `https://rubygems.org/` is in your gem sources.
|
||||
Version 0.9 is not compatible with previous versions. See [MIGRATING](MIGRATING.md) for additional details on how to
|
||||
migrate to the latest version.
|
||||
|
||||
For normal client usage, this is sufficient:
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ gem install google-api-client
|
||||
```
|
||||
|
||||
## Example Usage
|
||||
Add this line to your application's Gemfile:
|
||||
|
||||
```ruby
|
||||
require 'google/api_client'
|
||||
require 'google/api_client/client_secrets'
|
||||
require 'google/api_client/auth/installed_app'
|
||||
|
||||
# Initialize the client.
|
||||
client = Google::APIClient.new(
|
||||
:application_name => 'Example Ruby application',
|
||||
:application_version => '1.0.0'
|
||||
)
|
||||
|
||||
# Initialize Google+ API. Note this will make a request to the
|
||||
# discovery service every time, so be sure to use serialization
|
||||
# in your production code. Check the samples for more details.
|
||||
plus = client.discovered_api('plus')
|
||||
|
||||
# Load client secrets from your client_secrets.json.
|
||||
client_secrets = Google::APIClient::ClientSecrets.load
|
||||
|
||||
# Run installed application flow. Check the samples for a more
|
||||
# complete example that saves the credentials between runs.
|
||||
flow = Google::APIClient::InstalledAppFlow.new(
|
||||
:client_id => client_secrets.client_id,
|
||||
:client_secret => client_secrets.client_secret,
|
||||
:scope => ['https://www.googleapis.com/auth/plus.me']
|
||||
)
|
||||
client.authorization = flow.authorize
|
||||
|
||||
# Make an API call.
|
||||
result = client.execute(
|
||||
:api_method => plus.activities.list,
|
||||
:parameters => {'collection' => 'public', 'userId' => 'me'}
|
||||
)
|
||||
|
||||
puts result.data
|
||||
gem 'google-api-client'
|
||||
```
|
||||
|
||||
## API Features
|
||||
And then execute:
|
||||
|
||||
### API Discovery
|
||||
$ bundle
|
||||
|
||||
To take full advantage of the client, load API definitions prior to use. To load an API:
|
||||
Or install it yourself as:
|
||||
|
||||
$ gem install google-api-client
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic usage
|
||||
|
||||
To use an API, include the corresponding generated file and instantiate the service. For example to use the Drive API:
|
||||
|
||||
```ruby
|
||||
urlshortener = client.discovered_api('urlshortener')
|
||||
```
|
||||
require 'google/apis/drive_v2'
|
||||
|
||||
Specific versions of the API can be loaded as well:
|
||||
Drive = Google::Apis::DriveV2 # Alias the module
|
||||
drive = Drive::DriveService.new
|
||||
drive.authorization = authorization # See Googleauth or Signet libraries
|
||||
|
||||
```ruby
|
||||
drive = client.discovered_api('drive', 'v2')
|
||||
```
|
||||
|
||||
Locally cached discovery documents may be used as well. To load an API from a local file:
|
||||
|
||||
```ruby
|
||||
# Output discovery document to JSON
|
||||
File.open('my-api.json', 'w') do |f| f.puts MultiJson.dump(client.discovery_document('myapi', 'v1')) end
|
||||
|
||||
# Read discovery document and load API
|
||||
doc = File.read('my-api.json')
|
||||
client.register_discovery_document('myapi', 'v1', doc)
|
||||
my_api = client.discovered_api('myapi', 'v1')
|
||||
```
|
||||
|
||||
### Authorization
|
||||
|
||||
Most interactions with Google APIs require users to authorize applications via OAuth 2.0. The client library uses [Signet](https://github.com/google/signet) to handle most aspects of authorization. For additional details about Google's OAuth support, see [Google Developers](https://developers.google.com/accounts/docs/OAuth2).
|
||||
|
||||
Credentials can be managed at the connection level, as shown, or supplied on a per-request basis when calling `execute`.
|
||||
|
||||
For server-to-server interactions, like those between a web application and Google Cloud Storage, Prediction, or BigQuery APIs, use service accounts.
|
||||
|
||||
As of version 0.8.3, service accounts can be configured using
|
||||
[Application Default Credentials][1], which rely on the credentials being
|
||||
available in a well-known location. If the credentials are not present
|
||||
and it's being used on a Compute Engine VM, it will use the VM's default credentials.
|
||||
|
||||
```ruby
|
||||
client.authorization = :google_app_default # in a later version, this will become the default
|
||||
client.authorization.fetch_access_token!
|
||||
client.execute(...)
|
||||
```
|
||||
|
||||
This is simpler API to use than in previous versions, although that is still available:
|
||||
|
||||
```ruby
|
||||
key = Google::APIClient::KeyUtils.load_from_pkcs12('client.p12', 'notasecret')
|
||||
client.authorization = Signet::OAuth2::Client.new(
|
||||
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
|
||||
:audience => 'https://accounts.google.com/o/oauth2/token',
|
||||
:scope => 'https://www.googleapis.com/auth/prediction',
|
||||
:issuer => '123456-abcdef@developer.gserviceaccount.com',
|
||||
:signing_key => key)
|
||||
client.authorization.fetch_access_token!
|
||||
client.execute(...)
|
||||
```
|
||||
|
||||
Service accounts are also used for delegation in Google Apps domains. The target user for impersonation is specified by setting the `:person` parameter to the user's email address
|
||||
in the credentials. Detailed instructions on how to enable delegation for your domain can be found at [developers.google.com](https://developers.google.com/drive/delegation).
|
||||
|
||||
### Automatic Retries & Backoff
|
||||
|
||||
The API client can automatically retry requests for recoverable errors. To enable retries, set the `client.retries` property to
|
||||
the number of additional attempts. To avoid flooding servers, retries invovle a 1 second delay that increases on each subsequent retry.
|
||||
In the case of authentication token expiry, the API client will attempt to refresh the token and retry the failed operation - this
|
||||
is a specific exception to the retry rules.
|
||||
|
||||
The default value for retries is 0, but will be enabled by default in future releases.
|
||||
|
||||
### Batching Requests
|
||||
|
||||
Some Google APIs support batching requests into a single HTTP request. Use `Google::APIClient::BatchRequest`
|
||||
to bundle multiple requests together.
|
||||
|
||||
Example:
|
||||
|
||||
```ruby
|
||||
client = Google::APIClient.new
|
||||
urlshortener = client.discovered_api('urlshortener')
|
||||
|
||||
batch = Google::APIClient::BatchRequest.new do |result|
|
||||
puts result.data
|
||||
# Search for files in Drive (first page only)
|
||||
files = drive.list_files(q: "title contains 'finances'")
|
||||
files.items.each do |file|
|
||||
puts file.title
|
||||
end
|
||||
|
||||
batch.add(:api_method => urlshortener.url.insert,
|
||||
:body_object => { 'longUrl' => 'http://example.com/foo' })
|
||||
batch.add(:api_method => urlshortener.url.insert,
|
||||
:body_object => { 'longUrl' => 'http://example.com/bar' })
|
||||
client.execute(batch)
|
||||
# Upload a file
|
||||
metadata = Drive::File.new(title: 'My document')
|
||||
metadata = drive.insert_file(metadata, upload_source: 'test.txt', content_type: 'text/plain')
|
||||
|
||||
# Download a file
|
||||
drive.get_file(metadata.id, download_dest: '/tmp/myfile.txt')
|
||||
```
|
||||
|
||||
Blocks for handling responses can be specified either at the batch level or when adding an individual API call. For example:
|
||||
### Media
|
||||
|
||||
Methods that allow media operations have additional parameters to specify the upload source or download destination.
|
||||
|
||||
For uploads, the `upload_source` parameter can be specified with either a path to a file, an `IO` stream, or `StringIO`
|
||||
instance.
|
||||
|
||||
For downloads, the `download_dest` parameter can also be either a path to a file, an `IO` stream, or `StringIO` instance.
|
||||
|
||||
Both uploads & downloads are resumable. If an error occurs during transmission the request will be automatically
|
||||
retried from the last received byte.
|
||||
|
||||
### Errors & Retries
|
||||
|
||||
Retries are disabled by default, but enabling retries is strongly encouraged. The number of retries can be configured
|
||||
via `Google::Apis::RequestOptions`. Any number greater than 0 will enable retries.
|
||||
|
||||
To enable retries for all services:
|
||||
|
||||
```ruby
|
||||
batch.add(:api_method=>urlshortener.url.insert, :body_object => { 'longUrl' => 'http://example.com/bar' }) do |result|
|
||||
puts result.data
|
||||
Google::Apis::RequestOptions.default.retries = 5
|
||||
```
|
||||
|
||||
With retries enabled globally, retries can be disabled for specific calls by including a retry value of 0 in the
|
||||
request options:
|
||||
|
||||
```ruby
|
||||
drive.insert_file(metadata, upload_source: 'test.txt', content_type: 'text/plain', options: { retries: 0 })
|
||||
```
|
||||
|
||||
When retries are enabled, if a server or rate limit error occurs during a request it is automatically retried with
|
||||
an exponentially increasing delay on subsequent retries. If a request can not be retried or if the maximum number
|
||||
of retries is exceeded, an exception is thrown.
|
||||
|
||||
### Callbacks
|
||||
|
||||
A block an be specified when making calls. If present, the block will be called with the result or error, rather than
|
||||
returning the result from the call or raising the error. Example:
|
||||
|
||||
```ruby
|
||||
# Search for files in Drive (first page only)
|
||||
drive.list_files(q: "title contains 'finances'") do |res, err|
|
||||
if err
|
||||
# Handle error
|
||||
else
|
||||
# Handle response
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### Media Upload
|
||||
This calling style is required when making batch requests as responses are not available until the entire batch
|
||||
is complete.
|
||||
|
||||
### Batches
|
||||
|
||||
Multiple requests can be batched together into a single HTTP request to reduce overhead. Batched calls are executed
|
||||
in parallel and the responses processed once all results are available
|
||||
|
||||
For APIs that support file uploads, use `Google::APIClient::UploadIO` to load the stream. Both multipart and resumable
|
||||
uploads can be used. For example, to upload a file to Google Drive using multipart
|
||||
|
||||
```ruby
|
||||
drive = client.discovered_api('drive', 'v2')
|
||||
|
||||
media = Google::APIClient::UploadIO.new('mymovie.m4v', 'video/mp4')
|
||||
metadata = {
|
||||
'title' => 'My movie',
|
||||
'description' => 'The best home movie ever made'
|
||||
}
|
||||
client.execute(:api_method => drive.files.insert,
|
||||
:parameters => { 'uploadType' => 'multipart' },
|
||||
:body_object => metadata,
|
||||
:media => media )
|
||||
```
|
||||
|
||||
To use resumable uploads, change the `uploadType` parameter to `resumable`. To check the status of the upload
|
||||
and continue if necessary, check `result.resumable_upload`.
|
||||
|
||||
```ruby
|
||||
client.execute(:api_method => drive.files.insert,
|
||||
:parameters => { 'uploadType' => 'resumable' },
|
||||
:body_object => metadata,
|
||||
:media => media )
|
||||
upload = result.resumable_upload
|
||||
|
||||
# Resume if needed
|
||||
if upload.resumable?
|
||||
client.execute(upload)
|
||||
# Fetch a bunch of files by ID
|
||||
ids = ['file_id_1', 'file_id_2', 'file_id_3', 'file_id_4']
|
||||
drive.batch do |drive|
|
||||
ids.each do |id|
|
||||
drive.get_file(id) do |res, err|
|
||||
# Handle response
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Samples
|
||||
Media operations -- uploads & downloads -- can not be included in batch with other requests.
|
||||
|
||||
See the full list of [samples on Github](https://github.com/google/google-api-ruby-client-samples).
|
||||
However, some APIs support batch uploads. To upload multiple files in a batch, use the `batch_upload` method instead.
|
||||
Batch uploads should only be used when uploading multiple small files. For large files, upload files individually to
|
||||
take advantage of the libraries built-in reusmable upload support.
|
||||
|
||||
### Hashes
|
||||
|
||||
While the API will always return instances of schema classes, plain hashes are accepted in method calls for
|
||||
convenience. Hash keys must be symbols matching the attribute names on the corresponding object the hash is meant
|
||||
to replace. For example:
|
||||
|
||||
```ruby
|
||||
file = {id: '123', title: 'My document', labels: { starred: true }}
|
||||
file = drive.insert_file(file) # Returns a Drive::File instance
|
||||
```
|
||||
|
||||
is equivalent to:
|
||||
|
||||
```ruby
|
||||
file = Drive::File.new(id: '123', title: 'My document')
|
||||
file.labels = Drive::File::Labels.new(starred: true)
|
||||
file = drive.update_file(file) # Returns a Drive::File instance
|
||||
```
|
||||
|
||||
## Authorization
|
||||
|
||||
[OAuth 2](https://developers.google.com/accounts/docs/OAuth2) is used to authorize applications. This library uses
|
||||
both [Signet](https://github.com/google/signet) and
|
||||
[Google Auth Library for Ruby](https://github.com/google/google-auth-library-ruby) for OAuth 2 support.
|
||||
|
||||
The [Google Auth Library for Ruby](https://github.com/google/google-auth-library-ruby) provides an implementation of
|
||||
[application default credentials] for Ruby. It offers a simple way to get authorization credentials for use in
|
||||
calling Google APIs, best suited for cases when the call needs to have the same identity
|
||||
and authorization level for the application independent of the user. This is
|
||||
the recommended approach to authorize calls to Cloud APIs, particularly when
|
||||
you're building an application that uses Google Compute Engine.
|
||||
|
||||
For per-user authorization, use [Signet](https://github.com/google/signet) to obtain user authorization.
|
||||
|
||||
### Passing authorization to requests
|
||||
|
||||
Authorization can be specified for the entire client, for an individual service instance, or on a per-request basis.
|
||||
|
||||
Set authorization for all service:
|
||||
|
||||
```ruby
|
||||
Google::Apis::RequestOptions.default.authorization = authorization
|
||||
# Services instantiated after this will inherit the authorization
|
||||
```
|
||||
|
||||
On a per-service level:
|
||||
|
||||
```ruby
|
||||
drive = Google::Apis::DriveV2::DriveService.new
|
||||
drive.authorization = authorization
|
||||
|
||||
# All requests made with this service will use the same authorization
|
||||
```
|
||||
|
||||
Per-request:
|
||||
|
||||
```ruby
|
||||
drive.get_file('123', options: { authorization: authorization })
|
||||
```
|
||||
|
||||
## Generating APIs
|
||||
|
||||
For [Cloud Endpoints](https://cloud.google.com/endpoints/) or other APIs not included in the gem, ruby code can be
|
||||
generated from the discovery document.
|
||||
|
||||
To generate from a local discovery file:
|
||||
|
||||
$ generate-api gen <outdir> --file=<path>
|
||||
|
||||
A URL can also be specified:
|
||||
|
||||
$ generate-api gen <outdir> --url=<url>
|
||||
|
||||
## TODO
|
||||
|
||||
* ETag support (if-not-modified)
|
||||
* Auto-paging results (maybe)
|
||||
* Caching
|
||||
* Model validations
|
||||
|
||||
## License
|
||||
|
||||
This library is licensed under Apache 2.0. Full license text is
|
||||
available in [LICENSE.txt](LICENSE.txt).
|
||||
|
||||
## Contributing
|
||||
|
||||
See [CONTRIBUTING](contributing).
|
||||
|
||||
## Support
|
||||
|
||||
Please [report bugs at the project on Github](https://github.com/google/google-api-ruby-client/issues). Don't hesitate to [ask questions](http://stackoverflow.com/questions/tagged/google-api-ruby-client) about the client or APIs on [StackOverflow](http://stackoverflow.com).
|
||||
|
||||
[1]: https://developers.google.com/accounts/docs/application-default-credentials
|
||||
Please [report bugs at the project on Github](https://github.com/google/google-api-ruby-client/issues). Don't
|
||||
hesitate to [ask questions](http://stackoverflow.com/questions/tagged/google-api-ruby-client) about the client or APIs
|
||||
on [StackOverflow](http://stackoverflow.com).
|
||||
|
|
41
Rakefile
41
Rakefile
|
@ -1,41 +1,2 @@
|
|||
# -*- ruby -*-
|
||||
lib_dir = File.expand_path('../lib', __FILE__)
|
||||
$LOAD_PATH.unshift(lib_dir)
|
||||
$LOAD_PATH.uniq!
|
||||
require "bundler/gem_tasks"
|
||||
|
||||
require 'bundler/gem_tasks'
|
||||
require 'rubygems'
|
||||
require 'rake'
|
||||
|
||||
require File.join(File.dirname(__FILE__), 'lib/google/api_client', 'version')
|
||||
|
||||
PKG_DISPLAY_NAME = 'Google API Client'
|
||||
PKG_NAME = PKG_DISPLAY_NAME.downcase.gsub(/\s/, '-')
|
||||
PKG_VERSION = Google::APIClient::VERSION::STRING
|
||||
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
||||
PKG_HOMEPAGE = 'https://github.com/google/google-api-ruby-client'
|
||||
|
||||
RELEASE_NAME = "REL #{PKG_VERSION}"
|
||||
|
||||
PKG_AUTHOR = ["Bob Aman", "Steve Bazyl"]
|
||||
PKG_AUTHOR_EMAIL = "sbazyl@google.com"
|
||||
PKG_SUMMARY = 'Package Summary'
|
||||
PKG_DESCRIPTION = <<-TEXT
|
||||
The Google API Ruby Client makes it trivial to discover and access supported
|
||||
APIs.
|
||||
TEXT
|
||||
|
||||
list = FileList[
|
||||
'lib/**/*', 'spec/**/*', 'vendor/**/*',
|
||||
'tasks/**/*', 'website/**/*',
|
||||
'[A-Z]*', 'Rakefile'
|
||||
].exclude(/[_\.]git$/)
|
||||
(open(".gitignore") { |file| file.read }).split("\n").each do |pattern|
|
||||
list.exclude(pattern)
|
||||
end
|
||||
PKG_FILES = list
|
||||
|
||||
task :default => 'spec'
|
||||
|
||||
WINDOWS = (RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/) rescue false
|
||||
SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS'])
|
||||
|
|
|
@ -0,0 +1,871 @@
|
|||
---
|
||||
"/adexchangebuyer:v1.3/PerformanceReport/latency50thPercentile": latency_50th_percentile
|
||||
"/adexchangebuyer:v1.3/PerformanceReport/latency85thPercentile": latency_85th_percentile
|
||||
"/adexchangebuyer:v1.3/PerformanceReport/latency95thPercentile": latency_95th_percentile
|
||||
"/adexchangeseller:v2.0/adexchangeseller.accounts.adclients.list": list_account_ad_clients
|
||||
"/adexchangeseller:v2.0/adexchangeseller.accounts.customchannels.get": get_account_custom_channel
|
||||
"/adexchangeseller:v2.0/adexchangeseller.accounts.customchannels.list": list_account_custom_channels
|
||||
"/adexchangeseller:v2.0/adexchangeseller.accounts.metadata.dimensions.list": list_account_metadata_dimensions
|
||||
"/adexchangeseller:v2.0/adexchangeseller.accounts.metadata.metrics.list": list_account_metadata_metrics
|
||||
"/adexchangeseller:v2.0/adexchangeseller.accounts.preferreddeals.get": get_account_preferred_deal
|
||||
"/adexchangeseller:v2.0/adexchangeseller.accounts.preferreddeals.list": list_account_preferred_deals
|
||||
"/adexchangeseller:v2.0/adexchangeseller.accounts.reports.saved.generate": generate_account_saved_report
|
||||
"/adexchangeseller:v2.0/adexchangeseller.accounts.reports.saved.list": list_account_saved_reports
|
||||
"/adexchangeseller:v2.0/adexchangeseller.accounts.urlchannels.list": list_account_url_channels
|
||||
"/admin:directory_v1/directory.chromeosdevices.get": get_chrome_os_device
|
||||
"/admin:directory_v1/directory.chromeosdevices.list": list_chrome_os_devices
|
||||
"/admin:directory_v1/directory.chromeosdevices.patch": patch_chrome_os_device
|
||||
"/admin:directory_v1/directory.chromeosdevices.update": update_chrome_os_device
|
||||
"/admin:directory_v1/directory.groups.aliases.delete/alias": group_alias
|
||||
"/admin:directory_v1/directory.mobiledevices.action": action_mobile_device
|
||||
"/admin:directory_v1/directory.mobiledevices.delete": delete_mobile_device
|
||||
"/admin:directory_v1/directory.mobiledevices.get": get_mobile_device
|
||||
"/admin:directory_v1/directory.mobiledevices.list": list_mobile_devices
|
||||
"/admin:directory_v1/directory.orgunits.delete": delete_org_unit
|
||||
"/admin:directory_v1/directory.orgunits.get": get_org_unit
|
||||
"/admin:directory_v1/directory.orgunits.insert": insert_org_unit
|
||||
"/admin:directory_v1/directory.orgunits.list": list_org_units
|
||||
"/admin:directory_v1/directory.orgunits.patch": patch_org_unit
|
||||
"/admin:directory_v1/directory.orgunits.update": update_org_unit
|
||||
"/admin:directory_v1/directory.users.aliases.delete/alias": user_alias
|
||||
"/adsense:v1.4/AdsenseReportsGenerateResponse": generate_report_response
|
||||
"/adsense:v1.4/adsense.accounts.adclients.list": list_account_ad_clients
|
||||
"/adsense:v1.4/adsense.accounts.adunits.customchannels.list": list_account_ad_unit_custom_channels
|
||||
"/adsense:v1.4/adsense.accounts.adunits.get": get_account_ad_unit
|
||||
"/adsense:v1.4/adsense.accounts.adunits.getAdCode": get_account_ad_unit_ad_code
|
||||
"/adsense:v1.4/adsense.accounts.adunits.list": list_account_ad_units
|
||||
"/adsense:v1.4/adsense.accounts.customchannels.adunits.list": list_account_custom_channel_ad_units
|
||||
"/adsense:v1.4/adsense.accounts.customchannels.get": get_account_custom_channel
|
||||
"/adsense:v1.4/adsense.accounts.customchannels.list": list_account_custom_channels
|
||||
"/adsense:v1.4/adsense.accounts.reports.saved.generate": generate_account_saved_report
|
||||
"/adsense:v1.4/adsense.accounts.reports.saved.list": list_account_saved_reports
|
||||
"/adsense:v1.4/adsense.accounts.savedadstyles.get": get_account_saved_ad_style
|
||||
"/adsense:v1.4/adsense.accounts.savedadstyles.list": list_account_saved_ad_styles
|
||||
"/adsense:v1.4/adsense.accounts.urlchannels.list": list_account_url_channels
|
||||
"/adsense:v1.4/adsense.adclients.list": list_ad_clients
|
||||
"/adsense:v1.4/adsense.adunits.customchannels.list": list_ad_unit_custom_channels
|
||||
"/adsense:v1.4/adsense.adunits.get": get_ad_unit
|
||||
"/adsense:v1.4/adsense.adunits.getAdCode": get_ad_code_ad_unit
|
||||
"/adsense:v1.4/adsense.adunits.list": list_ad_units
|
||||
"/adsense:v1.4/adsense.customchannels.adunits.list": list_custom_channel_ad_units
|
||||
"/adsense:v1.4/adsense.customchannels.get": get_custom_channel
|
||||
"/adsense:v1.4/adsense.customchannels.list": list_custom_channels
|
||||
"/adsense:v1.4/adsense.metadata.dimensions.list": list_metadata_dimensions
|
||||
"/adsense:v1.4/adsense.metadata.metrics.list": list_metadata_metrics
|
||||
"/adsense:v1.4/adsense.reports.saved.generate": generate_saved_report
|
||||
"/adsense:v1.4/adsense.reports.saved.list": list_saved_reports
|
||||
"/adsense:v1.4/adsense.savedadstyles.get": get_saved_ad_style
|
||||
"/adsense:v1.4/adsense.savedadstyles.list": list_saved_ad_styles
|
||||
"/adsense:v1.4/adsense.urlchannels.list": list_url_channels
|
||||
"/adsensehost:v4.1/adsensehost.accounts.adclients.get": get_account_ad_client
|
||||
"/adsensehost:v4.1/adsensehost.accounts.adclients.list": list_account_ad_clients
|
||||
"/adsensehost:v4.1/adsensehost.accounts.adunits.delete": delete_account_ad_unit
|
||||
"/adsensehost:v4.1/adsensehost.accounts.adunits.get": get_account_ad_unit
|
||||
"/adsensehost:v4.1/adsensehost.accounts.adunits.getAdCode": get_account_ad_unit_ad_code
|
||||
"/adsensehost:v4.1/adsensehost.accounts.adunits.insert": insert_account_ad_unit
|
||||
"/adsensehost:v4.1/adsensehost.accounts.adunits.list": list_account_ad_units
|
||||
"/adsensehost:v4.1/adsensehost.accounts.adunits.patch": patch_account_ad_unit
|
||||
"/adsensehost:v4.1/adsensehost.accounts.adunits.update": update_account_ad_unit
|
||||
"/adsensehost:v4.1/adsensehost.adclients.get": get_ad_client
|
||||
"/adsensehost:v4.1/adsensehost.adclients.list": list_ad_clients
|
||||
"/adsensehost:v4.1/adsensehost.associationsessions.start": start_association_session
|
||||
"/adsensehost:v4.1/adsensehost.associationsessions.verify": verify_association_session
|
||||
"/adsensehost:v4.1/adsensehost.customchannels.delete": delete_custom_channel
|
||||
"/adsensehost:v4.1/adsensehost.customchannels.get": get_custom_channel
|
||||
"/adsensehost:v4.1/adsensehost.customchannels.insert": insert_custom_channel
|
||||
"/adsensehost:v4.1/adsensehost.customchannels.list": list_custom_channels
|
||||
"/adsensehost:v4.1/adsensehost.customchannels.patch": patch_custom_channel
|
||||
"/adsensehost:v4.1/adsensehost.customchannels.update": update_custom_channel
|
||||
"/adsensehost:v4.1/adsensehost.urlchannels.delete": delete_url_channel
|
||||
"/adsensehost:v4.1/adsensehost.urlchannels.insert": insert_url_channel
|
||||
"/adsensehost:v4.1/adsensehost.urlchannels.list": list_url_channels
|
||||
"/analytics:v3/AnalyticsDataimportDeleteUploadDataRequest": delete_upload_data_request
|
||||
"/analytics:v3/UnsampledReport/cloudStorageDownloadDetails/objectId": obj_id
|
||||
"/analytics:v3/analytics.data.ga.get": get_ga_data
|
||||
"/analytics:v3/analytics.data.mcf.get": get_mcf_data
|
||||
"/analytics:v3/analytics.data.realtime.get": get_realtime_data
|
||||
"/analytics:v3/analytics.management.accountSummaries.list": list_account_summaries
|
||||
"/analytics:v3/analytics.management.accountUserLinks.delete": delete_account_user_link
|
||||
"/analytics:v3/analytics.management.accountUserLinks.insert": insert_account_user_link
|
||||
"/analytics:v3/analytics.management.accountUserLinks.list": list_account_user_links
|
||||
"/analytics:v3/analytics.management.accountUserLinks.update": update_account_user_link
|
||||
"/analytics:v3/analytics.management.accounts.list": list_accounts
|
||||
"/analytics:v3/analytics.management.customDataSources.list": list_custom_data_sources
|
||||
"/analytics:v3/analytics.management.customDimensions.get": get_custom_dimension
|
||||
"/analytics:v3/analytics.management.customDimensions.insert": insert_custom_dimension
|
||||
"/analytics:v3/analytics.management.customDimensions.list": list_custom_dimensions
|
||||
"/analytics:v3/analytics.management.customDimensions.patch": patch_custom_dimension
|
||||
"/analytics:v3/analytics.management.customDimensions.update": update_custom_dimension
|
||||
"/analytics:v3/analytics.management.customMetrics.get": get_custom_metric
|
||||
"/analytics:v3/analytics.management.customMetrics.insert": insert_custom_metric
|
||||
"/analytics:v3/analytics.management.customMetrics.list": list_custom_metrics
|
||||
"/analytics:v3/analytics.management.customMetrics.patch": patch_custom_metric
|
||||
"/analytics:v3/analytics.management.customMetrics.update": update_custom_metric
|
||||
"/analytics:v3/analytics.management.experiments.delete": delete_experiment
|
||||
"/analytics:v3/analytics.management.experiments.get": get_experiment
|
||||
"/analytics:v3/analytics.management.experiments.insert": insert_experiment
|
||||
"/analytics:v3/analytics.management.experiments.list": list_experiments
|
||||
"/analytics:v3/analytics.management.experiments.patch": patch_experiment
|
||||
"/analytics:v3/analytics.management.experiments.update": update_experiment
|
||||
"/analytics:v3/analytics.management.filters.delete": delete_filter
|
||||
"/analytics:v3/analytics.management.filters.get": get_filter
|
||||
"/analytics:v3/analytics.management.filters.insert": insert_filter
|
||||
"/analytics:v3/analytics.management.filters.list": list_filters
|
||||
"/analytics:v3/analytics.management.filters.patch": patch_filter
|
||||
"/analytics:v3/analytics.management.filters.update": update_filter
|
||||
"/analytics:v3/analytics.management.goals.get": get_goal
|
||||
"/analytics:v3/analytics.management.goals.insert": insert_goal
|
||||
"/analytics:v3/analytics.management.goals.list": list_goals
|
||||
"/analytics:v3/analytics.management.goals.patch": patch_goal
|
||||
"/analytics:v3/analytics.management.goals.update": update_goal
|
||||
"/analytics:v3/analytics.management.profileFilterLinks.delete": delete_profile_filter_link
|
||||
"/analytics:v3/analytics.management.profileFilterLinks.get": get_profile_filter_link
|
||||
"/analytics:v3/analytics.management.profileFilterLinks.insert": insert_profile_filter_link
|
||||
"/analytics:v3/analytics.management.profileFilterLinks.list": list_profile_filter_links
|
||||
"/analytics:v3/analytics.management.profileFilterLinks.patch": patch_profile_filter_link
|
||||
"/analytics:v3/analytics.management.profileFilterLinks.update": update_profile_filter_link
|
||||
"/analytics:v3/analytics.management.profileUserLinks.delete": delete_profile_user_link
|
||||
"/analytics:v3/analytics.management.profileUserLinks.insert": insert_profile_user_link
|
||||
"/analytics:v3/analytics.management.profileUserLinks.list": list_profile_user_links
|
||||
"/analytics:v3/analytics.management.profileUserLinks.update": update_profile_user_link
|
||||
"/analytics:v3/analytics.management.profiles.delete": delete_profile
|
||||
"/analytics:v3/analytics.management.profiles.get": get_profile
|
||||
"/analytics:v3/analytics.management.profiles.insert": insert_profile
|
||||
"/analytics:v3/analytics.management.profiles.list": list_profiles
|
||||
"/analytics:v3/analytics.management.profiles.patch": patch_profile
|
||||
"/analytics:v3/analytics.management.profiles.update": update_profile
|
||||
"/analytics:v3/analytics.management.segments.list": list_segments
|
||||
"/analytics:v3/analytics.management.unsampledReports.get": get_unsampled_report
|
||||
"/analytics:v3/analytics.management.unsampledReports.insert": insert_unsampled_report
|
||||
"/analytics:v3/analytics.management.unsampledReports.list": list_unsampled_reports
|
||||
"/analytics:v3/analytics.management.uploads.deleteUploadData": delete_upload_data
|
||||
"/analytics:v3/analytics.management.uploads.get": get_upload
|
||||
"/analytics:v3/analytics.management.uploads.list": list_uploads
|
||||
"/analytics:v3/analytics.management.uploads.uploadData": upload_data
|
||||
"/analytics:v3/analytics.management.webPropertyAdWordsLinks.delete": delete_web_property_ad_words_link
|
||||
"/analytics:v3/analytics.management.webPropertyAdWordsLinks.get": get_web_property_ad_words_link
|
||||
"/analytics:v3/analytics.management.webPropertyAdWordsLinks.insert": insert_web_property_ad_words_link
|
||||
"/analytics:v3/analytics.management.webPropertyAdWordsLinks.list": list_web_property_ad_words_links
|
||||
"/analytics:v3/analytics.management.webPropertyAdWordsLinks.patch": patch_web_property_ad_words_link
|
||||
"/analytics:v3/analytics.management.webPropertyAdWordsLinks.update": update_web_property_ad_words_link
|
||||
"/analytics:v3/analytics.management.webproperties.get": get_web_property
|
||||
"/analytics:v3/analytics.management.webproperties.insert": insert_web_property
|
||||
"/analytics:v3/analytics.management.webproperties.list": list_web_properties
|
||||
"/analytics:v3/analytics.management.webproperties.patch": patch_web_property
|
||||
"/analytics:v3/analytics.management.webproperties.update": update_web_property
|
||||
"/analytics:v3/analytics.management.webpropertyUserLinks.delete": delete_web_property_user_link
|
||||
"/analytics:v3/analytics.management.webpropertyUserLinks.insert": insert_web_property_user_link
|
||||
"/analytics:v3/analytics.management.webpropertyUserLinks.list": list_web_property_user_links
|
||||
"/analytics:v3/analytics.management.webpropertyUserLinks.update": update_web_property_user_link
|
||||
"/analytics:v3/analytics.metadata.columns.list": list_metadata_columns
|
||||
"/analytics:v3/analytics.provisioning.createAccountTicket": create_account_ticket
|
||||
"/androidenterprise:v1/CollectionViewersListResponse": list_collection_viewers_response
|
||||
"/androidenterprise:v1/CollectionsListResponse": list_collections_response
|
||||
"/androidenterprise:v1/DevicesListResponse": list_devices_response
|
||||
"/androidenterprise:v1/EnterprisesListResponse": list_enterprises_response
|
||||
"/androidenterprise:v1/EntitlementsListResponse": list_entitlements_response
|
||||
"/androidenterprise:v1/GroupLicenseUsersListResponse": list_group_license_users_response
|
||||
"/androidenterprise:v1/GroupLicensesListResponse": list_group_licenses_response
|
||||
"/androidenterprise:v1/InstallsListResponse": list_installs_response
|
||||
"/androidenterprise:v1/UsersListResponse": list_users_response
|
||||
"/androidenterprise:v1/androidenterprise.collectionviewers.delete": delete_collection_viewer
|
||||
"/androidenterprise:v1/androidenterprise.collectionviewers.get": get_collection_viewer
|
||||
"/androidenterprise:v1/androidenterprise.collectionviewers.list": list_collection_viewers
|
||||
"/androidenterprise:v1/androidenterprise.collectionviewers.patch": patch_collection_viewer
|
||||
"/androidenterprise:v1/androidenterprise.collectionviewers.update": update_collection_viewer
|
||||
"/androidenterprise:v1/androidenterprise.grouplicenses.get": get_group_license
|
||||
"/androidenterprise:v1/androidenterprise.grouplicenses.list": list_group_licenses
|
||||
"/androidenterprise:v1/androidenterprise.grouplicenseusers.list": list_group_license_users
|
||||
"/androidenterprise:v1/androidenterprise.products.generateApprovalUrl": generate_product_approval_url
|
||||
"/androidenterprise:v1/androidenterprise.products.getAppRestrictionsSchema": get_product_app_restrictions_schema
|
||||
"/androidenterprise:v1/androidenterprise.products.getPermissions": get_product_permissions
|
||||
"/androidenterprise:v1/androidenterprise.products.updatePermissions": update_product_permissions
|
||||
"/androidenterprise:v1/androidenterprise.users.generateToken": generate_user_token
|
||||
"/androidenterprise:v1/androidenterprise.users.revokeToken": revoke_user_token
|
||||
"/androidenterprise:v1/ProductsGenerateApprovalUrlResponse": generate_product_approval_url_response
|
||||
"/androidenterprise:v1/ProductsApproveRequest": approve_product_request
|
||||
"/androidpublisher:v2/ApkListingsListResponse": list_apk_listings_response
|
||||
"/androidpublisher:v2/ApksAddExternallyHostedRequest": apks_add_externally_hosted_request
|
||||
"/androidpublisher:v2/ApksAddExternallyHostedResponse": apks_add_externally_hosted_response
|
||||
"/androidpublisher:v2/ApksListResponse": list_apks_response
|
||||
"/androidpublisher:v2/EntitlementsListResponse": list_entitlements_response
|
||||
"/androidpublisher:v2/ExpansionFilesUploadResponse": upload_expansion_files_response
|
||||
"/androidpublisher:v2/ImagesDeleteAllResponse": images_delete_all_response
|
||||
"/androidpublisher:v2/ImagesListResponse": list_images_response
|
||||
"/androidpublisher:v2/ImagesUploadResponse": upload_images_response
|
||||
"/androidpublisher:v2/InappproductsBatchRequest": in_app_products_batch_request
|
||||
"/androidpublisher:v2/InappproductsBatchRequestEntry": in_app_products_batch_request_entry
|
||||
"/androidpublisher:v2/InappproductsBatchResponse": in_app_products_batch_response
|
||||
"/androidpublisher:v2/InappproductsBatchResponseEntry": in_app_products_batch_response_entry
|
||||
"/androidpublisher:v2/InappproductsInsertRequest": insert_in_app_products_request
|
||||
"/androidpublisher:v2/InappproductsInsertResponse": insert_in_app_products_response
|
||||
"/androidpublisher:v2/InappproductsListResponse": list_in_app_products_response
|
||||
"/androidpublisher:v2/InappproductsUpdateRequest": update_in_app_products_request
|
||||
"/androidpublisher:v2/InappproductsUpdateResponse": update_in_app_products_response
|
||||
"/androidpublisher:v2/ListingsListResponse": list_listings_response
|
||||
"/androidpublisher:v2/SubscriptionPurchasesDeferRequest": defer_subscription_purchases_request
|
||||
"/androidpublisher:v2/SubscriptionPurchasesDeferResponse": defer_subscription_purchases_response
|
||||
"/androidpublisher:v2/TracksListResponse": list_tracks_response
|
||||
"/androidpublisher:v2/androidpublisher.edits.apklistings.delete": delete_apk_listing
|
||||
"/androidpublisher:v2/androidpublisher.edits.apklistings.deleteall": delete_all_apk_listings
|
||||
"/androidpublisher:v2/androidpublisher.edits.apklistings.get": get_apk_listing
|
||||
"/androidpublisher:v2/androidpublisher.edits.apklistings.list": list_apk_listings
|
||||
"/androidpublisher:v2/androidpublisher.edits.apklistings.patch": patch_apk_listing
|
||||
"/androidpublisher:v2/androidpublisher.edits.apklistings.update": update_apk_listing
|
||||
"/androidpublisher:v2/androidpublisher.edits.apks.addexternallyhosted": add_externally_hosted_apk
|
||||
"/androidpublisher:v2/androidpublisher.edits.apks.list": list_apks
|
||||
"/androidpublisher:v2/androidpublisher.edits.apks.upload": upload_apk
|
||||
"/androidpublisher:v2/androidpublisher.edits.details.get": get_detail
|
||||
"/androidpublisher:v2/androidpublisher.edits.details.patch": patch_detail
|
||||
"/androidpublisher:v2/androidpublisher.edits.details.update": update_detail
|
||||
"/androidpublisher:v2/androidpublisher.edits.expansionfiles.get": get_expansion_file
|
||||
"/androidpublisher:v2/androidpublisher.edits.expansionfiles.patch": patch_expansion_file
|
||||
"/androidpublisher:v2/androidpublisher.edits.expansionfiles.update": update_expansion_file
|
||||
"/androidpublisher:v2/androidpublisher.edits.expansionfiles.upload": upload_expansion_file
|
||||
"/androidpublisher:v2/androidpublisher.edits.images.delete": delete_image
|
||||
"/androidpublisher:v2/androidpublisher.edits.images.deleteall": delete_all_images
|
||||
"/androidpublisher:v2/androidpublisher.edits.images.list": list_images
|
||||
"/androidpublisher:v2/androidpublisher.edits.images.upload": upload_image
|
||||
"/androidpublisher:v2/androidpublisher.edits.listings.delete": delete_listing
|
||||
"/androidpublisher:v2/androidpublisher.edits.listings.deleteall": delete_all_listings
|
||||
"/androidpublisher:v2/androidpublisher.edits.listings.get": get_listing
|
||||
"/androidpublisher:v2/androidpublisher.edits.listings.list": list_listings
|
||||
"/androidpublisher:v2/androidpublisher.edits.listings.patch": patch_listing
|
||||
"/androidpublisher:v2/androidpublisher.edits.listings.update": update_listing
|
||||
"/androidpublisher:v2/androidpublisher.edits.testers.get": get_tester
|
||||
"/androidpublisher:v2/androidpublisher.edits.testers.patch": patch_tester
|
||||
"/androidpublisher:v2/androidpublisher.edits.testers.update": update_tester
|
||||
"/androidpublisher:v2/androidpublisher.edits.tracks.get": get_track
|
||||
"/androidpublisher:v2/androidpublisher.edits.tracks.list": list_tracks
|
||||
"/androidpublisher:v2/androidpublisher.edits.tracks.patch": patch_track
|
||||
"/androidpublisher:v2/androidpublisher.edits.tracks.update": update_track
|
||||
"/androidpublisher:v2/androidpublisher.entitlements.list": list_entitlements
|
||||
"/androidpublisher:v2/androidpublisher.inappproducts.batch": batch_update_in_app_products
|
||||
"/androidpublisher:v2/androidpublisher.inappproducts.delete": delete_in_app_product
|
||||
"/androidpublisher:v2/androidpublisher.inappproducts.get": get_in_app_product
|
||||
"/androidpublisher:v2/androidpublisher.inappproducts.insert": insert_in_app_product
|
||||
"/androidpublisher:v2/androidpublisher.inappproducts.list": list_in_app_products
|
||||
"/androidpublisher:v2/androidpublisher.inappproducts.patch": patch_in_app_product
|
||||
"/androidpublisher:v2/androidpublisher.inappproducts.update": update_in_app_product
|
||||
"/androidpublisher:v2/androidpublisher.purchases.products.get": get_purchase_product
|
||||
"/androidpublisher:v2/androidpublisher.purchases.subscriptions.cancel": cancel_purchase_subscription
|
||||
"/androidpublisher:v2/androidpublisher.purchases.subscriptions.defer": defer_purchase_subscription
|
||||
"/androidpublisher:v2/androidpublisher.purchases.subscriptions.get": get_purchase_subscription
|
||||
"/androidpublisher:v2/androidpublisher.purchases.subscriptions.refund": refund_purchase_subscription
|
||||
"/androidpublisher:v2/androidpublisher.purchases.subscriptions.revoke": revoke_purchase_subscription
|
||||
"/autoscaler:v1beta2/AutoscalerListResponse": list_autoscaler_response
|
||||
"/bigquery:v2/TableDataInsertAllRequest": insert_all_table_data_request
|
||||
"/bigquery:v2/TableDataInsertAllResponse": insert_all_table_data_response
|
||||
"/bigquery:v2/bigquery.jobs.getQueryResults": get_job_query_results
|
||||
"/bigquery:v2/bigquery.tabledata.insertAll": insert_all_table_data
|
||||
"/bigquery:v2/bigquery.tabledata.list": list_table_data
|
||||
"/bigquery:v2/JobCancelResponse": cancel_job_response
|
||||
"/blogger:v3/blogger.blogs.getByUrl": get_blog_by_url
|
||||
"/blogger:v3/blogger.blogs.listByUser": list_blogs_by_user
|
||||
"/blogger:v3/blogger.comments.listByBlog": list_comments_by_blog
|
||||
"/blogger:v3/blogger.comments.markAsSpam": mark_comment_as_spam
|
||||
"/blogger:v3/blogger.comments.removeContent": remove_comment_content
|
||||
"/blogger:v3/blogger.postUserInfos.get": get_post_user_info
|
||||
"/blogger:v3/blogger.postUserInfos.list": list_post_user_info
|
||||
"/blogger:v3/blogger.posts.getByPath": get_post_by_path
|
||||
"/books:v1/Annotationdata": annotation_data
|
||||
"/books:v1/AnnotationsSummary": annotations_summary
|
||||
"/books:v1/Annotationsdata": annotations_data
|
||||
"/books:v1/BooksAnnotationsRange": annotatins_Range
|
||||
"/books:v1/BooksCloudloadingResource": loading_resource
|
||||
"/books:v1/BooksVolumesRecommendedRateResponse": rate_recommended_volume_response
|
||||
"/books:v1/Dictlayerdata": dict_layer_data
|
||||
"/books:v1/Geolayerdata": geo_layer_data
|
||||
"/books:v1/Layersummaries": layer_summaries
|
||||
"/books:v1/Layersummary": layer_summary
|
||||
"/books:v1/Usersettings": user_settings
|
||||
"/books:v1/Volumeannotation": volume_annotation
|
||||
"/books:v1/books.bookshelves.get": get_bookshelf
|
||||
"/books:v1/books.bookshelves.list": list_bookshelves
|
||||
"/books:v1/books.bookshelves.volumes.list": list_bookshelf_volumes
|
||||
"/books:v1/books.cloudloading.addBook": add_book
|
||||
"/books:v1/books.cloudloading.deleteBook": delete_book
|
||||
"/books:v1/books.cloudloading.updateBook": update_book
|
||||
"/books:v1/books.dictionary.listOfflineMetadata": list_offline_metadata_dictionary
|
||||
"/books:v1/books.layers.annotationData.get": get_layer_annotation_data
|
||||
"/books:v1/books.layers.annotationData.list": list_layer_annotation_data
|
||||
"/books:v1/books.layers.get": get_layer
|
||||
"/books:v1/books.layers.list": list_layers
|
||||
"/books:v1/books.layers.volumeAnnotations.get": get_layer_volume_annotation
|
||||
"/books:v1/books.layers.volumeAnnotations.list": list_layer_volume_annotations
|
||||
"/books:v1/books.myconfig.getUserSettings": get_user_settings
|
||||
"/books:v1/books.myconfig.releaseDownloadAccess": release_download_access
|
||||
"/books:v1/books.myconfig.requestAccess": request_access
|
||||
"/books:v1/books.myconfig.syncVolumeLicenses": sync_volume_licenses
|
||||
"/books:v1/books.myconfig.updateUserSettings": update_user_settings
|
||||
"/books:v1/books.mylibrary.annotations.delete": delete_my_library_annotation
|
||||
"/books:v1/books.mylibrary.annotations.insert": insert_my_library_annotation
|
||||
"/books:v1/books.mylibrary.annotations.list": list_my_library_annotations
|
||||
"/books:v1/books.mylibrary.annotations.summary": summarize_my_library_annotation
|
||||
"/books:v1/books.mylibrary.annotations.update": update_my_library_annotation
|
||||
"/books:v1/books.mylibrary.bookshelves.addVolume": add_my_library_volume
|
||||
"/books:v1/books.mylibrary.bookshelves.clearVolumes": clear_my_library_volumes
|
||||
"/books:v1/books.mylibrary.bookshelves.get": get_my_library_bookshelf
|
||||
"/books:v1/books.mylibrary.bookshelves.list": list_my_library_bookshelves
|
||||
"/books:v1/books.mylibrary.bookshelves.moveVolume": move_my_library_volume
|
||||
"/books:v1/books.mylibrary.bookshelves.removeVolume": remove_my_library_volume
|
||||
"/books:v1/books.mylibrary.bookshelves.volumes.list": list_my_library_volumes
|
||||
"/books:v1/books.mylibrary.readingpositions.get": get_my_library_reading_position
|
||||
"/books:v1/books.mylibrary.readingpositions.setPosition": set_my_library_reading_position
|
||||
"/books:v1/books.onboarding.listCategories": list_onboarding_categories
|
||||
"/books:v1/books.onboarding.listCategoryVolumes": list_onboarding_category_volumes
|
||||
"/books:v1/books.promooffer.accept": accept_promo_offer
|
||||
"/books:v1/books.promooffer.dismiss": dismiss_promo_offer
|
||||
"/books:v1/books.promooffer.get": get_promo_offer
|
||||
"/books:v1/books.volumes.associated.list": list_associated_volumes
|
||||
"/books:v1/books.volumes.mybooks.list": list_my_books
|
||||
"/books:v1/books.volumes.recommended.list": list_recommended_volumes
|
||||
"/books:v1/books.volumes.recommended.rate": rate_recommended_volume
|
||||
"/books:v1/books.volumes.useruploaded.list": list_user_uploaded_volumes
|
||||
"/calendar:v3/CalendarNotification/method": delivery_method
|
||||
"/calendar:v3/Event/gadget/display": display_mode
|
||||
"/calendar:v3/EventReminder/method": reminder_method
|
||||
"/civicinfo:v2/DivisionSearchResponse": search_division_response
|
||||
"/civicinfo:v2/ElectionsQueryResponse": query_elections_response
|
||||
"/civicinfo:v2/civicinfo.divisions.search": search_divisions
|
||||
"/civicinfo:v2/civicinfo.elections.electionQuery": query_election
|
||||
"/civicinfo:v2/civicinfo.elections.voterInfoQuery": query_voter_info
|
||||
"/civicinfo:v2/civicinfo.representatives.representativeInfoByAddress": representative_info_by_address
|
||||
"/civicinfo:v2/civicinfo.representatives.representativeInfoByDivision": representative_info_by_division
|
||||
"/compute:v1/DiskMoveRequest": move_disk_request
|
||||
"/compute:v1/InstanceMoveRequest": move_instance_request
|
||||
"/compute:v1/TargetPoolsAddHealthCheckRequest": add_target_pools_health_check_request
|
||||
"/compute:v1/TargetPoolsAddInstanceRequest": add_target_pools_instance_request
|
||||
"/compute:v1/TargetPoolsRemoveHealthCheckRequest": remove_target_pools_health_check_request
|
||||
"/compute:v1/TargetPoolsRemoveInstanceRequest": remove_target_pools_instance_request
|
||||
"/compute:v1/UrlMapsValidateRequest": validate_url_maps_request
|
||||
"/compute:v1/UrlMapsValidateResponse": validate_url_maps_response
|
||||
"/compute:v1/compute.addresses.aggregatedList": list_aggregated_addresses
|
||||
"/compute:v1/compute.backendServices.getHealth": get_backend_service_health
|
||||
"/compute:v1/compute.diskTypes.aggregatedList": list_aggregated_disk_types
|
||||
"/compute:v1/compute.disks.aggregatedList": list_aggregated_disk
|
||||
"/compute:v1/compute.disks.createSnapshot": create_disk_snapshot
|
||||
"/compute:v1/compute.forwardingRules.aggregatedList": list_aggregated_forwarding_rules
|
||||
"/compute:v1/compute.forwardingRules.setTarget": set_forwarding_rule_target
|
||||
"/compute:v1/compute.globalForwardingRules.setTarget": set_global_forwarding_rule_target
|
||||
"/compute:v1/compute.globalOperations.aggregatedList": list_aggregated_global_operation
|
||||
"/compute:v1/compute.instances.addAccessConfig": add_instance_access_config
|
||||
"/compute:v1/compute.instances.aggregatedList": list_aggregated_instances
|
||||
"/compute:v1/compute.instances.attachDisk": attach_disk
|
||||
"/compute:v1/compute.instances.deleteAccessConfig": delete_instance_access_config
|
||||
"/compute:v1/compute.instances.detachDisk": detach_disk
|
||||
"/compute:v1/compute.instances.getSerialPortOutput": get_instance_serial_port_output
|
||||
"/compute:v1/compute.instances.setDiskAutoDelete": set_disk_auto_delete
|
||||
"/compute:v1/compute.instances.setMetadata": set_instance_metadata
|
||||
"/compute:v1/compute.instances.setScheduling": set_instance_scheduling
|
||||
"/compute:v1/compute.instances.setTags": set_instance_tags
|
||||
"/compute:v1/compute.machineTypes.aggregatedList": list_aggregated_machine_types
|
||||
"/compute:v1/compute.projects.moveDisk": move_disk
|
||||
"/compute:v1/compute.projects.moveInstance": move_instance
|
||||
"/compute:v1/compute.projects.setCommonInstanceMetadata": set_common_instance_metadata
|
||||
"/compute:v1/compute.projects.setUsageExportBucket": set_usage_export_bucket
|
||||
"/compute:v1/compute.targetHttpProxies.setUrlMap": set_target_http_proxy_url_map
|
||||
"/compute:v1/compute.targetInstances.aggregatedList": list_aggregated_target_instance
|
||||
"/compute:v1/compute.targetPools.addHealthCheck": add_target_pool_health_check
|
||||
"/compute:v1/compute.targetPools.addInstance": add_target_pool_instance
|
||||
"/compute:v1/compute.targetPools.aggregatedList": list_aggregated_target_pools
|
||||
"/compute:v1/compute.targetPools.getHealth": get_target_pool_health
|
||||
"/compute:v1/compute.targetPools.removeHealthCheck": remove_target_pool_health_check
|
||||
"/compute:v1/compute.targetPools.removeInstance": remove_target_pool_instance
|
||||
"/compute:v1/compute.targetPools.setBackup": set_target_pool_backup
|
||||
"/compute:v1/compute.targetVpnGateways.aggregatedList": list_aggregated_target_vpn_gateways
|
||||
"/compute:v1/compute.targetVpnGateways.delete": delete_target_vpn_gateway
|
||||
"/compute:v1/compute.targetVpnGateways.get": get_target_vpn_gateway
|
||||
"/compute:v1/compute.targetVpnGateways.insert": insert_target_vpn_gateway
|
||||
"/compute:v1/compute.targetVpnGateways.list": list_target_vpn_gateways
|
||||
"/compute:v1/compute.vpnTunnels.aggregatedList": list_aggregated_vpn_tunnel
|
||||
"/container:v1beta1/container.projects.clusters.list": list_clusters
|
||||
"/container:v1beta1/container.projects.operations.list": list_operations
|
||||
"/container:v1beta1/container.projects.zones.clusters.create": create_cluster
|
||||
"/container:v1beta1/container.projects.zones.clusters.delete": delete_zone_cluster
|
||||
"/container:v1beta1/container.projects.zones.clusters.get": get_zone_cluster
|
||||
"/container:v1beta1/container.projects.zones.clusters.list": list_zone_clusters
|
||||
"/container:v1beta1/container.projects.zones.operations.get": get_zone_operation
|
||||
"/container:v1beta1/container.projects.zones.operations.list": list_zone_operations
|
||||
"/container:v1beta1/container.projects.zones.tokens.get": get_zone_token
|
||||
"/content:v2/AccountsAuthInfoResponse": accounts_auth_info_response
|
||||
"/content:v2/AccountsCustomBatchRequest": accounts_custom_batch_request
|
||||
"/content:v2/AccountsCustomBatchRequest": batch_accounts_request
|
||||
"/content:v2/AccountsCustomBatchRequestEntry": accounts_batch_request_entry
|
||||
"/content:v2/AccountsCustomBatchRequestEntry/method": request_method
|
||||
"/content:v2/AccountsCustomBatchResponse": batch_accounts_response
|
||||
"/content:v2/AccountsCustomBatchResponse": batch_accounts_response
|
||||
"/content:v2/AccountsCustomBatchResponseEntry": accounts_batch_response_entry
|
||||
"/content:v2/AccountsListResponse": list_accounts_response
|
||||
"/content:v2/AccountshippingCustomBatchRequest": batch_account_shipping_request
|
||||
"/content:v2/AccountshippingCustomBatchRequest": batch_account_shipping_request
|
||||
"/content:v2/AccountshippingCustomBatchRequestEntry": account_shipping_batch_request_entry
|
||||
"/content:v2/AccountshippingCustomBatchRequestEntry/method": request_method
|
||||
"/content:v2/AccountshippingCustomBatchResponse": batch_account_shipping_response
|
||||
"/content:v2/AccountshippingCustomBatchResponse": batch_account_shipping_response
|
||||
"/content:v2/AccountshippingCustomBatchResponseEntry": account_shipping_batch_response_entry
|
||||
"/content:v2/AccountshippingListResponse": list_account_shipping_response
|
||||
"/content:v2/AccountstatusesCustomBatchRequest": batch_account_statuses_request
|
||||
"/content:v2/AccountstatusesCustomBatchRequest": batch_account_statuses_request
|
||||
"/content:v2/AccountstatusesCustomBatchRequestEntry": account_statuses_batch_request_entry
|
||||
"/content:v2/AccountstatusesCustomBatchRequestEntry/method": request_method
|
||||
"/content:v2/AccountstatusesCustomBatchResponse": batch_account_statuses_response
|
||||
"/content:v2/AccountstatusesCustomBatchResponse": batch_account_statuses_response
|
||||
"/content:v2/AccountstatusesCustomBatchResponseEntry": account_statuses_batch_response_entry
|
||||
"/content:v2/AccountstatusesListResponse": list_account_statuses_response
|
||||
"/content:v2/AccounttaxCustomBatchRequest": batch_account_tax_request
|
||||
"/content:v2/AccounttaxCustomBatchRequest": batch_account_tax_request
|
||||
"/content:v2/AccounttaxCustomBatchRequestEntry": account_tax_batch_request_entry
|
||||
"/content:v2/AccounttaxCustomBatchRequestEntry/method": request_method
|
||||
"/content:v2/AccounttaxCustomBatchResponse": batch_account_tax_response
|
||||
"/content:v2/AccounttaxCustomBatchResponse": batch_account_tax_response
|
||||
"/content:v2/AccounttaxCustomBatchResponseEntry": account_tax_batch_response_entry
|
||||
"/content:v2/AccounttaxListResponse": list_account_tax_response
|
||||
"/content:v2/DatafeedsCustomBatchRequest": batch_datafeeds_request
|
||||
"/content:v2/DatafeedsCustomBatchRequest": batch_datafeeds_request
|
||||
"/content:v2/DatafeedsCustomBatchRequestEntry": datafeeds_batch_request_entry
|
||||
"/content:v2/DatafeedsCustomBatchRequestEntry/method": request_method
|
||||
"/content:v2/DatafeedsCustomBatchResponse": batch_datafeeds_response
|
||||
"/content:v2/DatafeedsCustomBatchResponse": batch_datafeeds_response
|
||||
"/content:v2/DatafeedsCustomBatchResponseEntry": datafeeds_batch_response_entry
|
||||
"/content:v2/DatafeedsListResponse": list_datafeeds_response
|
||||
"/content:v2/DatafeedstatusesCustomBatchRequest": batch_datafeed_statuses_request
|
||||
"/content:v2/DatafeedstatusesCustomBatchRequest": batch_datafeed_statuses_request
|
||||
"/content:v2/DatafeedstatusesCustomBatchRequestEntry": datafeed_statuses_batch_request_entry
|
||||
"/content:v2/DatafeedstatusesCustomBatchRequestEntry/method": request_method
|
||||
"/content:v2/DatafeedstatusesCustomBatchResponse": batch_datafeed_statuses_response
|
||||
"/content:v2/DatafeedstatusesCustomBatchResponse": batch_datafeed_statuses_response
|
||||
"/content:v2/DatafeedstatusesCustomBatchResponseEntry": datafeed_statuses_batch_response_entry
|
||||
"/content:v2/DatafeedstatusesListResponse": list_datafeed_statuses_response
|
||||
"/content:v2/InventoryCustomBatchRequest": batch_inventory_request
|
||||
"/content:v2/InventoryCustomBatchRequest": batch_inventory_request
|
||||
"/content:v2/InventoryCustomBatchRequestEntry": inventory_batch_request_entry
|
||||
"/content:v2/InventoryCustomBatchResponse": batch_inventory_response
|
||||
"/content:v2/InventoryCustomBatchResponse": batch_inventory_response
|
||||
"/content:v2/InventoryCustomBatchResponseEntry": inventory_batch_response_entry
|
||||
"/content:v2/InventorySetRequest": set_inventory_request
|
||||
"/content:v2/InventorySetResponse": set_inventory_response
|
||||
"/content:v2/ProductsCustomBatchRequest": batch_products_request
|
||||
"/content:v2/ProductsCustomBatchRequest": batch_products_request
|
||||
"/content:v2/ProductsCustomBatchRequestEntry": products_batch_request_entry
|
||||
"/content:v2/ProductsCustomBatchRequestEntry/method": request_method
|
||||
"/content:v2/ProductsCustomBatchResponse": batch_products_response
|
||||
"/content:v2/ProductsCustomBatchResponse": batch_products_response
|
||||
"/content:v2/ProductsCustomBatchResponseEntry": products_batch_response_entry
|
||||
"/content:v2/ProductsListResponse": list_products_response
|
||||
"/content:v2/ProductstatusesCustomBatchRequest": batch_product_statuses_request
|
||||
"/content:v2/ProductstatusesCustomBatchRequest": batch_product_statuses_request
|
||||
"/content:v2/ProductstatusesCustomBatchRequestEntry": product_statuses_batch_request_entry
|
||||
"/content:v2/ProductstatusesCustomBatchRequestEntry/method": request_method
|
||||
"/content:v2/ProductstatusesCustomBatchResponse": batch_product_statuses_response
|
||||
"/content:v2/ProductstatusesCustomBatchResponse": batch_product_statuses_response
|
||||
"/content:v2/ProductstatusesCustomBatchResponseEntry": product_statuses_batch_response_entry
|
||||
"/content:v2/ProductstatusesListResponse": list_product_statuses_response
|
||||
"/content:v2/content.accounts.authinfo": get_account_authinfo
|
||||
"/content:v2/content.accounts.custombatch": batch_account
|
||||
"/content:v2/content.accountshipping.custombatch": batch_account_shipping
|
||||
"/content:v2/content.accountshipping.get": get_account_shipping
|
||||
"/content:v2/content.accountshipping.list": list_account_shippings
|
||||
"/content:v2/content.accountshipping.patch": patch_account_shipping
|
||||
"/content:v2/content.accountshipping.update": update_account_shipping
|
||||
"/content:v2/content.accountstatuses.custombatch": batch_account_status
|
||||
"/content:v2/content.accountstatuses.get": get_account_status
|
||||
"/content:v2/content.accountstatuses.list": list_account_statuses
|
||||
"/content:v2/content.accounttax.custombatch": batch_account_tax
|
||||
"/content:v2/content.accounttax.get": get_account_tax
|
||||
"/content:v2/content.accounttax.list": list_account_taxes
|
||||
"/content:v2/content.accounttax.patch": patch_account_tax
|
||||
"/content:v2/content.accounttax.update": update_account_tax
|
||||
"/content:v2/content.datafeeds.custombatch": batch_datafeed
|
||||
"/content:v2/content.datafeedstatuses.custombatch": batch_datafeed_status
|
||||
"/content:v2/content.datafeedstatuses.get": get_datafeed_status
|
||||
"/content:v2/content.datafeedstatuses.list": list_datafeed_statuses
|
||||
"/content:v2/content.inventory.custombatch": batch_inventory
|
||||
"/content:v2/content.inventory.set": set_inventory
|
||||
"/content:v2/content.products.custombatch": batch_product
|
||||
"/content:v2/content.productstatuses.custombatch": batch_product_status
|
||||
"/content:v2/content.productstatuses.get": get_product_status
|
||||
"/content:v2/content.productstatuses.list": list_product_statuses
|
||||
"/coordinate:v1/CustomFieldDefListResponse": list_custom_field_def_response
|
||||
"/coordinate:v1/JobListResponse": list_job_response
|
||||
"/coordinate:v1/LocationListResponse": list_location_response
|
||||
"/coordinate:v1/TeamListResponse": list_team_response
|
||||
"/coordinate:v1/WorkerListResponse": list_worker_response
|
||||
"/datastore:v1beta2/AllocateIdsRequest": allocate_ids_request
|
||||
"/datastore:v1beta2/AllocateIdsResponse": allocate_ids_response
|
||||
"/datastore:v1beta2/BeginTransactionRequest": begin_transaction_request
|
||||
"/datastore:v1beta2/BeginTransactionResponse": begin_transaction_response
|
||||
"/deploymentmanager:v2beta1/DeploymentsListResponse": list_deployments_response
|
||||
"/deploymentmanager:v2beta1/ManifestsListResponse": list_manifests_response
|
||||
"/deploymentmanager:v2beta1/OperationsListResponse": list_operations_response
|
||||
"/deploymentmanager:v2beta1/ResourcesListResponse": list_resources_response
|
||||
"/deploymentmanager:v2beta1/TypesListResponse": list_types_response
|
||||
"/deploymentmanager:v2beta2/DeploymentsListResponse": list_deployments_response
|
||||
"/deploymentmanager:v2beta2/ManifestsListResponse": list_manifests_response
|
||||
"/deploymentmanager:v2beta2/OperationsListResponse": list_operations_response
|
||||
"/deploymentmanager:v2beta2/ResourcesListResponse": list_resources_response
|
||||
"/deploymentmanager:v2beta2/TypesListResponse": list_types_response
|
||||
"/dfareporting:v2.1/AccountPermissionGroupsListResponse": list_account_permission_groups_response
|
||||
"/dfareporting:v2.1/AccountPermissionsListResponse": list_account_permissions_response
|
||||
"/dfareporting:v2.1/AccountUserProfilesListResponse": list_account_user_profiles_response
|
||||
"/dfareporting:v2.1/AccountsListResponse": list_accounts_response
|
||||
"/dfareporting:v2.1/AdsListResponse": list_ads_response
|
||||
"/dfareporting:v2.1/AdvertiserGroupsListResponse": list_advertiser_groups_response
|
||||
"/dfareporting:v2.1/AdvertisersListResponse": list_advertisers_response
|
||||
"/dfareporting:v2.1/BrowsersListResponse": list_browsers_response
|
||||
"/dfareporting:v2.1/CampaignCreativeAssociationsListResponse": list_campaign_creative_associations_response
|
||||
"/dfareporting:v2.1/CampaignsListResponse": list_campaigns_response
|
||||
"/dfareporting:v2.1/ChangeLog/objectId": obj_id
|
||||
"/dfareporting:v2.1/ChangeLogsListResponse": list_change_logs_response
|
||||
"/dfareporting:v2.1/CitiesListResponse": list_cities_response
|
||||
"/dfareporting:v2.1/ConnectionTypesListResponse": list_connection_types_response
|
||||
"/dfareporting:v2.1/ContentCategoriesListResponse": list_content_categories_response
|
||||
"/dfareporting:v2.1/CountriesListResponse": list_countries_response
|
||||
"/dfareporting:v2.1/CreativeFieldValuesListResponse": list_creative_field_values_response
|
||||
"/dfareporting:v2.1/CreativeFieldsListResponse": list_creative_fields_response
|
||||
"/dfareporting:v2.1/CreativeGroupsListResponse": list_creative_groups_response
|
||||
"/dfareporting:v2.1/CreativesListResponse": list_creatives_response
|
||||
"/dfareporting:v2.1/DimensionValueRequest": dimension_value_request
|
||||
"/dfareporting:v2.1/DirectorySiteContactsListResponse": list_directory_site_contacts_response
|
||||
"/dfareporting:v2.1/DirectorySitesListResponse": list_directory_sites_response
|
||||
"/dfareporting:v2.1/EventTagsListResponse": list_event_tags_response
|
||||
"/dfareporting:v2.1/FloodlightActivitiesGenerateTagResponse": floodlight_activities_generate_tag_response
|
||||
"/dfareporting:v2.1/FloodlightActivitiesListResponse": list_floodlight_activities_response
|
||||
"/dfareporting:v2.1/FloodlightActivityGroupsListResponse": list_floodlight_activity_groups_response
|
||||
"/dfareporting:v2.1/FloodlightConfigurationsListResponse": list_floodlight_configurations_response
|
||||
"/dfareporting:v2.1/InventoryItemsListResponse": list_inventory_items_response
|
||||
"/dfareporting:v2.1/LandingPagesListResponse": list_landing_pages_response
|
||||
"/dfareporting:v2.1/MetrosListResponse": list_metros_response
|
||||
"/dfareporting:v2.1/MobileCarriersListResponse": list_mobile_carriers_response
|
||||
"/dfareporting:v2.1/ObjectFilter/objectIds/object_id": obj_id
|
||||
"/dfareporting:v2.1/OperatingSystemVersionsListResponse": list_operating_system_versions_response
|
||||
"/dfareporting:v2.1/OperatingSystemsListResponse": list_operating_systems_response
|
||||
"/dfareporting:v2.1/OrderDocumentsListResponse": list_order_documents_response
|
||||
"/dfareporting:v2.1/OrdersListResponse": list_orders_response
|
||||
"/dfareporting:v2.1/PlacementGroupsListResponse": list_placement_groups_response
|
||||
"/dfareporting:v2.1/PlacementStrategiesListResponse": list_placement_strategies_response
|
||||
"/dfareporting:v2.1/PlacementsGenerateTagsResponse": generate_placements_tags_response
|
||||
"/dfareporting:v2.1/PlacementsListResponse": list_placements_response
|
||||
"/dfareporting:v2.1/PlatformTypesListResponse": list_platform_types_response
|
||||
"/dfareporting:v2.1/PostalCodesListResponse": list_postal_codes_response
|
||||
"/dfareporting:v2.1/ProjectsListResponse": list_projects_response
|
||||
"/dfareporting:v2.1/RegionsListResponse": list_regions_response
|
||||
"/dfareporting:v2.1/RemarketingListsListResponse": list_remarketing_lists_response
|
||||
"/dfareporting:v2.1/SitesListResponse": list_sites_response
|
||||
"/dfareporting:v2.1/SizesListResponse": list_sizes_response
|
||||
"/dfareporting:v2.1/SubaccountsListResponse": list_subaccounts_response
|
||||
"/dfareporting:v2.1/TargetableRemarketingListsListResponse": list_targetable_remarketing_lists_response
|
||||
"/dfareporting:v2.1/UserRolePermissionGroupsListResponse": list_user_role_permission_groups_response
|
||||
"/dfareporting:v2.1/UserRolePermissionsListResponse": list_user_role_permissions_response
|
||||
"/dfareporting:v2.1/UserRolesListResponse": list_user_roles_response
|
||||
"/dfareporting:v2.1/dfareporting.floodlightActivities.generatetag": generate_floodlight_activity_tag
|
||||
"/dfareporting:v2.1/dfareporting.placements.generatetags": generate_placement_tags
|
||||
"/discovery:v1/RestDescription/methods": api_methods
|
||||
"/discovery:v1/RestResource/methods": api_methods
|
||||
"/dns:v1/ChangesListResponse": list_changes_response
|
||||
"/dns:v1/ManagedZonesListResponse": list_managed_zones_response
|
||||
"/dns:v1/ResourceRecordSetsListResponse": list_resource_record_sets_response
|
||||
"/doubleclickbidmanager:v1/DownloadLineItemsRequest": download_line_items_request
|
||||
"/doubleclickbidmanager:v1/DownloadLineItemsResponse": download_line_items_response
|
||||
"/doubleclickbidmanager:v1/ListQueriesResponse": list_queries_response
|
||||
"/doubleclickbidmanager:v1/ListReportsResponse": list_reports_response
|
||||
"/doubleclickbidmanager:v1/RunQueryRequest": run_query_request
|
||||
"/doubleclickbidmanager:v1/UploadLineItemsRequest": upload_line_items_request
|
||||
"/doubleclickbidmanager:v1/UploadLineItemsResponse": upload_line_items_response
|
||||
"/doubleclickbidmanager:v1/doubleclickbidmanager.lineitems.downloadlineitems": download_line_items
|
||||
"/doubleclickbidmanager:v1/doubleclickbidmanager.lineitems.uploadlineitems": upload_line_items
|
||||
"/doubleclickbidmanager:v1/doubleclickbidmanager.queries.createquery": create_query
|
||||
"/doubleclickbidmanager:v1/doubleclickbidmanager.queries.deletequery": deletequery
|
||||
"/doubleclickbidmanager:v1/doubleclickbidmanager.queries.getquery": get_query
|
||||
"/doubleclickbidmanager:v1/doubleclickbidmanager.queries.listqueries": list_queries
|
||||
"/doubleclickbidmanager:v1/doubleclickbidmanager.queries.runquery": run_query
|
||||
"/doubleclickbidmanager:v1/doubleclickbidmanager.reports.listreports": list_reports
|
||||
"/doubleclicksearch:v2/ReportRequest": report_request
|
||||
"/doubleclicksearch:v2/UpdateAvailabilityRequest": update_availability_request
|
||||
"/doubleclicksearch:v2/UpdateAvailabilityResponse": update_availability_response
|
||||
"/drive:v2/drive.files.emptyTrash": empty_trash
|
||||
"/drive:v2/drive.permissions.getIdForEmail": get_permission_id_for_email
|
||||
"/fusiontables:v2/fusiontables.table.importRows": import_rows
|
||||
"/fusiontables:v2/fusiontables.table.importTable": import_table
|
||||
"/games:v1/AchievementDefinitionsListResponse": list_achievement_definitions_response
|
||||
"/games:v1/AchievementIncrementResponse": achievement_increment_response
|
||||
"/games:v1/AchievementRevealResponse": achievement_reveal_response
|
||||
"/games:v1/AchievementSetStepsAtLeastResponse": achievement_set_steps_at_least_response
|
||||
"/games:v1/AchievementUnlockResponse": achievement_unlock_response
|
||||
"/games:v1/AchievementUpdateMultipleRequest": achievement_update_multiple_request
|
||||
"/games:v1/AchievementUpdateMultipleResponse": achievement_update_multiple_response
|
||||
"/games:v1/AchievementUpdateRequest": update_achievement_request
|
||||
"/games:v1/AchievementUpdateResponse": update_achievement_response
|
||||
"/games:v1/CategoryListResponse": list_category_response
|
||||
"/games:v1/EventDefinitionListResponse": list_event_definition_response
|
||||
"/games:v1/EventRecordRequest": event_record_request
|
||||
"/games:v1/EventUpdateRequest": update_event_request
|
||||
"/games:v1/EventUpdateResponse": update_event_response
|
||||
"/games:v1/LeaderboardListResponse": list_leaderboard_response
|
||||
"/games:v1/PlayerAchievementListResponse": list_player_achievement_response
|
||||
"/games:v1/PlayerEventListResponse": list_player_event_response
|
||||
"/games:v1/PlayerLeaderboardScoreListResponse": list_player_leaderboard_score_response
|
||||
"/games:v1/PlayerListResponse": list_player_response
|
||||
"/games:v1/PlayerScoreListResponse": list_player_score_response
|
||||
"/games:v1/PlayerScoreResponse": player_score_response
|
||||
"/games:v1/QuestListResponse": list_quest_response
|
||||
"/games:v1/RevisionCheckResponse": check_revision_response
|
||||
"/games:v1/RoomCreateRequest": create_room_request
|
||||
"/games:v1/RoomJoinRequest": join_room_request
|
||||
"/games:v1/RoomLeaveRequest": leave_room_request
|
||||
"/games:v1/SnapshotListResponse": list_snapshot_response
|
||||
"/games:v1/TurnBasedMatchCreateRequest": create_turn_based_match_request
|
||||
"/games:v1/TurnBasedMatchDataRequest": turn_based_match_data_request
|
||||
"/games:v1/games.achievements.updateMultiple": update_multiple_achievements
|
||||
"/games:v1/games.events.listDefinitions": list_event_definitions
|
||||
"/games:v1/games.metagame.getMetagameConfig": get_metagame_config
|
||||
"/games:v1/games.rooms.reportStatus": report_room_status
|
||||
"/games:v1/games.turnBasedMatches.leaveTurn": leave_turn
|
||||
"/games:v1/games.turnBasedMatches.takeTurn": take_turn
|
||||
"/gamesConfiguration:v1configuration/AchievementConfigurationListResponse": list_achievement_configuration_response
|
||||
"/gamesConfiguration:v1configuration/LeaderboardConfigurationListResponse": list_leaderboard_configuration_response
|
||||
"/genomics:v1beta2/genomics.callsets.create": create_call_set
|
||||
"/genomics:v1beta2/genomics.callsets.delete": delete_call_set
|
||||
"/genomics:v1beta2/genomics.callsets.get": get_call_set
|
||||
"/genomics:v1beta2/genomics.callsets.patch": patch_call_set
|
||||
"/genomics:v1beta2/genomics.callsets.search": search_call_sets
|
||||
"/genomics:v1beta2/genomics.callsets.update": update_call_set
|
||||
"/genomics:v1beta2/genomics.readgroupsets.align": align_read_group_sets
|
||||
"/genomics:v1beta2/genomics.readgroupsets.call": call_read_group_sets
|
||||
"/genomics:v1beta2/genomics.readgroupsets.coveragebuckets.list": list_coverage_buckets
|
||||
"/genomics:v1beta2/genomics.readgroupsets.delete": delete_read_group_set
|
||||
"/genomics:v1beta2/genomics.readgroupsets.export": export_read_group_sets
|
||||
"/genomics:v1beta2/genomics.readgroupsets.get": get_read_group_set
|
||||
"/genomics:v1beta2/genomics.readgroupsets.import": import_read_group_sets
|
||||
"/genomics:v1beta2/genomics.readgroupsets.patch": patch_read_group_set
|
||||
"/genomics:v1beta2/genomics.readgroupsets.search": search_read_group_sets
|
||||
"/genomics:v1beta2/genomics.readgroupsets.update": update_read_group_set
|
||||
"/genomics:v1beta2/genomics.references.bases.list/end": end_position
|
||||
"/genomics:v1beta2/genomics.references.bases.list/start": start_position
|
||||
"/genomics:v1beta2/genomics.referencesets.get": get_reference_set
|
||||
"/genomics:v1beta2/genomics.streamingReadstore.streamreads": stream_reads
|
||||
"/gmail:v1/gmail.users.getProfile": get_user_profile
|
||||
"/identitytoolkit:v3/IdentitytoolkitRelyingpartyCreateAuthUriRequest": create_auth_uri_request
|
||||
"/identitytoolkit:v3/IdentitytoolkitRelyingpartyDeleteAccountRequest": delete_account_request
|
||||
"/identitytoolkit:v3/IdentitytoolkitRelyingpartyDownloadAccountRequest": download_account_request
|
||||
"/identitytoolkit:v3/IdentitytoolkitRelyingpartyGetAccountInfoRequest": get_account_info_request
|
||||
"/identitytoolkit:v3/IdentitytoolkitRelyingpartyGetPublicKeysResponse": get_public_keys_response
|
||||
"/identitytoolkit:v3/IdentitytoolkitRelyingpartyGetPublicKeysResponse/get_public_keys_response": get_public_keys_response
|
||||
"/identitytoolkit:v3/IdentitytoolkitRelyingpartyResetPasswordRequest": reset_password_request
|
||||
"/identitytoolkit:v3/IdentitytoolkitRelyingpartySetAccountInfoRequest": set_account_info_request
|
||||
"/identitytoolkit:v3/IdentitytoolkitRelyingpartyUploadAccountRequest": upload_account_request
|
||||
"/identitytoolkit:v3/IdentitytoolkitRelyingpartyVerifyAssertionRequest": verify_assertion_request
|
||||
"/identitytoolkit:v3/IdentitytoolkitRelyingpartyVerifyPasswordRequest": verify_password_request
|
||||
"/identitytoolkit:v3/identitytoolkit.relyingparty.createAuthUri": create_auth_uri
|
||||
"/identitytoolkit:v3/identitytoolkit.relyingparty.deleteAccount": delete_account
|
||||
"/identitytoolkit:v3/identitytoolkit.relyingparty.downloadAccount": download_account
|
||||
"/identitytoolkit:v3/identitytoolkit.relyingparty.getAccountInfo": get_account_info
|
||||
"/identitytoolkit:v3/identitytoolkit.relyingparty.getOobConfirmationCode": get_oob_confirmation_code
|
||||
"/identitytoolkit:v3/identitytoolkit.relyingparty.getPublicKeys": get_public_keys
|
||||
"/identitytoolkit:v3/identitytoolkit.relyingparty.getRecaptchaParam": get_recaptcha_param
|
||||
"/identitytoolkit:v3/identitytoolkit.relyingparty.resetPassword": reset_password
|
||||
"/identitytoolkit:v3/identitytoolkit.relyingparty.setAccountInfo": set_account_info
|
||||
"/identitytoolkit:v3/identitytoolkit.relyingparty.uploadAccount": upload_account
|
||||
"/identitytoolkit:v3/identitytoolkit.relyingparty.verifyAssertion": verify_assertion
|
||||
"/identitytoolkit:v3/identitytoolkit.relyingparty.verifyPassword": verify_password
|
||||
"/licensing:v1/licensing.licenseAssignments.listForProduct": list_license_assignment_for_product
|
||||
"/licensing:v1/licensing.licenseAssignments.listForProductAndSku": list_license_assignment_for_product_and_sku
|
||||
"/logging:v1beta3/logging.projects.logServices.indexes.list": list_log_service_indexes
|
||||
"/logging:v1beta3/logging.projects.logServices.list": list_log_services
|
||||
"/logging:v1beta3/logging.projects.logServices.sinks.create": create_log_service_sink
|
||||
"/logging:v1beta3/logging.projects.logServices.sinks.delete": delete_log_service_sink
|
||||
"/logging:v1beta3/logging.projects.logServices.sinks.get": get_log_service_sink
|
||||
"/logging:v1beta3/logging.projects.logServices.sinks.list": list_log_service_sinks
|
||||
"/logging:v1beta3/logging.projects.logServices.sinks.update": update_log_service_sink
|
||||
"/logging:v1beta3/logging.projects.logs.delete": delete_log
|
||||
"/logging:v1beta3/logging.projects.logs.list": list_logs
|
||||
"/logging:v1beta3/logging.projects.logs.sinks.create": create_log_sink
|
||||
"/logging:v1beta3/logging.projects.logs.sinks.delete": delete_log_sink
|
||||
"/logging:v1beta3/logging.projects.logs.sinks.get": get_log_sink
|
||||
"/logging:v1beta3/logging.projects.logs.sinks.list": list_log_sinks
|
||||
"/logging:v1beta3/logging.projects.logs.sinks.update": update_log_sink
|
||||
"/manager:v1beta2/DeploymentsListResponse": list_deployments_response
|
||||
"/manager:v1beta2/TemplatesListResponse": list_templates_response
|
||||
"/mapsengine:v1/AssetsListResponse": list_assets_response
|
||||
"/mapsengine:v1/FeaturesBatchDeleteRequest": batch_delete_features_request
|
||||
"/mapsengine:v1/FeaturesBatchInsertRequest": batch_insert_features_request
|
||||
"/mapsengine:v1/FeaturesBatchPatchRequest": batch_patch_features_request
|
||||
"/mapsengine:v1/FeaturesListResponse": list_features_response
|
||||
"/mapsengine:v1/IconsListResponse": list_icons_response
|
||||
"/mapsengine:v1/LayersListResponse": list_layers_response
|
||||
"/mapsengine:v1/MapsListResponse": list_maps_response
|
||||
"/mapsengine:v1/ParentsListResponse": list_parents_response
|
||||
"/mapsengine:v1/PermissionsBatchDeleteRequest": batch_delete_permissions_request
|
||||
"/mapsengine:v1/PermissionsBatchDeleteResponse": batch_delete_permissions_response
|
||||
"/mapsengine:v1/PermissionsBatchUpdateRequest": batch_update_permissions_request
|
||||
"/mapsengine:v1/PermissionsBatchUpdateResponse": batch_update_permissions_response
|
||||
"/mapsengine:v1/PermissionsListResponse": list_permissions_response
|
||||
"/mapsengine:v1/ProjectsListResponse": list_projects_response
|
||||
"/mapsengine:v1/PublishedLayersListResponse": list_published_layers_response
|
||||
"/mapsengine:v1/PublishedMapsListResponse": list_published_maps_response
|
||||
"/mapsengine:v1/RasterCollectionsListResponse": list_raster_collections_response
|
||||
"/mapsengine:v1/RasterCollectionsRasterBatchDeleteRequest": batch_delete_raster_collections_raster_request
|
||||
"/mapsengine:v1/RasterCollectionsRastersBatchDeleteResponse": batch_delete_raster_collections_rasters_response
|
||||
"/mapsengine:v1/RasterCollectionsRastersBatchInsertRequest": batch_insert_raster_collections_rasters_request
|
||||
"/mapsengine:v1/RasterCollectionsRastersBatchInsertResponse": batch_insert_raster_collections_rasters_response
|
||||
"/mapsengine:v1/RasterCollectionsRastersListResponse": list_raster_collections_rasters_response
|
||||
"/mapsengine:v1/RastersListResponse": list_rasters_response
|
||||
"/mapsengine:v1/TablesListResponse": list_tables_response
|
||||
"/mirror:v1/AttachmentsListResponse": list_attachments_response
|
||||
"/mirror:v1/ContactsListResponse": list_contacts_response
|
||||
"/mirror:v1/LocationsListResponse": list_locations_response
|
||||
"/mirror:v1/SubscriptionsListResponse": list_subscriptions_response
|
||||
"/mirror:v1/TimelineListResponse": list_timeline_response
|
||||
"/oauth2:v2/oauth2.userinfo.v2.me.get": get_userinfo_v2
|
||||
"/pagespeedonline:v2/PagespeedApiFormatStringV2": format_string
|
||||
"/pagespeedonline:v2/PagespeedApiImageV2": image
|
||||
"/pagespeedonline:v2/pagespeedonline.pagespeedapi.runpagespeed": run_pagespeed
|
||||
"/plus:v1/plus.people.listByActivity": list_people_by_activity
|
||||
"/plusDomains:v1/plusDomains.circles.addPeople": add_people
|
||||
"/plusDomains:v1/plusDomains.circles.removePeople": remove_people
|
||||
"/plusDomains:v1/plusDomains.people.listByActivity": list_people_by_activity
|
||||
"/plusDomains:v1/plusDomains.people.listByCircle": list_people_by_circle
|
||||
"/prediction:v1.6/prediction.hostedmodels.predict": predict_hosted_model
|
||||
"/prediction:v1.6/prediction.trainedmodels.analyze": analyze_trained_model
|
||||
"/prediction:v1.6/prediction.trainedmodels.delete": delete_trained_model
|
||||
"/prediction:v1.6/prediction.trainedmodels.get": get_trained_model
|
||||
"/prediction:v1.6/prediction.trainedmodels.insert": insert_trained_model
|
||||
"/prediction:v1.6/prediction.trainedmodels.list": list_trained_models
|
||||
"/prediction:v1.6/prediction.trainedmodels.predict": predict_trained_model
|
||||
"/prediction:v1.6/prediction.trainedmodels.update": update_trained_model
|
||||
"/pubsub:v1beta2/PubsubMessage": message
|
||||
"/pubsub:v1beta2/pubsub.projects.subscriptions.create": create_subscription
|
||||
"/pubsub:v1beta2/pubsub.projects.subscriptions.delete": delete_subscription
|
||||
"/pubsub:v1beta2/pubsub.projects.subscriptions.get": get_subscription
|
||||
"/pubsub:v1beta2/pubsub.projects.subscriptions.list": list_subscriptions
|
||||
"/pubsub:v1beta2/pubsub.projects.subscriptions.setIamPolicy": set_subscription_policy
|
||||
"/pubsub:v1beta2/pubsub.projects.subscriptions.testIamPermissions": test_subscription_permissions
|
||||
"/pubsub:v1beta2/pubsub.projects.topics.create": create_topic
|
||||
"/pubsub:v1beta2/pubsub.projects.topics.delete": delete_topic
|
||||
"/pubsub:v1beta2/pubsub.projects.topics.get": get_topic
|
||||
"/pubsub:v1beta2/pubsub.projects.topics.list": list_topics
|
||||
"/pubsub:v1beta2/pubsub.projects.topics.setIamPolicy": set_topic_policy
|
||||
"/pubsub:v1beta2/pubsub.projects.topics.testIamPermissions": test_topic_permissions
|
||||
"/pubsub:v1beta2/pubsub.projects.topics.subscriptions.list": list_topic_subscriptions
|
||||
"/qpxExpress:v1/TripsSearchRequest": search_trips_request
|
||||
"/qpxExpress:v1/TripsSearchResponse": search_trips_response
|
||||
"/replicapool:v1beta2/InstanceGroupManagersAbandonInstancesRequest": abandon_instances_request
|
||||
"/replicapool:v1beta2/InstanceGroupManagersDeleteInstancesRequest": delete_instances_request
|
||||
"/replicapool:v1beta2/InstanceGroupManagersRecreateInstancesRequest": recreate_instances_request
|
||||
"/replicapool:v1beta2/InstanceGroupManagersSetInstanceTemplateRequest": set_instance_template_request
|
||||
"/replicapool:v1beta2/InstanceGroupManagersSetTargetPoolsRequest": set_target_pools_request
|
||||
"/replicapool:v1beta2/replicapool.instanceGroupManagers.abandonInstances": abandon_instances
|
||||
"/replicapool:v1beta2/replicapool.instanceGroupManagers.deleteInstances": delete_instances
|
||||
"/replicapool:v1beta2/replicapool.instanceGroupManagers.recreateInstances": recreate_instances
|
||||
"/replicapool:v1beta2/replicapool.instanceGroupManagers.resize": resize_instance
|
||||
"/replicapool:v1beta2/replicapool.instanceGroupManagers.setInstanceTemplate": set_instance_template
|
||||
"/replicapool:v1beta2/replicapool.instanceGroupManagers.setTargetPools": set_target_pools
|
||||
"/replicapoolupdater:v1beta1/replicapoolupdater.rollingUpdates.listInstanceUpdates": list_instance_updates
|
||||
"/reseller:v1/ChangePlanRequest": change_plan_request
|
||||
"/reseller:v1/reseller.subscriptions.changeRenewalSettings": change_subscription_renewal_settings
|
||||
"/reseller:v1/reseller.subscriptions.changeSeats": change_subscription_seats
|
||||
"/resourceviews:v1beta2/ZoneViewsAddResourcesRequest": add_resources_request
|
||||
"/resourceviews:v1beta2/ZoneViewsGetServiceResponse": get_service_response
|
||||
"/resourceviews:v1beta2/ZoneViewsListResourcesResponse": list_resources_response
|
||||
"/resourceviews:v1beta2/ZoneViewsRemoveResourcesRequest": remove_resources_request
|
||||
"/resourceviews:v1beta2/ZoneViewsSetServiceRequest": set_service_request
|
||||
"/siteVerification:v1/SiteVerificationWebResourceGettokenRequest": get_web_resource_token_request
|
||||
"/siteVerification:v1/SiteVerificationWebResourceGettokenResponse": get_web_resource_token_response
|
||||
"/siteVerification:v1/SiteVerificationWebResourceGettokenResponse/method": verification_method
|
||||
"/siteVerification:v1/SiteVerificationWebResourceListResponse": list_web_resource_response
|
||||
"/sqladmin:v1beta4/BackupRunsListResponse": list_backup_runs_response
|
||||
"/sqladmin:v1beta4/DatabasesListResponse": list_databases_response
|
||||
"/sqladmin:v1beta4/FlagsListResponse": list_flags_response
|
||||
"/sqladmin:v1beta4/InstancesCloneRequest": clone_instances_request
|
||||
"/sqladmin:v1beta4/InstancesExportRequest": export_instances_request
|
||||
"/sqladmin:v1beta4/InstancesImportRequest": import_instances_request
|
||||
"/sqladmin:v1beta4/InstancesListResponse": list_instances_response
|
||||
"/sqladmin:v1beta4/InstancesRestoreBackupRequest": restore_instances_backup_request
|
||||
"/sqladmin:v1beta4/OperationsListResponse": list_operations_response
|
||||
"/sqladmin:v1beta4/SslCertsInsertRequest": insert_ssl_certs_request
|
||||
"/sqladmin:v1beta4/SslCertsInsertResponse": insert_ssl_certs_response
|
||||
"/sqladmin:v1beta4/SslCertsListResponse": list_ssl_certs_response
|
||||
"/sqladmin:v1beta4/TiersListResponse": list_tiers_response
|
||||
"/sqladmin:v1beta4/UsersListResponse": list_users_response
|
||||
"/storage:v1/Bucket/cors": cors_configurations
|
||||
"/storage:v1/Bucket/cors/cors_configuration/method": http_method
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.create": create_container
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.delete": delete_container
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.get": get_container
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.list": list_containers
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.macros.create": create_macro
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.macros.delete": delete_macro
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.macros.get": get_macro
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.macros.list": list_macros
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.macros.update": update_macro
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.rules.create": create_rule
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.rules.delete": delete_rule
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.rules.get": get_rule
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.rules.list": list_rules
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.rules.update": update_rule
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.tags.create": create_tag
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.tags.delete": delete_tag
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.tags.get": get_tag
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.tags.list": list_tags
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.tags.update": update_tag
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.triggers.create": create_trigger
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.triggers.delete": delete_trigger
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.triggers.get": get_trigger
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.triggers.list": list_triggers
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.triggers.update": update_trigger
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.update": update_container
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.variables.create": create_variable
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.variables.delete": delete_variable
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.variables.get": get_variable
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.variables.list": list_variables
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.variables.update": update_variable
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.versions.create": create_version
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.versions.delete": delete_version
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.versions.get": get_version
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.versions.list": list_versions
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.versions.publish": publish_version
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.versions.restore": restore_version
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.versions.undelete": undelete_version
|
||||
"/tagmanager:v1/tagmanager.accounts.containers.versions.update": update_version
|
||||
"/tagmanager:v1/tagmanager.accounts.get": get_account
|
||||
"/tagmanager:v1/tagmanager.accounts.list": list_accounts
|
||||
"/tagmanager:v1/tagmanager.accounts.permissions.create": create_permission
|
||||
"/tagmanager:v1/tagmanager.accounts.permissions.delete": delete_permission
|
||||
"/tagmanager:v1/tagmanager.accounts.permissions.get": get_permission
|
||||
"/tagmanager:v1/tagmanager.accounts.permissions.list": list_permissions
|
||||
"/tagmanager:v1/tagmanager.accounts.permissions.update": update_permission
|
||||
"/tagmanager:v1/tagmanager.accounts.update": update_account
|
||||
"/translate:v2/DetectionsListResponse": list_detections_response
|
||||
"/translate:v2/LanguagesListResponse": list_languages_response
|
||||
"/translate:v2/TranslationsListResponse": list_translations_response
|
||||
"/webmasters:v3/SitemapsListResponse": list_sitemaps_response
|
||||
"/webmasters:v3/SitesListResponse": list_sites_response
|
||||
"/webmasters:v3/UrlCrawlErrorsCountsQueryResponse": query_url_crawl_errors_counts_response
|
||||
"/webmasters:v3/UrlCrawlErrorsSamplesListResponse": list_url_crawl_errors_samples_response
|
||||
"/webmasters:v3/webmasters.urlcrawlerrorscounts.query": query_errors_count
|
||||
"/webmasters:v3/webmasters.urlcrawlerrorssamples.get": get_errors_sample
|
||||
"/webmasters:v3/webmasters.urlcrawlerrorssamples.list": list_errors_samples
|
||||
"/webmasters:v3/webmasters.urlcrawlerrorssamples.markAsFixed": mark_as_fixed
|
||||
"/youtube:v3/youtube.comments.setModerationStatus": set_comment_moderation_status
|
||||
"/youtube:v3/ActivityListResponse": list_activities_response
|
||||
"/youtube:v3/CaptionListResponse": list_captions_response
|
||||
"/youtube:v3/ChannelListResponse": list_channels_response
|
||||
"/youtube:v3/ChannelSectionListResponse": list_channel_sections_response
|
||||
"/youtube:v3/CommentListResponse": list_comments_response
|
||||
"/youtube:v3/CommentThreadListResponse": list_comment_threads_response
|
||||
"/youtube:v3/GuideCategoryListResponse": list_guide_categories_response
|
||||
"/youtube:v3/I18nLanguageListResponse": list_i18n_languages_response
|
||||
"/youtube:v3/I18nRegionListResponse": list_i18n_regions_response
|
||||
"/youtube:v3/LiveBroadcastListResponse": list_live_broadcasts_response
|
||||
"/youtube:v3/LiveStreamListResponse": list_live_streams_response
|
||||
"/youtube:v3/PlaylistItemListResponse": list_playlist_items_response
|
||||
"/youtube:v3/PlaylistListResponse": list_playlist_response
|
||||
"/youtube:v3/SearchListResponse": search_lists_response
|
||||
"/youtube:v3/SubscriptionListResponse": list_subscription_response
|
||||
"/youtube:v3/ThumbnailSetResponse": set_thumbnail_response
|
||||
"/youtube:v3/VideoAbuseReportReasonListResponse": list_video_abuse_report_reason_response
|
||||
"/youtube:v3/VideoCategoryListResponse": list_video_category_response
|
||||
"/youtube:v3/VideoGetRatingResponse": get_video_rating_response
|
||||
"/youtube:v3/VideoListResponse": list_videos_response
|
||||
"/youtubeAnalytics:v1/GroupItemListResponse": list_group_item_response
|
||||
"/youtubeAnalytics:v1/GroupListResponse": list_groups_response
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,93 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
# TODO - Repeated params
|
||||
|
||||
require 'thor'
|
||||
require 'open-uri'
|
||||
require 'google/apis/discovery_v1'
|
||||
require 'google/apis/generator'
|
||||
require 'multi_json'
|
||||
require 'logger'
|
||||
|
||||
module Google
|
||||
class ApiGenerator < Thor
|
||||
include Thor::Actions
|
||||
|
||||
Google::Apis::ClientOptions.default.application_name = "generate-api"
|
||||
Google::Apis::ClientOptions.default.application_version = Google::Apis::VERSION
|
||||
|
||||
Discovery = Google::Apis::DiscoveryV1
|
||||
|
||||
desc 'gen OUTDIR', 'Generate ruby API from an API description'
|
||||
method_options url: :string, file: :string, id: :array, preferred_only: :boolean, verbose: :boolean, names: :string, names_out: :string
|
||||
method_option :preferred_only, default: true
|
||||
def gen(dir)
|
||||
self.destination_root = dir
|
||||
Google::Apis.logger.level = Logger::DEBUG if options[:verbose]
|
||||
if options[:url]
|
||||
generate_from_url(options[:url])
|
||||
elsif options[:file]
|
||||
generate_from_file(options[:file])
|
||||
else
|
||||
generate_from_discovery(preferred_only: options[:preferred_only], id: options[:id] )
|
||||
end
|
||||
create_file(options[:names_out]) { |*| generator.dump_api_names } if options[:names_out]
|
||||
end
|
||||
|
||||
desc 'list', 'List public APIs'
|
||||
method_options verbose: :boolean, preferred_only: :boolean
|
||||
def list
|
||||
Google::Apis.logger.level = Logger::DEBUG if options[:verbose]
|
||||
discovery = Discovery::DiscoveryService.new
|
||||
apis = discovery.list_apis
|
||||
apis.items.each do |api|
|
||||
say sprintf('%s - %s', api.id, api.description).strip unless options[:preferred_only] && !api.preferred?
|
||||
end
|
||||
end
|
||||
|
||||
no_commands do
|
||||
def generate_from_url(url)
|
||||
json = discovery.http(:get, url)
|
||||
generate_api(json)
|
||||
end
|
||||
|
||||
def generate_from_file(file)
|
||||
File.open(file) do |f|
|
||||
generate_api(f.read)
|
||||
end
|
||||
end
|
||||
|
||||
def generate_from_discovery(preferred_only: false, id: nil)
|
||||
say 'Fetching API list'
|
||||
id = Array(id)
|
||||
apis = discovery.list_apis
|
||||
apis.items.each do |api|
|
||||
if (id.empty? && preferred_only && api.preferred?) || id.include?(api.id)
|
||||
say sprintf('Loading %s, version %s from %s', api.name, api.version, api.discovery_rest_url)
|
||||
generate_from_url(api.discovery_rest_url)
|
||||
else
|
||||
say sprintf('Ignoring disoverable API %s', api.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def generate_api(json)
|
||||
files = generator.render(json)
|
||||
files.each do |file, content|
|
||||
create_file(file) { |*| content }
|
||||
end
|
||||
end
|
||||
|
||||
def discovery
|
||||
@discovery ||= Discovery::DiscoveryService.new
|
||||
end
|
||||
|
||||
def generator
|
||||
@generator ||= Google::Apis::Generator.new(api_names: options[:names])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Google::ApiGenerator.start(ARGV)
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2013 Google Inc.
|
||||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -12,17 +12,21 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'faraday'
|
||||
require 'signet/oauth_2/client'
|
||||
require 'google/apis/discovery_v1/service.rb'
|
||||
require 'google/apis/discovery_v1/classes.rb'
|
||||
require 'google/apis/discovery_v1/representations.rb'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
class ComputeServiceAccount < Signet::OAuth2::Client
|
||||
def fetch_access_token(options={})
|
||||
connection = options[:connection] || Faraday.default_connection
|
||||
response = connection.get 'http://metadata/computeMetadata/v1beta1/instance/service-accounts/default/token'
|
||||
Signet::OAuth2.parse_credentials(response.body, response.headers['content-type'])
|
||||
end
|
||||
module Apis
|
||||
# APIs Discovery Service
|
||||
#
|
||||
# Lets you discover information about other Google APIs, such as what APIs are
|
||||
# available, the resource and method details for each API.
|
||||
#
|
||||
# @see https://developers.google.com/discovery/
|
||||
module DiscoveryV1
|
||||
VERSION = 'V1'
|
||||
REVISION = ''
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,947 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'date'
|
||||
require 'google/apis/core/base_service'
|
||||
require 'google/apis/core/json_representation'
|
||||
require 'google/apis/core/hashable'
|
||||
require 'google/apis/errors'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
module DiscoveryV1
|
||||
|
||||
#
|
||||
class DirectoryList
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# Indicate the version of the Discovery API used to generate this doc.
|
||||
# Corresponds to the JSON property `discoveryVersion`
|
||||
# @return [String]
|
||||
attr_accessor :discovery_version
|
||||
|
||||
# The individual directory entries. One entry per api/version pair.
|
||||
# Corresponds to the JSON property `items`
|
||||
# @return [Array<Google::Apis::DiscoveryV1::DirectoryList::Item>]
|
||||
attr_accessor :items
|
||||
|
||||
# The kind for this response.
|
||||
# Corresponds to the JSON property `kind`
|
||||
# @return [String]
|
||||
attr_accessor :kind
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@discovery_version = args[:discovery_version] unless args[:discovery_version].nil?
|
||||
@items = args[:items] unless args[:items].nil?
|
||||
@kind = args[:kind] unless args[:kind].nil?
|
||||
end
|
||||
|
||||
#
|
||||
class Item
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# The description of this API.
|
||||
# Corresponds to the JSON property `description`
|
||||
# @return [String]
|
||||
attr_accessor :description
|
||||
|
||||
# A link to the discovery document.
|
||||
# Corresponds to the JSON property `discoveryLink`
|
||||
# @return [String]
|
||||
attr_accessor :discovery_link
|
||||
|
||||
# The URL for the discovery REST document.
|
||||
# Corresponds to the JSON property `discoveryRestUrl`
|
||||
# @return [String]
|
||||
attr_accessor :discovery_rest_url
|
||||
|
||||
# A link to human readable documentation for the API.
|
||||
# Corresponds to the JSON property `documentationLink`
|
||||
# @return [String]
|
||||
attr_accessor :documentation_link
|
||||
|
||||
# Links to 16x16 and 32x32 icons representing the API.
|
||||
# Corresponds to the JSON property `icons`
|
||||
# @return [Google::Apis::DiscoveryV1::DirectoryList::Item::Icons]
|
||||
attr_accessor :icons
|
||||
|
||||
# The id of this API.
|
||||
# Corresponds to the JSON property `id`
|
||||
# @return [String]
|
||||
attr_accessor :id
|
||||
|
||||
# The kind for this response.
|
||||
# Corresponds to the JSON property `kind`
|
||||
# @return [String]
|
||||
attr_accessor :kind
|
||||
|
||||
# Labels for the status of this API, such as labs or deprecated.
|
||||
# Corresponds to the JSON property `labels`
|
||||
# @return [Array<String>]
|
||||
attr_accessor :labels
|
||||
|
||||
# The name of the API.
|
||||
# Corresponds to the JSON property `name`
|
||||
# @return [String]
|
||||
attr_accessor :name
|
||||
|
||||
# True if this version is the preferred version to use.
|
||||
# Corresponds to the JSON property `preferred`
|
||||
# @return [Boolean]
|
||||
attr_accessor :preferred
|
||||
alias_method :preferred?, :preferred
|
||||
|
||||
# The title of this API.
|
||||
# Corresponds to the JSON property `title`
|
||||
# @return [String]
|
||||
attr_accessor :title
|
||||
|
||||
# The version of the API.
|
||||
# Corresponds to the JSON property `version`
|
||||
# @return [String]
|
||||
attr_accessor :version
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@description = args[:description] unless args[:description].nil?
|
||||
@discovery_link = args[:discovery_link] unless args[:discovery_link].nil?
|
||||
@discovery_rest_url = args[:discovery_rest_url] unless args[:discovery_rest_url].nil?
|
||||
@documentation_link = args[:documentation_link] unless args[:documentation_link].nil?
|
||||
@icons = args[:icons] unless args[:icons].nil?
|
||||
@id = args[:id] unless args[:id].nil?
|
||||
@kind = args[:kind] unless args[:kind].nil?
|
||||
@labels = args[:labels] unless args[:labels].nil?
|
||||
@name = args[:name] unless args[:name].nil?
|
||||
@preferred = args[:preferred] unless args[:preferred].nil?
|
||||
@title = args[:title] unless args[:title].nil?
|
||||
@version = args[:version] unless args[:version].nil?
|
||||
end
|
||||
|
||||
# Links to 16x16 and 32x32 icons representing the API.
|
||||
class Icons
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# The URL of the 16x16 icon.
|
||||
# Corresponds to the JSON property `x16`
|
||||
# @return [String]
|
||||
attr_accessor :x16
|
||||
|
||||
# The URL of the 32x32 icon.
|
||||
# Corresponds to the JSON property `x32`
|
||||
# @return [String]
|
||||
attr_accessor :x32
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@x16 = args[:x16] unless args[:x16].nil?
|
||||
@x32 = args[:x32] unless args[:x32].nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
class JsonSchema
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# A reference to another schema. The value of this property is the "id" of
|
||||
# another schema.
|
||||
# Corresponds to the JSON property `$ref`
|
||||
# @return [String]
|
||||
attr_accessor :_ref
|
||||
|
||||
# If this is a schema for an object, this property is the schema for any
|
||||
# additional properties with dynamic keys on this object.
|
||||
# Corresponds to the JSON property `additionalProperties`
|
||||
# @return [Google::Apis::DiscoveryV1::JsonSchema]
|
||||
attr_accessor :additional_properties
|
||||
|
||||
# Additional information about this property.
|
||||
# Corresponds to the JSON property `annotations`
|
||||
# @return [Google::Apis::DiscoveryV1::JsonSchema::Annotations]
|
||||
attr_accessor :annotations
|
||||
|
||||
# The default value of this property (if one exists).
|
||||
# Corresponds to the JSON property `default`
|
||||
# @return [String]
|
||||
attr_accessor :default
|
||||
|
||||
# A description of this object.
|
||||
# Corresponds to the JSON property `description`
|
||||
# @return [String]
|
||||
attr_accessor :description
|
||||
|
||||
# Values this parameter may take (if it is an enum).
|
||||
# Corresponds to the JSON property `enum`
|
||||
# @return [Array<String>]
|
||||
attr_accessor :enum
|
||||
|
||||
# The descriptions for the enums. Each position maps to the corresponding value
|
||||
# in the "enum" array.
|
||||
# Corresponds to the JSON property `enumDescriptions`
|
||||
# @return [Array<String>]
|
||||
attr_accessor :enum_descriptions
|
||||
|
||||
# An additional regular expression or key that helps constrain the value. For
|
||||
# more details see: http://tools.ietf.org/html/draft-zyp-json-schema-03#section-
|
||||
# 5.23
|
||||
# Corresponds to the JSON property `format`
|
||||
# @return [String]
|
||||
attr_accessor :format
|
||||
|
||||
# Unique identifier for this schema.
|
||||
# Corresponds to the JSON property `id`
|
||||
# @return [String]
|
||||
attr_accessor :id
|
||||
|
||||
# If this is a schema for an array, this property is the schema for each element
|
||||
# in the array.
|
||||
# Corresponds to the JSON property `items`
|
||||
# @return [Google::Apis::DiscoveryV1::JsonSchema]
|
||||
attr_accessor :items
|
||||
|
||||
# Whether this parameter goes in the query or the path for REST requests.
|
||||
# Corresponds to the JSON property `location`
|
||||
# @return [String]
|
||||
attr_accessor :location
|
||||
|
||||
# The maximum value of this parameter.
|
||||
# Corresponds to the JSON property `maximum`
|
||||
# @return [String]
|
||||
attr_accessor :maximum
|
||||
|
||||
# The minimum value of this parameter.
|
||||
# Corresponds to the JSON property `minimum`
|
||||
# @return [String]
|
||||
attr_accessor :minimum
|
||||
|
||||
# The regular expression this parameter must conform to. Uses Java 6 regex
|
||||
# format: http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html
|
||||
# Corresponds to the JSON property `pattern`
|
||||
# @return [String]
|
||||
attr_accessor :pattern
|
||||
|
||||
# If this is a schema for an object, list the schema for each property of this
|
||||
# object.
|
||||
# Corresponds to the JSON property `properties`
|
||||
# @return [Hash<String,Google::Apis::DiscoveryV1::JsonSchema>]
|
||||
attr_accessor :properties
|
||||
|
||||
# The value is read-only, generated by the service. The value cannot be modified
|
||||
# by the client. If the value is included in a POST, PUT, or PATCH request, it
|
||||
# is ignored by the service.
|
||||
# Corresponds to the JSON property `readOnly`
|
||||
# @return [Boolean]
|
||||
attr_accessor :read_only
|
||||
alias_method :read_only?, :read_only
|
||||
|
||||
# Whether this parameter may appear multiple times.
|
||||
# Corresponds to the JSON property `repeated`
|
||||
# @return [Boolean]
|
||||
attr_accessor :repeated
|
||||
alias_method :repeated?, :repeated
|
||||
|
||||
# Whether the parameter is required.
|
||||
# Corresponds to the JSON property `required`
|
||||
# @return [Boolean]
|
||||
attr_accessor :required
|
||||
alias_method :required?, :required
|
||||
|
||||
# The value type for this schema. A list of values can be found here: http://
|
||||
# tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1
|
||||
# Corresponds to the JSON property `type`
|
||||
# @return [String]
|
||||
attr_accessor :type
|
||||
|
||||
# In a variant data type, the value of one property is used to determine how to
|
||||
# interpret the entire entity. Its value must exist in a map of descriminant
|
||||
# values to schema names.
|
||||
# Corresponds to the JSON property `variant`
|
||||
# @return [Google::Apis::DiscoveryV1::JsonSchema::Variant]
|
||||
attr_accessor :variant
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@_ref = args[:_ref] unless args[:_ref].nil?
|
||||
@additional_properties = args[:additional_properties] unless args[:additional_properties].nil?
|
||||
@annotations = args[:annotations] unless args[:annotations].nil?
|
||||
@default = args[:default] unless args[:default].nil?
|
||||
@description = args[:description] unless args[:description].nil?
|
||||
@enum = args[:enum] unless args[:enum].nil?
|
||||
@enum_descriptions = args[:enum_descriptions] unless args[:enum_descriptions].nil?
|
||||
@format = args[:format] unless args[:format].nil?
|
||||
@id = args[:id] unless args[:id].nil?
|
||||
@items = args[:items] unless args[:items].nil?
|
||||
@location = args[:location] unless args[:location].nil?
|
||||
@maximum = args[:maximum] unless args[:maximum].nil?
|
||||
@minimum = args[:minimum] unless args[:minimum].nil?
|
||||
@pattern = args[:pattern] unless args[:pattern].nil?
|
||||
@properties = args[:properties] unless args[:properties].nil?
|
||||
@read_only = args[:read_only] unless args[:read_only].nil?
|
||||
@repeated = args[:repeated] unless args[:repeated].nil?
|
||||
@required = args[:required] unless args[:required].nil?
|
||||
@type = args[:type] unless args[:type].nil?
|
||||
@variant = args[:variant] unless args[:variant].nil?
|
||||
end
|
||||
|
||||
# Additional information about this property.
|
||||
class Annotations
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# A list of methods for which this property is required on requests.
|
||||
# Corresponds to the JSON property `required`
|
||||
# @return [Array<String>]
|
||||
attr_accessor :required
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@required = args[:required] unless args[:required].nil?
|
||||
end
|
||||
end
|
||||
|
||||
# In a variant data type, the value of one property is used to determine how to
|
||||
# interpret the entire entity. Its value must exist in a map of descriminant
|
||||
# values to schema names.
|
||||
class Variant
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# The name of the type discriminant property.
|
||||
# Corresponds to the JSON property `discriminant`
|
||||
# @return [String]
|
||||
attr_accessor :discriminant
|
||||
|
||||
# The map of discriminant value to schema to use for parsing..
|
||||
# Corresponds to the JSON property `map`
|
||||
# @return [Array<Google::Apis::DiscoveryV1::JsonSchema::Variant::Map>]
|
||||
attr_accessor :map
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@discriminant = args[:discriminant] unless args[:discriminant].nil?
|
||||
@map = args[:map] unless args[:map].nil?
|
||||
end
|
||||
|
||||
#
|
||||
class Map
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
#
|
||||
# Corresponds to the JSON property `$ref`
|
||||
# @return [String]
|
||||
attr_accessor :_ref
|
||||
|
||||
#
|
||||
# Corresponds to the JSON property `type_value`
|
||||
# @return [String]
|
||||
attr_accessor :type_value
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@_ref = args[:_ref] unless args[:_ref].nil?
|
||||
@type_value = args[:type_value] unless args[:type_value].nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
class RestDescription
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# Authentication information.
|
||||
# Corresponds to the JSON property `auth`
|
||||
# @return [Google::Apis::DiscoveryV1::RestDescription::Auth]
|
||||
attr_accessor :auth
|
||||
|
||||
# [DEPRECATED] The base path for REST requests.
|
||||
# Corresponds to the JSON property `basePath`
|
||||
# @return [String]
|
||||
attr_accessor :base_path
|
||||
|
||||
# [DEPRECATED] The base URL for REST requests.
|
||||
# Corresponds to the JSON property `baseUrl`
|
||||
# @return [String]
|
||||
attr_accessor :base_url
|
||||
|
||||
# The path for REST batch requests.
|
||||
# Corresponds to the JSON property `batchPath`
|
||||
# @return [String]
|
||||
attr_accessor :batch_path
|
||||
|
||||
# Indicates how the API name should be capitalized and split into various parts.
|
||||
# Useful for generating pretty class names.
|
||||
# Corresponds to the JSON property `canonicalName`
|
||||
# @return [String]
|
||||
attr_accessor :canonical_name
|
||||
|
||||
# The description of this API.
|
||||
# Corresponds to the JSON property `description`
|
||||
# @return [String]
|
||||
attr_accessor :description
|
||||
|
||||
# Indicate the version of the Discovery API used to generate this doc.
|
||||
# Corresponds to the JSON property `discoveryVersion`
|
||||
# @return [String]
|
||||
attr_accessor :discovery_version
|
||||
|
||||
# A link to human readable documentation for the API.
|
||||
# Corresponds to the JSON property `documentationLink`
|
||||
# @return [String]
|
||||
attr_accessor :documentation_link
|
||||
|
||||
# The ETag for this response.
|
||||
# Corresponds to the JSON property `etag`
|
||||
# @return [String]
|
||||
attr_accessor :etag
|
||||
|
||||
# A list of supported features for this API.
|
||||
# Corresponds to the JSON property `features`
|
||||
# @return [Array<String>]
|
||||
attr_accessor :features
|
||||
|
||||
# Links to 16x16 and 32x32 icons representing the API.
|
||||
# Corresponds to the JSON property `icons`
|
||||
# @return [Google::Apis::DiscoveryV1::RestDescription::Icons]
|
||||
attr_accessor :icons
|
||||
|
||||
# The ID of this API.
|
||||
# Corresponds to the JSON property `id`
|
||||
# @return [String]
|
||||
attr_accessor :id
|
||||
|
||||
# The kind for this response.
|
||||
# Corresponds to the JSON property `kind`
|
||||
# @return [String]
|
||||
attr_accessor :kind
|
||||
|
||||
# Labels for the status of this API, such as labs or deprecated.
|
||||
# Corresponds to the JSON property `labels`
|
||||
# @return [Array<String>]
|
||||
attr_accessor :labels
|
||||
|
||||
# API-level methods for this API.
|
||||
# Corresponds to the JSON property `methods`
|
||||
# @return [Hash<String,Google::Apis::DiscoveryV1::RestMethod>]
|
||||
attr_accessor :api_methods
|
||||
|
||||
# The name of this API.
|
||||
# Corresponds to the JSON property `name`
|
||||
# @return [String]
|
||||
attr_accessor :name
|
||||
|
||||
# The domain of the owner of this API. Together with the ownerName and a
|
||||
# packagePath values, this can be used to generate a library for this API which
|
||||
# would have a unique fully qualified name.
|
||||
# Corresponds to the JSON property `ownerDomain`
|
||||
# @return [String]
|
||||
attr_accessor :owner_domain
|
||||
|
||||
# The name of the owner of this API. See ownerDomain.
|
||||
# Corresponds to the JSON property `ownerName`
|
||||
# @return [String]
|
||||
attr_accessor :owner_name
|
||||
|
||||
# The package of the owner of this API. See ownerDomain.
|
||||
# Corresponds to the JSON property `packagePath`
|
||||
# @return [String]
|
||||
attr_accessor :package_path
|
||||
|
||||
# Common parameters that apply across all apis.
|
||||
# Corresponds to the JSON property `parameters`
|
||||
# @return [Hash<String,Google::Apis::DiscoveryV1::JsonSchema>]
|
||||
attr_accessor :parameters
|
||||
|
||||
# The protocol described by this document.
|
||||
# Corresponds to the JSON property `protocol`
|
||||
# @return [String]
|
||||
attr_accessor :protocol
|
||||
|
||||
# The resources in this API.
|
||||
# Corresponds to the JSON property `resources`
|
||||
# @return [Hash<String,Google::Apis::DiscoveryV1::RestResource>]
|
||||
attr_accessor :resources
|
||||
|
||||
# The version of this API.
|
||||
# Corresponds to the JSON property `revision`
|
||||
# @return [String]
|
||||
attr_accessor :revision
|
||||
|
||||
# The root URL under which all API services live.
|
||||
# Corresponds to the JSON property `rootUrl`
|
||||
# @return [String]
|
||||
attr_accessor :root_url
|
||||
|
||||
# The schemas for this API.
|
||||
# Corresponds to the JSON property `schemas`
|
||||
# @return [Hash<String,Google::Apis::DiscoveryV1::JsonSchema>]
|
||||
attr_accessor :schemas
|
||||
|
||||
# The base path for all REST requests.
|
||||
# Corresponds to the JSON property `servicePath`
|
||||
# @return [String]
|
||||
attr_accessor :service_path
|
||||
|
||||
# The title of this API.
|
||||
# Corresponds to the JSON property `title`
|
||||
# @return [String]
|
||||
attr_accessor :title
|
||||
|
||||
# The version of this API.
|
||||
# Corresponds to the JSON property `version`
|
||||
# @return [String]
|
||||
attr_accessor :version
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@auth = args[:auth] unless args[:auth].nil?
|
||||
@base_path = args[:base_path] unless args[:base_path].nil?
|
||||
@base_url = args[:base_url] unless args[:base_url].nil?
|
||||
@batch_path = args[:batch_path] unless args[:batch_path].nil?
|
||||
@canonical_name = args[:canonical_name] unless args[:canonical_name].nil?
|
||||
@description = args[:description] unless args[:description].nil?
|
||||
@discovery_version = args[:discovery_version] unless args[:discovery_version].nil?
|
||||
@documentation_link = args[:documentation_link] unless args[:documentation_link].nil?
|
||||
@etag = args[:etag] unless args[:etag].nil?
|
||||
@features = args[:features] unless args[:features].nil?
|
||||
@icons = args[:icons] unless args[:icons].nil?
|
||||
@id = args[:id] unless args[:id].nil?
|
||||
@kind = args[:kind] unless args[:kind].nil?
|
||||
@labels = args[:labels] unless args[:labels].nil?
|
||||
@api_methods = args[:api_methods] unless args[:api_methods].nil?
|
||||
@name = args[:name] unless args[:name].nil?
|
||||
@owner_domain = args[:owner_domain] unless args[:owner_domain].nil?
|
||||
@owner_name = args[:owner_name] unless args[:owner_name].nil?
|
||||
@package_path = args[:package_path] unless args[:package_path].nil?
|
||||
@parameters = args[:parameters] unless args[:parameters].nil?
|
||||
@protocol = args[:protocol] unless args[:protocol].nil?
|
||||
@resources = args[:resources] unless args[:resources].nil?
|
||||
@revision = args[:revision] unless args[:revision].nil?
|
||||
@root_url = args[:root_url] unless args[:root_url].nil?
|
||||
@schemas = args[:schemas] unless args[:schemas].nil?
|
||||
@service_path = args[:service_path] unless args[:service_path].nil?
|
||||
@title = args[:title] unless args[:title].nil?
|
||||
@version = args[:version] unless args[:version].nil?
|
||||
end
|
||||
|
||||
# Authentication information.
|
||||
class Auth
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# OAuth 2.0 authentication information.
|
||||
# Corresponds to the JSON property `oauth2`
|
||||
# @return [Google::Apis::DiscoveryV1::RestDescription::Auth::Oauth2]
|
||||
attr_accessor :oauth2
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@oauth2 = args[:oauth2] unless args[:oauth2].nil?
|
||||
end
|
||||
|
||||
# OAuth 2.0 authentication information.
|
||||
class Oauth2
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# Available OAuth 2.0 scopes.
|
||||
# Corresponds to the JSON property `scopes`
|
||||
# @return [Hash<String,Google::Apis::DiscoveryV1::RestDescription::Auth::Oauth2::Scope>]
|
||||
attr_accessor :scopes
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@scopes = args[:scopes] unless args[:scopes].nil?
|
||||
end
|
||||
|
||||
# The scope value.
|
||||
class Scope
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# Description of scope.
|
||||
# Corresponds to the JSON property `description`
|
||||
# @return [String]
|
||||
attr_accessor :description
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@description = args[:description] unless args[:description].nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Links to 16x16 and 32x32 icons representing the API.
|
||||
class Icons
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# The URL of the 16x16 icon.
|
||||
# Corresponds to the JSON property `x16`
|
||||
# @return [String]
|
||||
attr_accessor :x16
|
||||
|
||||
# The URL of the 32x32 icon.
|
||||
# Corresponds to the JSON property `x32`
|
||||
# @return [String]
|
||||
attr_accessor :x32
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@x16 = args[:x16] unless args[:x16].nil?
|
||||
@x32 = args[:x32] unless args[:x32].nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
class RestMethod
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# Description of this method.
|
||||
# Corresponds to the JSON property `description`
|
||||
# @return [String]
|
||||
attr_accessor :description
|
||||
|
||||
# Whether this method requires an ETag to be specified. The ETag is sent as an
|
||||
# HTTP If-Match or If-None-Match header.
|
||||
# Corresponds to the JSON property `etagRequired`
|
||||
# @return [Boolean]
|
||||
attr_accessor :etag_required
|
||||
alias_method :etag_required?, :etag_required
|
||||
|
||||
# HTTP method used by this method.
|
||||
# Corresponds to the JSON property `httpMethod`
|
||||
# @return [String]
|
||||
attr_accessor :http_method
|
||||
|
||||
# A unique ID for this method. This property can be used to match methods
|
||||
# between different versions of Discovery.
|
||||
# Corresponds to the JSON property `id`
|
||||
# @return [String]
|
||||
attr_accessor :id
|
||||
|
||||
# Media upload parameters.
|
||||
# Corresponds to the JSON property `mediaUpload`
|
||||
# @return [Google::Apis::DiscoveryV1::RestMethod::MediaUpload]
|
||||
attr_accessor :media_upload
|
||||
|
||||
# Ordered list of required parameters, serves as a hint to clients on how to
|
||||
# structure their method signatures. The array is ordered such that the "most-
|
||||
# significant" parameter appears first.
|
||||
# Corresponds to the JSON property `parameterOrder`
|
||||
# @return [Array<String>]
|
||||
attr_accessor :parameter_order
|
||||
|
||||
# Details for all parameters in this method.
|
||||
# Corresponds to the JSON property `parameters`
|
||||
# @return [Hash<String,Google::Apis::DiscoveryV1::JsonSchema>]
|
||||
attr_accessor :parameters
|
||||
|
||||
# The URI path of this REST method. Should be used in conjunction with the
|
||||
# basePath property at the api-level.
|
||||
# Corresponds to the JSON property `path`
|
||||
# @return [String]
|
||||
attr_accessor :path
|
||||
|
||||
# The schema for the request.
|
||||
# Corresponds to the JSON property `request`
|
||||
# @return [Google::Apis::DiscoveryV1::RestMethod::Request]
|
||||
attr_accessor :request
|
||||
|
||||
# The schema for the response.
|
||||
# Corresponds to the JSON property `response`
|
||||
# @return [Google::Apis::DiscoveryV1::RestMethod::Response]
|
||||
attr_accessor :response
|
||||
|
||||
# OAuth 2.0 scopes applicable to this method.
|
||||
# Corresponds to the JSON property `scopes`
|
||||
# @return [Array<String>]
|
||||
attr_accessor :scopes
|
||||
|
||||
# Whether this method supports media downloads.
|
||||
# Corresponds to the JSON property `supportsMediaDownload`
|
||||
# @return [Boolean]
|
||||
attr_accessor :supports_media_download
|
||||
alias_method :supports_media_download?, :supports_media_download
|
||||
|
||||
# Whether this method supports media uploads.
|
||||
# Corresponds to the JSON property `supportsMediaUpload`
|
||||
# @return [Boolean]
|
||||
attr_accessor :supports_media_upload
|
||||
alias_method :supports_media_upload?, :supports_media_upload
|
||||
|
||||
# Whether this method supports subscriptions.
|
||||
# Corresponds to the JSON property `supportsSubscription`
|
||||
# @return [Boolean]
|
||||
attr_accessor :supports_subscription
|
||||
alias_method :supports_subscription?, :supports_subscription
|
||||
|
||||
# Indicates that downloads from this method should use the download service URL (
|
||||
# i.e. "/download"). Only applies if the method supports media download.
|
||||
# Corresponds to the JSON property `useMediaDownloadService`
|
||||
# @return [Boolean]
|
||||
attr_accessor :use_media_download_service
|
||||
alias_method :use_media_download_service?, :use_media_download_service
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@description = args[:description] unless args[:description].nil?
|
||||
@etag_required = args[:etag_required] unless args[:etag_required].nil?
|
||||
@http_method = args[:http_method] unless args[:http_method].nil?
|
||||
@id = args[:id] unless args[:id].nil?
|
||||
@media_upload = args[:media_upload] unless args[:media_upload].nil?
|
||||
@parameter_order = args[:parameter_order] unless args[:parameter_order].nil?
|
||||
@parameters = args[:parameters] unless args[:parameters].nil?
|
||||
@path = args[:path] unless args[:path].nil?
|
||||
@request = args[:request] unless args[:request].nil?
|
||||
@response = args[:response] unless args[:response].nil?
|
||||
@scopes = args[:scopes] unless args[:scopes].nil?
|
||||
@supports_media_download = args[:supports_media_download] unless args[:supports_media_download].nil?
|
||||
@supports_media_upload = args[:supports_media_upload] unless args[:supports_media_upload].nil?
|
||||
@supports_subscription = args[:supports_subscription] unless args[:supports_subscription].nil?
|
||||
@use_media_download_service = args[:use_media_download_service] unless args[:use_media_download_service].nil?
|
||||
end
|
||||
|
||||
# Media upload parameters.
|
||||
class MediaUpload
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# MIME Media Ranges for acceptable media uploads to this method.
|
||||
# Corresponds to the JSON property `accept`
|
||||
# @return [Array<String>]
|
||||
attr_accessor :accept
|
||||
|
||||
# Maximum size of a media upload, such as "1MB", "2GB" or "3TB".
|
||||
# Corresponds to the JSON property `maxSize`
|
||||
# @return [String]
|
||||
attr_accessor :max_size
|
||||
|
||||
# Supported upload protocols.
|
||||
# Corresponds to the JSON property `protocols`
|
||||
# @return [Google::Apis::DiscoveryV1::RestMethod::MediaUpload::Protocols]
|
||||
attr_accessor :protocols
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@accept = args[:accept] unless args[:accept].nil?
|
||||
@max_size = args[:max_size] unless args[:max_size].nil?
|
||||
@protocols = args[:protocols] unless args[:protocols].nil?
|
||||
end
|
||||
|
||||
# Supported upload protocols.
|
||||
class Protocols
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# Supports the Resumable Media Upload protocol.
|
||||
# Corresponds to the JSON property `resumable`
|
||||
# @return [Google::Apis::DiscoveryV1::RestMethod::MediaUpload::Protocols::Resumable]
|
||||
attr_accessor :resumable
|
||||
|
||||
# Supports uploading as a single HTTP request.
|
||||
# Corresponds to the JSON property `simple`
|
||||
# @return [Google::Apis::DiscoveryV1::RestMethod::MediaUpload::Protocols::Simple]
|
||||
attr_accessor :simple
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@resumable = args[:resumable] unless args[:resumable].nil?
|
||||
@simple = args[:simple] unless args[:simple].nil?
|
||||
end
|
||||
|
||||
# Supports the Resumable Media Upload protocol.
|
||||
class Resumable
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# True if this endpoint supports uploading multipart media.
|
||||
# Corresponds to the JSON property `multipart`
|
||||
# @return [Boolean]
|
||||
attr_accessor :multipart
|
||||
alias_method :multipart?, :multipart
|
||||
|
||||
# The URI path to be used for upload. Should be used in conjunction with the
|
||||
# basePath property at the api-level.
|
||||
# Corresponds to the JSON property `path`
|
||||
# @return [String]
|
||||
attr_accessor :path
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@multipart = args[:multipart] unless args[:multipart].nil?
|
||||
@path = args[:path] unless args[:path].nil?
|
||||
end
|
||||
end
|
||||
|
||||
# Supports uploading as a single HTTP request.
|
||||
class Simple
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# True if this endpoint supports upload multipart media.
|
||||
# Corresponds to the JSON property `multipart`
|
||||
# @return [Boolean]
|
||||
attr_accessor :multipart
|
||||
alias_method :multipart?, :multipart
|
||||
|
||||
# The URI path to be used for upload. Should be used in conjunction with the
|
||||
# basePath property at the api-level.
|
||||
# Corresponds to the JSON property `path`
|
||||
# @return [String]
|
||||
attr_accessor :path
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@multipart = args[:multipart] unless args[:multipart].nil?
|
||||
@path = args[:path] unless args[:path].nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# The schema for the request.
|
||||
class Request
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# Schema ID for the request schema.
|
||||
# Corresponds to the JSON property `$ref`
|
||||
# @return [String]
|
||||
attr_accessor :_ref
|
||||
|
||||
# parameter name.
|
||||
# Corresponds to the JSON property `parameterName`
|
||||
# @return [String]
|
||||
attr_accessor :parameter_name
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@_ref = args[:_ref] unless args[:_ref].nil?
|
||||
@parameter_name = args[:parameter_name] unless args[:parameter_name].nil?
|
||||
end
|
||||
end
|
||||
|
||||
# The schema for the response.
|
||||
class Response
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# Schema ID for the response schema.
|
||||
# Corresponds to the JSON property `$ref`
|
||||
# @return [String]
|
||||
attr_accessor :_ref
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@_ref = args[:_ref] unless args[:_ref].nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
class RestResource
|
||||
include Google::Apis::Core::Hashable
|
||||
|
||||
# Methods on this resource.
|
||||
# Corresponds to the JSON property `methods`
|
||||
# @return [Hash<String,Google::Apis::DiscoveryV1::RestMethod>]
|
||||
attr_accessor :api_methods
|
||||
|
||||
# Sub-resources on this resource.
|
||||
# Corresponds to the JSON property `resources`
|
||||
# @return [Hash<String,Google::Apis::DiscoveryV1::RestResource>]
|
||||
attr_accessor :resources
|
||||
|
||||
def initialize(**args)
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
@api_methods = args[:api_methods] unless args[:api_methods].nil?
|
||||
@resources = args[:resources] unless args[:resources].nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,355 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'date'
|
||||
require 'google/apis/core/base_service'
|
||||
require 'google/apis/core/json_representation'
|
||||
require 'google/apis/core/hashable'
|
||||
require 'google/apis/errors'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
module DiscoveryV1
|
||||
|
||||
class DirectoryList
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
|
||||
class Item
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
|
||||
class Icons
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class JsonSchema
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
|
||||
class Annotations
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
end
|
||||
|
||||
class Variant
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
|
||||
class Map
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class RestDescription
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
|
||||
class Auth
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
|
||||
class Oauth2
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
|
||||
class Scope
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Icons
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
end
|
||||
end
|
||||
|
||||
class RestMethod
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
|
||||
class MediaUpload
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
|
||||
class Protocols
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
|
||||
class Resumable
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
end
|
||||
|
||||
class Simple
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Request
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
end
|
||||
|
||||
class Response
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
end
|
||||
end
|
||||
|
||||
class RestResource
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
end
|
||||
|
||||
# @private
|
||||
class DirectoryList
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :discovery_version, as: 'discoveryVersion'
|
||||
collection :items, as: 'items', class: Google::Apis::DiscoveryV1::DirectoryList::Item, decorator: Google::Apis::DiscoveryV1::DirectoryList::Item::Representation
|
||||
|
||||
property :kind, as: 'kind'
|
||||
end
|
||||
|
||||
# @private
|
||||
class Item
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :description, as: 'description'
|
||||
property :discovery_link, as: 'discoveryLink'
|
||||
property :discovery_rest_url, as: 'discoveryRestUrl'
|
||||
property :documentation_link, as: 'documentationLink'
|
||||
property :icons, as: 'icons', class: Google::Apis::DiscoveryV1::DirectoryList::Item::Icons, decorator: Google::Apis::DiscoveryV1::DirectoryList::Item::Icons::Representation
|
||||
|
||||
property :id, as: 'id'
|
||||
property :kind, as: 'kind'
|
||||
collection :labels, as: 'labels'
|
||||
property :name, as: 'name'
|
||||
property :preferred, as: 'preferred'
|
||||
property :title, as: 'title'
|
||||
property :version, as: 'version'
|
||||
end
|
||||
|
||||
# @private
|
||||
class Icons
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :x16, as: 'x16'
|
||||
property :x32, as: 'x32'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# @private
|
||||
class JsonSchema
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :_ref, as: '$ref'
|
||||
property :additional_properties, as: 'additionalProperties', class: Google::Apis::DiscoveryV1::JsonSchema, decorator: Google::Apis::DiscoveryV1::JsonSchema::Representation
|
||||
|
||||
property :annotations, as: 'annotations', class: Google::Apis::DiscoveryV1::JsonSchema::Annotations, decorator: Google::Apis::DiscoveryV1::JsonSchema::Annotations::Representation
|
||||
|
||||
property :default, as: 'default'
|
||||
property :description, as: 'description'
|
||||
collection :enum, as: 'enum'
|
||||
collection :enum_descriptions, as: 'enumDescriptions'
|
||||
property :format, as: 'format'
|
||||
property :id, as: 'id'
|
||||
property :items, as: 'items', class: Google::Apis::DiscoveryV1::JsonSchema, decorator: Google::Apis::DiscoveryV1::JsonSchema::Representation
|
||||
|
||||
property :location, as: 'location'
|
||||
property :maximum, as: 'maximum'
|
||||
property :minimum, as: 'minimum'
|
||||
property :pattern, as: 'pattern'
|
||||
hash :properties, as: 'properties', class: Google::Apis::DiscoveryV1::JsonSchema, decorator: Google::Apis::DiscoveryV1::JsonSchema::Representation
|
||||
|
||||
property :read_only, as: 'readOnly'
|
||||
property :repeated, as: 'repeated'
|
||||
property :required, as: 'required'
|
||||
property :type, as: 'type'
|
||||
property :variant, as: 'variant', class: Google::Apis::DiscoveryV1::JsonSchema::Variant, decorator: Google::Apis::DiscoveryV1::JsonSchema::Variant::Representation
|
||||
|
||||
end
|
||||
|
||||
# @private
|
||||
class Annotations
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
collection :required, as: 'required'
|
||||
end
|
||||
end
|
||||
|
||||
# @private
|
||||
class Variant
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :discriminant, as: 'discriminant'
|
||||
collection :map, as: 'map', class: Google::Apis::DiscoveryV1::JsonSchema::Variant::Map, decorator: Google::Apis::DiscoveryV1::JsonSchema::Variant::Map::Representation
|
||||
|
||||
end
|
||||
|
||||
# @private
|
||||
class Map
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :_ref, as: '$ref'
|
||||
property :type_value, as: 'type_value'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# @private
|
||||
class RestDescription
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :auth, as: 'auth', class: Google::Apis::DiscoveryV1::RestDescription::Auth, decorator: Google::Apis::DiscoveryV1::RestDescription::Auth::Representation
|
||||
|
||||
property :base_path, as: 'basePath'
|
||||
property :base_url, as: 'baseUrl'
|
||||
property :batch_path, as: 'batchPath'
|
||||
property :canonical_name, as: 'canonicalName'
|
||||
property :description, as: 'description'
|
||||
property :discovery_version, as: 'discoveryVersion'
|
||||
property :documentation_link, as: 'documentationLink'
|
||||
property :etag, as: 'etag'
|
||||
collection :features, as: 'features'
|
||||
property :icons, as: 'icons', class: Google::Apis::DiscoveryV1::RestDescription::Icons, decorator: Google::Apis::DiscoveryV1::RestDescription::Icons::Representation
|
||||
|
||||
property :id, as: 'id'
|
||||
property :kind, as: 'kind'
|
||||
collection :labels, as: 'labels'
|
||||
hash :api_methods, as: 'methods', class: Google::Apis::DiscoveryV1::RestMethod, decorator: Google::Apis::DiscoveryV1::RestMethod::Representation
|
||||
|
||||
property :name, as: 'name'
|
||||
property :owner_domain, as: 'ownerDomain'
|
||||
property :owner_name, as: 'ownerName'
|
||||
property :package_path, as: 'packagePath'
|
||||
hash :parameters, as: 'parameters', class: Google::Apis::DiscoveryV1::JsonSchema, decorator: Google::Apis::DiscoveryV1::JsonSchema::Representation
|
||||
|
||||
property :protocol, as: 'protocol'
|
||||
hash :resources, as: 'resources', class: Google::Apis::DiscoveryV1::RestResource, decorator: Google::Apis::DiscoveryV1::RestResource::Representation
|
||||
|
||||
property :revision, as: 'revision'
|
||||
property :root_url, as: 'rootUrl'
|
||||
hash :schemas, as: 'schemas', class: Google::Apis::DiscoveryV1::JsonSchema, decorator: Google::Apis::DiscoveryV1::JsonSchema::Representation
|
||||
|
||||
property :service_path, as: 'servicePath'
|
||||
property :title, as: 'title'
|
||||
property :version, as: 'version'
|
||||
end
|
||||
|
||||
# @private
|
||||
class Auth
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :oauth2, as: 'oauth2', class: Google::Apis::DiscoveryV1::RestDescription::Auth::Oauth2, decorator: Google::Apis::DiscoveryV1::RestDescription::Auth::Oauth2::Representation
|
||||
|
||||
end
|
||||
|
||||
# @private
|
||||
class Oauth2
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
hash :scopes, as: 'scopes', class: Google::Apis::DiscoveryV1::RestDescription::Auth::Oauth2::Scope, decorator: Google::Apis::DiscoveryV1::RestDescription::Auth::Oauth2::Scope::Representation
|
||||
|
||||
end
|
||||
|
||||
# @private
|
||||
class Scope
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :description, as: 'description'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# @private
|
||||
class Icons
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :x16, as: 'x16'
|
||||
property :x32, as: 'x32'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# @private
|
||||
class RestMethod
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :description, as: 'description'
|
||||
property :etag_required, as: 'etagRequired'
|
||||
property :http_method, as: 'httpMethod'
|
||||
property :id, as: 'id'
|
||||
property :media_upload, as: 'mediaUpload', class: Google::Apis::DiscoveryV1::RestMethod::MediaUpload, decorator: Google::Apis::DiscoveryV1::RestMethod::MediaUpload::Representation
|
||||
|
||||
collection :parameter_order, as: 'parameterOrder'
|
||||
hash :parameters, as: 'parameters', class: Google::Apis::DiscoveryV1::JsonSchema, decorator: Google::Apis::DiscoveryV1::JsonSchema::Representation
|
||||
|
||||
property :path, as: 'path'
|
||||
property :request, as: 'request', class: Google::Apis::DiscoveryV1::RestMethod::Request, decorator: Google::Apis::DiscoveryV1::RestMethod::Request::Representation
|
||||
|
||||
property :response, as: 'response', class: Google::Apis::DiscoveryV1::RestMethod::Response, decorator: Google::Apis::DiscoveryV1::RestMethod::Response::Representation
|
||||
|
||||
collection :scopes, as: 'scopes'
|
||||
property :supports_media_download, as: 'supportsMediaDownload'
|
||||
property :supports_media_upload, as: 'supportsMediaUpload'
|
||||
property :supports_subscription, as: 'supportsSubscription'
|
||||
property :use_media_download_service, as: 'useMediaDownloadService'
|
||||
end
|
||||
|
||||
# @private
|
||||
class MediaUpload
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
collection :accept, as: 'accept'
|
||||
property :max_size, as: 'maxSize'
|
||||
property :protocols, as: 'protocols', class: Google::Apis::DiscoveryV1::RestMethod::MediaUpload::Protocols, decorator: Google::Apis::DiscoveryV1::RestMethod::MediaUpload::Protocols::Representation
|
||||
|
||||
end
|
||||
|
||||
# @private
|
||||
class Protocols
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :resumable, as: 'resumable', class: Google::Apis::DiscoveryV1::RestMethod::MediaUpload::Protocols::Resumable, decorator: Google::Apis::DiscoveryV1::RestMethod::MediaUpload::Protocols::Resumable::Representation
|
||||
|
||||
property :simple, as: 'simple', class: Google::Apis::DiscoveryV1::RestMethod::MediaUpload::Protocols::Simple, decorator: Google::Apis::DiscoveryV1::RestMethod::MediaUpload::Protocols::Simple::Representation
|
||||
|
||||
end
|
||||
|
||||
# @private
|
||||
class Resumable
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :multipart, as: 'multipart'
|
||||
property :path, as: 'path'
|
||||
end
|
||||
end
|
||||
|
||||
# @private
|
||||
class Simple
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :multipart, as: 'multipart'
|
||||
property :path, as: 'path'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# @private
|
||||
class Request
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :_ref, as: '$ref'
|
||||
property :parameter_name, as: 'parameterName'
|
||||
end
|
||||
end
|
||||
|
||||
# @private
|
||||
class Response
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
property :_ref, as: '$ref'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# @private
|
||||
class RestResource
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
hash :api_methods, as: 'methods', class: Google::Apis::DiscoveryV1::RestMethod, decorator: Google::Apis::DiscoveryV1::RestMethod::Representation
|
||||
|
||||
hash :resources, as: 'resources', class: Google::Apis::DiscoveryV1::RestResource, decorator: Google::Apis::DiscoveryV1::RestResource::Representation
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,144 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'google/apis/core/base_service'
|
||||
require 'google/apis/core/json_representation'
|
||||
require 'google/apis/core/hashable'
|
||||
require 'google/apis/errors'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
module DiscoveryV1
|
||||
# APIs Discovery Service
|
||||
#
|
||||
# Lets you discover information about other Google APIs, such as what APIs are
|
||||
# available, the resource and method details for each API.
|
||||
#
|
||||
# @example
|
||||
# require 'google/apis/discovery_v1'
|
||||
#
|
||||
# Discovery = Google::Apis::DiscoveryV1 # Alias the module
|
||||
# service = Discovery::DiscoveryService.new
|
||||
#
|
||||
# @see https://developers.google.com/discovery/
|
||||
class DiscoveryService < Google::Apis::Core::BaseService
|
||||
# @return [String]
|
||||
# API key. Your API key identifies your project and provides you with API access,
|
||||
# quota, and reports. Required unless you provide an OAuth 2.0 token.
|
||||
attr_accessor :key
|
||||
|
||||
# @return [String]
|
||||
# Available to use for quota purposes for server-side applications. Can be any
|
||||
# arbitrary string assigned to a user, but should not exceed 40 characters.
|
||||
# Overrides userIp if both are provided.
|
||||
attr_accessor :quota_user
|
||||
|
||||
# @return [String]
|
||||
# IP address of the site where the request originates. Use this if you want to
|
||||
# enforce per-user limits.
|
||||
attr_accessor :user_ip
|
||||
|
||||
def initialize
|
||||
super('https://www.googleapis.com/', 'discovery/v1/')
|
||||
end
|
||||
|
||||
# Retrieve the description of a particular version of an api.
|
||||
# @param [String] api
|
||||
# The name of the API.
|
||||
# @param [String] version
|
||||
# The version of the API.
|
||||
# @param [String] fields
|
||||
# Selector specifying which fields to include in a partial response.
|
||||
# @param [String] quota_user
|
||||
# Available to use for quota purposes for server-side applications. Can be any
|
||||
# arbitrary string assigned to a user, but should not exceed 40 characters.
|
||||
# Overrides userIp if both are provided.
|
||||
# @param [String] user_ip
|
||||
# IP address of the site where the request originates. Use this if you want to
|
||||
# enforce per-user limits.
|
||||
# @param [Google::Apis::RequestOptions] options
|
||||
# Request-specific options
|
||||
#
|
||||
# @yield [result, err] Result & error if block supplied
|
||||
# @yieldparam result [Google::Apis::DiscoveryV1::RestDescription] parsed result object
|
||||
# @yieldparam err [StandardError] error object if request failed
|
||||
#
|
||||
# @return [Google::Apis::DiscoveryV1::RestDescription]
|
||||
#
|
||||
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
||||
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
||||
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
||||
def get_rest_api(api, version, fields: nil, quota_user: nil, user_ip: nil, options: nil, &block)
|
||||
path = 'apis/{api}/{version}/rest'
|
||||
command = make_simple_command(:get, path, options)
|
||||
command.response_representation = Google::Apis::DiscoveryV1::RestDescription::Representation
|
||||
command.response_class = Google::Apis::DiscoveryV1::RestDescription
|
||||
command.params['api'] = api unless api.nil?
|
||||
command.params['version'] = version unless version.nil?
|
||||
command.query['fields'] = fields unless fields.nil?
|
||||
command.query['quotaUser'] = quota_user unless quota_user.nil?
|
||||
command.query['userIp'] = user_ip unless user_ip.nil?
|
||||
execute_or_queue_command(command, &block)
|
||||
end
|
||||
|
||||
# Retrieve the list of APIs supported at this endpoint.
|
||||
# @param [String] name
|
||||
# Only include APIs with the given name.
|
||||
# @param [Boolean] preferred
|
||||
# Return only the preferred version of an API.
|
||||
# @param [String] fields
|
||||
# Selector specifying which fields to include in a partial response.
|
||||
# @param [String] quota_user
|
||||
# Available to use for quota purposes for server-side applications. Can be any
|
||||
# arbitrary string assigned to a user, but should not exceed 40 characters.
|
||||
# Overrides userIp if both are provided.
|
||||
# @param [String] user_ip
|
||||
# IP address of the site where the request originates. Use this if you want to
|
||||
# enforce per-user limits.
|
||||
# @param [Google::Apis::RequestOptions] options
|
||||
# Request-specific options
|
||||
#
|
||||
# @yield [result, err] Result & error if block supplied
|
||||
# @yieldparam result [Google::Apis::DiscoveryV1::DirectoryList] parsed result object
|
||||
# @yieldparam err [StandardError] error object if request failed
|
||||
#
|
||||
# @return [Google::Apis::DiscoveryV1::DirectoryList]
|
||||
#
|
||||
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
||||
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
||||
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
||||
def list_apis(name: nil, preferred: nil, fields: nil, quota_user: nil, user_ip: nil, options: nil, &block)
|
||||
path = 'apis'
|
||||
command = make_simple_command(:get, path, options)
|
||||
command.response_representation = Google::Apis::DiscoveryV1::DirectoryList::Representation
|
||||
command.response_class = Google::Apis::DiscoveryV1::DirectoryList
|
||||
command.query['name'] = name unless name.nil?
|
||||
command.query['preferred'] = preferred unless preferred.nil?
|
||||
command.query['fields'] = fields unless fields.nil?
|
||||
command.query['quotaUser'] = quota_user unless quota_user.nil?
|
||||
command.query['userIp'] = user_ip unless user_ip.nil?
|
||||
execute_or_queue_command(command, &block)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def apply_command_defaults(command)
|
||||
command.query['key'] = key unless key.nil?
|
||||
command.query['quotaUser'] = quota_user unless quota_user.nil?
|
||||
command.query['userIp'] = user_ip unless user_ip.nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,43 +1,31 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.join(File.dirname(__FILE__), 'lib/google/api_client', 'version')
|
||||
# coding: utf-8
|
||||
lib = File.expand_path('../lib', __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'google/apis/version'
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "google-api-client"
|
||||
s.version = Google::APIClient::VERSION::STRING
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = 'google-api-client'
|
||||
spec.version = Google::Apis::VERSION
|
||||
spec.authors = ['Steven Bazyl', 'Tim Emiola', 'Sergio Gomes', 'Bob Aman']
|
||||
spec.email = ['sbazyl@google.com']
|
||||
spec.summary = %q{Client for accessing Google APIs}
|
||||
spec.homepage = 'https://github.com/google/google-api-ruby-client'
|
||||
spec.license = 'Apache 2.0'
|
||||
|
||||
s.required_rubygems_version = ">= 1.3.5"
|
||||
s.require_paths = ["lib"]
|
||||
s.authors = ["Bob Aman", "Steven Bazyl"]
|
||||
s.license = "Apache-2.0"
|
||||
s.description = "The Google API Ruby Client makes it trivial to discover and access supported APIs."
|
||||
s.email = "sbazyl@google.com"
|
||||
s.extra_rdoc_files = ["README.md"]
|
||||
s.files = %w(google-api-client.gemspec Rakefile LICENSE CHANGELOG.md README.md Gemfile)
|
||||
s.files += Dir.glob("lib/**/*.rb")
|
||||
s.files += Dir.glob("lib/cacerts.pem")
|
||||
s.files += Dir.glob("spec/**/*.{rb,opts}")
|
||||
s.files += Dir.glob("vendor/**/*.rb")
|
||||
s.files += Dir.glob("tasks/**/*")
|
||||
s.files += Dir.glob("website/**/*")
|
||||
s.homepage = "https://github.com/google/google-api-ruby-client/"
|
||||
s.rdoc_options = ["--main", "README.md"]
|
||||
s.summary = "The Google API Ruby Client makes it trivial to discover and access Google's REST APIs."
|
||||
spec.files = `git ls-files -z`.split("\x0")
|
||||
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
||||
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
||||
spec.require_paths = ['lib', 'generated']
|
||||
|
||||
s.add_runtime_dependency 'addressable', '~> 2.3'
|
||||
s.add_runtime_dependency 'signet', '~> 0.6'
|
||||
s.add_runtime_dependency 'faraday', '~> 0.9'
|
||||
s.add_runtime_dependency 'googleauth', '~> 0.3'
|
||||
s.add_runtime_dependency 'multi_json', '~> 1.10'
|
||||
s.add_runtime_dependency 'autoparse', '~> 0.3'
|
||||
s.add_runtime_dependency 'extlib', '~> 0.9'
|
||||
s.add_runtime_dependency 'launchy', '~> 2.4'
|
||||
s.add_runtime_dependency 'retriable', '~> 1.4'
|
||||
s.add_runtime_dependency 'activesupport', '>= 3.2'
|
||||
|
||||
s.add_development_dependency 'rake', '~> 10.0'
|
||||
s.add_development_dependency 'yard', '~> 0.8'
|
||||
s.add_development_dependency 'rspec', '~> 3.1'
|
||||
s.add_development_dependency 'kramdown', '~> 1.5'
|
||||
s.add_development_dependency 'simplecov', '~> 0.9.2'
|
||||
s.add_development_dependency 'coveralls', '~> 0.7.11'
|
||||
spec.add_runtime_dependency 'representable', '~> 2.1'
|
||||
spec.add_runtime_dependency 'multi_json', '~> 1.11'
|
||||
spec.add_runtime_dependency 'retriable', '~> 2.0'
|
||||
spec.add_runtime_dependency 'activesupport', '>= 3.2'
|
||||
spec.add_runtime_dependency 'addressable', '~> 2.3'
|
||||
spec.add_runtime_dependency 'mime-types', '>= 1.6'
|
||||
spec.add_runtime_dependency 'hurley', '~> 0.1'
|
||||
spec.add_runtime_dependency 'googleauth', '~> 0.2'
|
||||
spec.add_runtime_dependency 'thor', '~> 0.19'
|
||||
spec.add_runtime_dependency 'memoist', '~> 0.11'
|
||||
spec.add_runtime_dependency 'virtus', '~> 1.0'
|
||||
end
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
require 'multi_json'
|
||||
|
||||
if !MultiJson.respond_to?(:load) || [
|
||||
Kernel,
|
||||
defined?(ActiveSupport::Dependencies::Loadable) && ActiveSupport::Dependencies::Loadable
|
||||
].compact.include?(MultiJson.method(:load).owner)
|
||||
module MultiJson
|
||||
class <<self
|
||||
alias :load :decode
|
||||
end
|
||||
end
|
||||
end
|
||||
if !MultiJson.respond_to?(:dump)
|
||||
module MultiJson
|
||||
class <<self
|
||||
alias :dump :encode
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,750 +0,0 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
require 'faraday'
|
||||
require 'multi_json'
|
||||
require 'compat/multi_json'
|
||||
require 'stringio'
|
||||
require 'retriable'
|
||||
|
||||
require 'google/api_client/version'
|
||||
require 'google/api_client/logging'
|
||||
require 'google/api_client/errors'
|
||||
require 'google/api_client/environment'
|
||||
require 'google/api_client/discovery'
|
||||
require 'google/api_client/request'
|
||||
require 'google/api_client/reference'
|
||||
require 'google/api_client/result'
|
||||
require 'google/api_client/media'
|
||||
require 'google/api_client/service_account'
|
||||
require 'google/api_client/batch'
|
||||
require 'google/api_client/gzip'
|
||||
require 'google/api_client/charset'
|
||||
require 'google/api_client/client_secrets'
|
||||
require 'google/api_client/railtie' if defined?(Rails)
|
||||
|
||||
module Google
|
||||
|
||||
##
|
||||
# This class manages APIs communication.
|
||||
class APIClient
|
||||
include Google::APIClient::Logging
|
||||
|
||||
##
|
||||
# Creates a new Google API client.
|
||||
#
|
||||
# @param [Hash] options The configuration parameters for the client.
|
||||
# @option options [Symbol, #generate_authenticated_request] :authorization
|
||||
# (:oauth_1)
|
||||
# The authorization mechanism used by the client. The following
|
||||
# mechanisms are supported out-of-the-box:
|
||||
# <ul>
|
||||
# <li><code>:two_legged_oauth_1</code></li>
|
||||
# <li><code>:oauth_1</code></li>
|
||||
# <li><code>:oauth_2</code></li>
|
||||
# <li><code>:google_app_default</code></li>
|
||||
# </ul>
|
||||
# @option options [Boolean] :auto_refresh_token (true)
|
||||
# The setting that controls whether or not the api client attempts to
|
||||
# refresh authorization when a 401 is hit in #execute. If the token does
|
||||
# not support it, this option is ignored.
|
||||
# @option options [String] :application_name
|
||||
# The name of the application using the client.
|
||||
# @option options [String | Array | nil] :scope
|
||||
# The scope(s) used when using google application default credentials
|
||||
# @option options [String] :application_version
|
||||
# The version number of the application using the client.
|
||||
# @option options [String] :user_agent
|
||||
# ("{app_name} google-api-ruby-client/{version} {os_name}/{os_version}")
|
||||
# The user agent used by the client. Most developers will want to
|
||||
# leave this value alone and use the `:application_name` option instead.
|
||||
# @option options [String] :host ("www.googleapis.com")
|
||||
# The API hostname used by the client. This rarely needs to be changed.
|
||||
# @option options [String] :port (443)
|
||||
# The port number used by the client. This rarely needs to be changed.
|
||||
# @option options [String] :discovery_path ("/discovery/v1")
|
||||
# The discovery base path. This rarely needs to be changed.
|
||||
# @option options [String] :ca_file
|
||||
# Optional set of root certificates to use when validating SSL connections.
|
||||
# By default, a bundled set of trusted roots will be used.
|
||||
# @options options[Hash] :force_encoding
|
||||
# Experimental option. True if response body should be force encoded into the charset
|
||||
# specified in the Content-Type header. Mostly intended for compressed content.
|
||||
# @options options[Hash] :faraday_option
|
||||
# Pass through of options to set on the Faraday connection
|
||||
def initialize(options={})
|
||||
logger.debug { "#{self.class} - Initializing client with options #{options}" }
|
||||
|
||||
# Normalize key to String to allow indifferent access.
|
||||
options = options.inject({}) do |accu, (key, value)|
|
||||
accu[key.to_sym] = value
|
||||
accu
|
||||
end
|
||||
# Almost all API usage will have a host of 'www.googleapis.com'.
|
||||
self.host = options[:host] || 'www.googleapis.com'
|
||||
self.port = options[:port] || 443
|
||||
self.discovery_path = options[:discovery_path] || '/discovery/v1'
|
||||
|
||||
# Most developers will want to leave this value alone and use the
|
||||
# application_name option.
|
||||
if options[:application_name]
|
||||
app_name = options[:application_name]
|
||||
app_version = options[:application_version]
|
||||
application_string = "#{app_name}/#{app_version || '0.0.0'}"
|
||||
else
|
||||
logger.warn { "#{self.class} - Please provide :application_name and :application_version when initializing the client" }
|
||||
end
|
||||
|
||||
proxy = options[:proxy] || Object::ENV["http_proxy"]
|
||||
|
||||
self.user_agent = options[:user_agent] || (
|
||||
"#{application_string} " +
|
||||
"google-api-ruby-client/#{Google::APIClient::VERSION::STRING} #{ENV::OS_VERSION} (gzip)"
|
||||
).strip
|
||||
# The writer method understands a few Symbols and will generate useful
|
||||
# default authentication mechanisms.
|
||||
self.authorization =
|
||||
options.key?(:authorization) ? options[:authorization] : :oauth_2
|
||||
if !options['scope'].nil? and self.authorization.respond_to?(:scope=)
|
||||
self.authorization.scope = options['scope']
|
||||
end
|
||||
self.auto_refresh_token = options.fetch(:auto_refresh_token) { true }
|
||||
self.key = options[:key]
|
||||
self.user_ip = options[:user_ip]
|
||||
self.retries = options.fetch(:retries) { 0 }
|
||||
self.expired_auth_retry = options.fetch(:expired_auth_retry) { true }
|
||||
@discovery_uris = {}
|
||||
@discovery_documents = {}
|
||||
@discovered_apis = {}
|
||||
ca_file = options[:ca_file] || File.expand_path('../../cacerts.pem', __FILE__)
|
||||
self.connection = Faraday.new do |faraday|
|
||||
faraday.response :charset if options[:force_encoding]
|
||||
faraday.response :gzip
|
||||
faraday.options.params_encoder = Faraday::FlatParamsEncoder
|
||||
faraday.ssl.ca_file = ca_file
|
||||
faraday.ssl.verify = true
|
||||
faraday.proxy proxy
|
||||
faraday.adapter Faraday.default_adapter
|
||||
if options[:faraday_option].is_a?(Hash)
|
||||
options[:faraday_option].each_pair do |option, value|
|
||||
faraday.options.send("#{option}=", value)
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the authorization mechanism used by the client.
|
||||
#
|
||||
# @return [#generate_authenticated_request] The authorization mechanism.
|
||||
attr_reader :authorization
|
||||
|
||||
##
|
||||
# Sets the authorization mechanism used by the client.
|
||||
#
|
||||
# @param [#generate_authenticated_request] new_authorization
|
||||
# The new authorization mechanism.
|
||||
def authorization=(new_authorization)
|
||||
case new_authorization
|
||||
when :oauth_1, :oauth
|
||||
require 'signet/oauth_1/client'
|
||||
# NOTE: Do not rely on this default value, as it may change
|
||||
new_authorization = Signet::OAuth1::Client.new(
|
||||
:temporary_credential_uri =>
|
||||
'https://www.google.com/accounts/OAuthGetRequestToken',
|
||||
:authorization_uri =>
|
||||
'https://www.google.com/accounts/OAuthAuthorizeToken',
|
||||
:token_credential_uri =>
|
||||
'https://www.google.com/accounts/OAuthGetAccessToken',
|
||||
:client_credential_key => 'anonymous',
|
||||
:client_credential_secret => 'anonymous'
|
||||
)
|
||||
when :two_legged_oauth_1, :two_legged_oauth
|
||||
require 'signet/oauth_1/client'
|
||||
# NOTE: Do not rely on this default value, as it may change
|
||||
new_authorization = Signet::OAuth1::Client.new(
|
||||
:client_credential_key => nil,
|
||||
:client_credential_secret => nil,
|
||||
:two_legged => true
|
||||
)
|
||||
when :google_app_default
|
||||
require 'googleauth'
|
||||
new_authorization = Google::Auth.get_application_default
|
||||
|
||||
when :oauth_2
|
||||
require 'signet/oauth_2/client'
|
||||
# NOTE: Do not rely on this default value, as it may change
|
||||
new_authorization = Signet::OAuth2::Client.new(
|
||||
:authorization_uri =>
|
||||
'https://accounts.google.com/o/oauth2/auth',
|
||||
:token_credential_uri =>
|
||||
'https://accounts.google.com/o/oauth2/token'
|
||||
)
|
||||
when nil
|
||||
# No authorization mechanism
|
||||
else
|
||||
if !new_authorization.respond_to?(:generate_authenticated_request)
|
||||
raise TypeError,
|
||||
'Expected authorization mechanism to respond to ' +
|
||||
'#generate_authenticated_request.'
|
||||
end
|
||||
end
|
||||
@authorization = new_authorization
|
||||
return @authorization
|
||||
end
|
||||
|
||||
##
|
||||
# Default Faraday/HTTP connection.
|
||||
#
|
||||
# @return [Faraday::Connection]
|
||||
attr_accessor :connection
|
||||
|
||||
##
|
||||
# The setting that controls whether or not the api client attempts to
|
||||
# refresh authorization when a 401 is hit in #execute.
|
||||
#
|
||||
# @return [Boolean]
|
||||
attr_accessor :auto_refresh_token
|
||||
|
||||
##
|
||||
# The application's API key issued by the API console.
|
||||
#
|
||||
# @return [String] The API key.
|
||||
attr_accessor :key
|
||||
|
||||
##
|
||||
# The IP address of the user this request is being performed on behalf of.
|
||||
#
|
||||
# @return [String] The user's IP address.
|
||||
attr_accessor :user_ip
|
||||
|
||||
##
|
||||
# The user agent used by the client.
|
||||
#
|
||||
# @return [String]
|
||||
# The user agent string used in the User-Agent header.
|
||||
attr_accessor :user_agent
|
||||
|
||||
##
|
||||
# The API hostname used by the client.
|
||||
#
|
||||
# @return [String]
|
||||
# The API hostname. Should almost always be 'www.googleapis.com'.
|
||||
attr_accessor :host
|
||||
|
||||
##
|
||||
# The port number used by the client.
|
||||
#
|
||||
# @return [String]
|
||||
# The port number. Should almost always be 443.
|
||||
attr_accessor :port
|
||||
|
||||
##
|
||||
# The base path used by the client for discovery.
|
||||
#
|
||||
# @return [String]
|
||||
# The base path. Should almost always be '/discovery/v1'.
|
||||
attr_accessor :discovery_path
|
||||
|
||||
##
|
||||
# Number of times to retry on recoverable errors
|
||||
#
|
||||
# @return [FixNum]
|
||||
# Number of retries
|
||||
attr_accessor :retries
|
||||
|
||||
##
|
||||
# Whether or not an expired auth token should be re-acquired
|
||||
# (and the operation retried) regardless of retries setting
|
||||
# @return [Boolean]
|
||||
# Auto retry on auth expiry
|
||||
attr_accessor :expired_auth_retry
|
||||
|
||||
##
|
||||
# Returns the URI for the directory document.
|
||||
#
|
||||
# @return [Addressable::URI] The URI of the directory document.
|
||||
def directory_uri
|
||||
return resolve_uri(self.discovery_path + '/apis')
|
||||
end
|
||||
|
||||
##
|
||||
# Manually registers a URI as a discovery document for a specific version
|
||||
# of an API.
|
||||
#
|
||||
# @param [String, Symbol] api The API name.
|
||||
# @param [String] version The desired version of the API.
|
||||
# @param [Addressable::URI] uri The URI of the discovery document.
|
||||
# @return [Google::APIClient::API] The service object.
|
||||
def register_discovery_uri(api, version, uri)
|
||||
api = api.to_s
|
||||
version = version || 'v1'
|
||||
@discovery_uris["#{api}:#{version}"] = uri
|
||||
discovered_api(api, version)
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the URI for the discovery document.
|
||||
#
|
||||
# @param [String, Symbol] api The API name.
|
||||
# @param [String] version The desired version of the API.
|
||||
# @return [Addressable::URI] The URI of the discovery document.
|
||||
def discovery_uri(api, version=nil)
|
||||
api = api.to_s
|
||||
version = version || 'v1'
|
||||
return @discovery_uris["#{api}:#{version}"] ||= (
|
||||
resolve_uri(
|
||||
self.discovery_path + '/apis/{api}/{version}/rest',
|
||||
'api' => api,
|
||||
'version' => version
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
##
|
||||
# Manually registers a pre-loaded discovery document for a specific version
|
||||
# of an API.
|
||||
#
|
||||
# @param [String, Symbol] api The API name.
|
||||
# @param [String] version The desired version of the API.
|
||||
# @param [String, StringIO] discovery_document
|
||||
# The contents of the discovery document.
|
||||
# @return [Google::APIClient::API] The service object.
|
||||
def register_discovery_document(api, version, discovery_document)
|
||||
api = api.to_s
|
||||
version = version || 'v1'
|
||||
if discovery_document.kind_of?(StringIO)
|
||||
discovery_document.rewind
|
||||
discovery_document = discovery_document.string
|
||||
elsif discovery_document.respond_to?(:to_str)
|
||||
discovery_document = discovery_document.to_str
|
||||
else
|
||||
raise TypeError,
|
||||
"Expected String or StringIO, got #{discovery_document.class}."
|
||||
end
|
||||
@discovery_documents["#{api}:#{version}"] =
|
||||
MultiJson.load(discovery_document)
|
||||
discovered_api(api, version)
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the parsed directory document.
|
||||
#
|
||||
# @return [Hash] The parsed JSON from the directory document.
|
||||
def directory_document
|
||||
return @directory_document ||= (begin
|
||||
response = self.execute!(
|
||||
:http_method => :get,
|
||||
:uri => self.directory_uri,
|
||||
:authenticated => false
|
||||
)
|
||||
response.data
|
||||
end)
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the parsed discovery document.
|
||||
#
|
||||
# @param [String, Symbol] api The API name.
|
||||
# @param [String] version The desired version of the API.
|
||||
# @return [Hash] The parsed JSON from the discovery document.
|
||||
def discovery_document(api, version=nil)
|
||||
api = api.to_s
|
||||
version = version || 'v1'
|
||||
return @discovery_documents["#{api}:#{version}"] ||= (begin
|
||||
response = self.execute!(
|
||||
:http_method => :get,
|
||||
:uri => self.discovery_uri(api, version),
|
||||
:authenticated => false
|
||||
)
|
||||
response.data
|
||||
end)
|
||||
end
|
||||
|
||||
##
|
||||
# Returns all APIs published in the directory document.
|
||||
#
|
||||
# @return [Array] The list of available APIs.
|
||||
def discovered_apis
|
||||
@directory_apis ||= (begin
|
||||
document_base = self.directory_uri
|
||||
if self.directory_document && self.directory_document['items']
|
||||
self.directory_document['items'].map do |discovery_document|
|
||||
Google::APIClient::API.new(
|
||||
document_base,
|
||||
discovery_document
|
||||
)
|
||||
end
|
||||
else
|
||||
[]
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the service object for a given service name and service version.
|
||||
#
|
||||
# @param [String, Symbol] api The API name.
|
||||
# @param [String] version The desired version of the API.
|
||||
#
|
||||
# @return [Google::APIClient::API] The service object.
|
||||
def discovered_api(api, version=nil)
|
||||
if !api.kind_of?(String) && !api.kind_of?(Symbol)
|
||||
raise TypeError,
|
||||
"Expected String or Symbol, got #{api.class}."
|
||||
end
|
||||
api = api.to_s
|
||||
version = version || 'v1'
|
||||
return @discovered_apis["#{api}:#{version}"] ||= begin
|
||||
document_base = self.discovery_uri(api, version)
|
||||
discovery_document = self.discovery_document(api, version)
|
||||
if document_base && discovery_document
|
||||
Google::APIClient::API.new(
|
||||
document_base,
|
||||
discovery_document
|
||||
)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the method object for a given RPC name and service version.
|
||||
#
|
||||
# @param [String, Symbol] rpc_name The RPC name of the desired method.
|
||||
# @param [String, Symbol] api The API the method is within.
|
||||
# @param [String] version The desired version of the API.
|
||||
#
|
||||
# @return [Google::APIClient::Method] The method object.
|
||||
def discovered_method(rpc_name, api, version=nil)
|
||||
if !rpc_name.kind_of?(String) && !rpc_name.kind_of?(Symbol)
|
||||
raise TypeError,
|
||||
"Expected String or Symbol, got #{rpc_name.class}."
|
||||
end
|
||||
rpc_name = rpc_name.to_s
|
||||
api = api.to_s
|
||||
version = version || 'v1'
|
||||
service = self.discovered_api(api, version)
|
||||
if service.to_h[rpc_name]
|
||||
return service.to_h[rpc_name]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the service object with the highest version number.
|
||||
#
|
||||
# @note <em>Warning</em>: This method should be used with great care.
|
||||
# As APIs are updated, minor differences between versions may cause
|
||||
# incompatibilities. Requesting a specific version will avoid this issue.
|
||||
#
|
||||
# @param [String, Symbol] api The name of the service.
|
||||
#
|
||||
# @return [Google::APIClient::API] The service object.
|
||||
def preferred_version(api)
|
||||
if !api.kind_of?(String) && !api.kind_of?(Symbol)
|
||||
raise TypeError,
|
||||
"Expected String or Symbol, got #{api.class}."
|
||||
end
|
||||
api = api.to_s
|
||||
return self.discovered_apis.detect do |a|
|
||||
a.name == api && a.preferred == true
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Verifies an ID token against a server certificate. Used to ensure that
|
||||
# an ID token supplied by an untrusted client-side mechanism is valid.
|
||||
# Raises an error if the token is invalid or missing.
|
||||
#
|
||||
# @deprecated Use the google-id-token gem for verifying JWTs
|
||||
def verify_id_token!
|
||||
require 'jwt'
|
||||
require 'openssl'
|
||||
@certificates ||= {}
|
||||
if !self.authorization.respond_to?(:id_token)
|
||||
raise ArgumentError, (
|
||||
"Current authorization mechanism does not support ID tokens: " +
|
||||
"#{self.authorization.class.to_s}"
|
||||
)
|
||||
elsif !self.authorization.id_token
|
||||
raise ArgumentError, (
|
||||
"Could not verify ID token, ID token missing. " +
|
||||
"Scopes were: #{self.authorization.scope.inspect}"
|
||||
)
|
||||
else
|
||||
check_cached_certs = lambda do
|
||||
valid = false
|
||||
for _key, cert in @certificates
|
||||
begin
|
||||
self.authorization.decoded_id_token(cert.public_key)
|
||||
valid = true
|
||||
rescue JWT::DecodeError, Signet::UnsafeOperationError
|
||||
# Expected exception. Ignore, ID token has not been validated.
|
||||
end
|
||||
end
|
||||
valid
|
||||
end
|
||||
if check_cached_certs.call()
|
||||
return true
|
||||
end
|
||||
response = self.execute!(
|
||||
:http_method => :get,
|
||||
:uri => 'https://www.googleapis.com/oauth2/v1/certs',
|
||||
:authenticated => false
|
||||
)
|
||||
@certificates.merge!(
|
||||
Hash[MultiJson.load(response.body).map do |key, cert|
|
||||
[key, OpenSSL::X509::Certificate.new(cert)]
|
||||
end]
|
||||
)
|
||||
if check_cached_certs.call()
|
||||
return true
|
||||
else
|
||||
raise InvalidIDTokenError,
|
||||
"Could not verify ID token against any available certificate."
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
##
|
||||
# Generates a request.
|
||||
#
|
||||
# @option options [Google::APIClient::Method] :api_method
|
||||
# The method object or the RPC name of the method being executed.
|
||||
# @option options [Hash, Array] :parameters
|
||||
# The parameters to send to the method.
|
||||
# @option options [Hash, Array] :headers The HTTP headers for the request.
|
||||
# @option options [String] :body The body of the request.
|
||||
# @option options [String] :version ("v1")
|
||||
# The service version. Only used if `api_method` is a `String`.
|
||||
# @option options [#generate_authenticated_request] :authorization
|
||||
# The authorization mechanism for the response. Used only if
|
||||
# `:authenticated` is `true`.
|
||||
# @option options [TrueClass, FalseClass] :authenticated (true)
|
||||
# `true` if the request must be signed or somehow
|
||||
# authenticated, `false` otherwise.
|
||||
#
|
||||
# @return [Google::APIClient::Reference] The generated request.
|
||||
#
|
||||
# @example
|
||||
# request = client.generate_request(
|
||||
# :api_method => 'plus.activities.list',
|
||||
# :parameters =>
|
||||
# {'collection' => 'public', 'userId' => 'me'}
|
||||
# )
|
||||
def generate_request(options={})
|
||||
options = {
|
||||
:api_client => self
|
||||
}.merge(options)
|
||||
return Google::APIClient::Request.new(options)
|
||||
end
|
||||
|
||||
##
|
||||
# Executes a request, wrapping it in a Result object.
|
||||
#
|
||||
# @param [Google::APIClient::Request, Hash, Array] params
|
||||
# Either a Google::APIClient::Request, a Hash, or an Array.
|
||||
#
|
||||
# If a Google::APIClient::Request, no other parameters are expected.
|
||||
#
|
||||
# If a Hash, the below parameters are handled. If an Array, the
|
||||
# parameters are assumed to be in the below order:
|
||||
#
|
||||
# - (Google::APIClient::Method) api_method:
|
||||
# The method object or the RPC name of the method being executed.
|
||||
# - (Hash, Array) parameters:
|
||||
# The parameters to send to the method.
|
||||
# - (String) body: The body of the request.
|
||||
# - (Hash, Array) headers: The HTTP headers for the request.
|
||||
# - (Hash) options: A set of options for the request, of which:
|
||||
# - (#generate_authenticated_request) :authorization (default: true) -
|
||||
# The authorization mechanism for the response. Used only if
|
||||
# `:authenticated` is `true`.
|
||||
# - (TrueClass, FalseClass) :authenticated (default: true) -
|
||||
# `true` if the request must be signed or somehow
|
||||
# authenticated, `false` otherwise.
|
||||
# - (TrueClass, FalseClass) :gzip (default: true) -
|
||||
# `true` if gzip enabled, `false` otherwise.
|
||||
# - (FixNum) :retries -
|
||||
# # of times to retry on recoverable errors
|
||||
#
|
||||
# @return [Google::APIClient::Result] The result from the API, nil if batch.
|
||||
#
|
||||
# @example
|
||||
# result = client.execute(batch_request)
|
||||
#
|
||||
# @example
|
||||
# plus = client.discovered_api('plus')
|
||||
# result = client.execute(
|
||||
# :api_method => plus.activities.list,
|
||||
# :parameters => {'collection' => 'public', 'userId' => 'me'}
|
||||
# )
|
||||
#
|
||||
# @see Google::APIClient#generate_request
|
||||
def execute!(*params)
|
||||
if params.first.kind_of?(Google::APIClient::Request)
|
||||
request = params.shift
|
||||
options = params.shift || {}
|
||||
else
|
||||
# This block of code allows us to accept multiple parameter passing
|
||||
# styles, and maintaining some backwards compatibility.
|
||||
#
|
||||
# Note: I'm extremely tempted to deprecate this style of execute call.
|
||||
if params.last.respond_to?(:to_hash) && params.size == 1
|
||||
options = params.pop
|
||||
else
|
||||
options = {}
|
||||
end
|
||||
|
||||
options[:api_method] = params.shift if params.size > 0
|
||||
options[:parameters] = params.shift if params.size > 0
|
||||
options[:body] = params.shift if params.size > 0
|
||||
options[:headers] = params.shift if params.size > 0
|
||||
options.update(params.shift) if params.size > 0
|
||||
request = self.generate_request(options)
|
||||
end
|
||||
|
||||
request.headers['User-Agent'] ||= '' + self.user_agent unless self.user_agent.nil?
|
||||
request.headers['Accept-Encoding'] ||= 'gzip' unless options[:gzip] == false
|
||||
request.headers['Content-Type'] ||= ''
|
||||
request.parameters['key'] ||= self.key unless self.key.nil?
|
||||
request.parameters['userIp'] ||= self.user_ip unless self.user_ip.nil?
|
||||
|
||||
connection = options[:connection] || self.connection
|
||||
request.authorization = options[:authorization] || self.authorization unless options[:authenticated] == false
|
||||
|
||||
tries = 1 + (options[:retries] || self.retries)
|
||||
attempt = 0
|
||||
|
||||
Retriable.retriable :tries => tries,
|
||||
:on => [TransmissionError],
|
||||
:on_retry => client_error_handler,
|
||||
:interval => lambda {|attempts| (2 ** attempts) + rand} do
|
||||
attempt += 1
|
||||
|
||||
# This 2nd level retriable only catches auth errors, and supports 1 retry, which allows
|
||||
# auth to be re-attempted without having to retry all sorts of other failures like
|
||||
# NotFound, etc
|
||||
Retriable.retriable :tries => ((expired_auth_retry || tries > 1) && attempt == 1) ? 2 : 1,
|
||||
:on => [AuthorizationError],
|
||||
:on_retry => authorization_error_handler(request.authorization) do
|
||||
result = request.send(connection, true)
|
||||
|
||||
case result.status
|
||||
when 200...300
|
||||
result
|
||||
when 301, 302, 303, 307
|
||||
request = generate_request(request.to_hash.merge({
|
||||
:uri => result.headers['location'],
|
||||
:api_method => nil
|
||||
}))
|
||||
raise RedirectError.new(result.headers['location'], result)
|
||||
when 401
|
||||
raise AuthorizationError.new(result.error_message || 'Invalid/Expired Authentication', result)
|
||||
when 400, 402...500
|
||||
raise ClientError.new(result.error_message || "A client error has occurred", result)
|
||||
when 500...600
|
||||
raise ServerError.new(result.error_message || "A server error has occurred", result)
|
||||
else
|
||||
raise TransmissionError.new(result.error_message || "A transmission error has occurred", result)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Same as Google::APIClient#execute!, but does not raise an exception for
|
||||
# normal API errros.
|
||||
#
|
||||
# @see Google::APIClient#execute
|
||||
def execute(*params)
|
||||
begin
|
||||
return self.execute!(*params)
|
||||
rescue TransmissionError => e
|
||||
return e.result
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
##
|
||||
# Resolves a URI template against the client's configured base.
|
||||
#
|
||||
# @api private
|
||||
# @param [String, Addressable::URI, Addressable::Template] template
|
||||
# The template to resolve.
|
||||
# @param [Hash] mapping The mapping that corresponds to the template.
|
||||
# @return [Addressable::URI] The expanded URI.
|
||||
def resolve_uri(template, mapping={})
|
||||
@base_uri ||= Addressable::URI.new(
|
||||
:scheme => 'https',
|
||||
:host => self.host,
|
||||
:port => self.port
|
||||
).normalize
|
||||
template = if template.kind_of?(Addressable::Template)
|
||||
template.pattern
|
||||
elsif template.respond_to?(:to_str)
|
||||
template.to_str
|
||||
else
|
||||
raise TypeError,
|
||||
"Expected String, Addressable::URI, or Addressable::Template, " +
|
||||
"got #{template.class}."
|
||||
end
|
||||
return Addressable::Template.new(@base_uri + template).expand(mapping)
|
||||
end
|
||||
|
||||
|
||||
##
|
||||
# Returns on proc for special processing of retries for authorization errors
|
||||
# Only 401s should be retried and only if the credentials are refreshable
|
||||
#
|
||||
# @param [#fetch_access_token!] authorization
|
||||
# OAuth 2 credentials
|
||||
# @return [Proc]
|
||||
def authorization_error_handler(authorization)
|
||||
can_refresh = authorization.respond_to?(:refresh_token) && auto_refresh_token
|
||||
Proc.new do |exception, tries|
|
||||
next unless exception.kind_of?(AuthorizationError)
|
||||
if can_refresh
|
||||
begin
|
||||
logger.debug("Attempting refresh of access token & retry of request")
|
||||
authorization.fetch_access_token!
|
||||
next
|
||||
rescue Signet::AuthorizationError
|
||||
end
|
||||
end
|
||||
raise exception
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Returns on proc for special processing of retries as not all client errors
|
||||
# are recoverable. Only 401s should be retried (via authorization_error_handler)
|
||||
#
|
||||
# @return [Proc]
|
||||
def client_error_handler
|
||||
Proc.new do |exception, tries|
|
||||
raise exception if exception.kind_of?(ClientError)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -1,59 +0,0 @@
|
|||
# Copyright 2013 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'signet/oauth_2/client'
|
||||
require_relative 'storage'
|
||||
require_relative 'storages/file_store'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
|
||||
##
|
||||
# Represents cached OAuth 2 tokens stored on local disk in a
|
||||
# JSON serialized file. Meant to resemble the serialized format
|
||||
# http://google-api-python-client.googlecode.com/hg/docs/epy/oauth2client.file.Storage-class.html
|
||||
#
|
||||
# @deprecated
|
||||
# Use {Google::APIClient::Storage} and {Google::APIClient::FileStore} instead
|
||||
#
|
||||
class FileStorage
|
||||
|
||||
attr_accessor :storage
|
||||
|
||||
def initialize(path)
|
||||
store = Google::APIClient::FileStore.new(path)
|
||||
@storage = Google::APIClient::Storage.new(store)
|
||||
@storage.authorize
|
||||
end
|
||||
|
||||
def load_credentials
|
||||
storage.authorize
|
||||
end
|
||||
|
||||
def authorization
|
||||
storage.authorization
|
||||
end
|
||||
|
||||
##
|
||||
# Write the credentials to the specified file.
|
||||
#
|
||||
# @param [Signet::OAuth2::Client] authorization
|
||||
# Optional authorization instance. If not provided, the authorization
|
||||
# already associated with this instance will be written.
|
||||
def write_credentials(auth=nil)
|
||||
storage.write_credentials(auth)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,126 +0,0 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'jwt'
|
||||
require 'signet/oauth_2/client'
|
||||
require 'delegate'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
##
|
||||
# Generates access tokens using the JWT assertion profile. Requires a
|
||||
# service account & access to the private key.
|
||||
#
|
||||
# @example Using Signet
|
||||
#
|
||||
# key = Google::APIClient::KeyUtils.load_from_pkcs12('client.p12', 'notasecret')
|
||||
# client.authorization = Signet::OAuth2::Client.new(
|
||||
# :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
|
||||
# :audience => 'https://accounts.google.com/o/oauth2/token',
|
||||
# :scope => 'https://www.googleapis.com/auth/prediction',
|
||||
# :issuer => '123456-abcdef@developer.gserviceaccount.com',
|
||||
# :signing_key => key)
|
||||
# client.authorization.fetch_access_token!
|
||||
# client.execute(...)
|
||||
#
|
||||
# @deprecated
|
||||
# Service accounts are now supported directly in Signet
|
||||
# @see https://developers.google.com/accounts/docs/OAuth2ServiceAccount
|
||||
class JWTAsserter
|
||||
# @return [String] ID/email of the issuing party
|
||||
attr_accessor :issuer
|
||||
# @return [Fixnum] How long, in seconds, the assertion is valid for
|
||||
attr_accessor :expiry
|
||||
# @return [Fixnum] Seconds to expand the issued at/expiry window to account for clock skew
|
||||
attr_accessor :skew
|
||||
# @return [String] Scopes to authorize
|
||||
attr_reader :scope
|
||||
# @return [String,OpenSSL::PKey] key for signing assertions
|
||||
attr_writer :key
|
||||
# @return [String] Algorithm used for signing
|
||||
attr_accessor :algorithm
|
||||
|
||||
##
|
||||
# Initializes the asserter for a service account.
|
||||
#
|
||||
# @param [String] issuer
|
||||
# Name/ID of the client issuing the assertion
|
||||
# @param [String, Array] scope
|
||||
# Scopes to authorize. May be a space delimited string or array of strings
|
||||
# @param [String,OpenSSL::PKey] key
|
||||
# Key for signing assertions
|
||||
# @param [String] algorithm
|
||||
# Algorithm to use, either 'RS256' for RSA with SHA-256
|
||||
# or 'HS256' for HMAC with SHA-256
|
||||
def initialize(issuer, scope, key, algorithm = "RS256")
|
||||
self.issuer = issuer
|
||||
self.scope = scope
|
||||
self.expiry = 60 # 1 min default
|
||||
self.skew = 60
|
||||
self.key = key
|
||||
self.algorithm = algorithm
|
||||
end
|
||||
|
||||
##
|
||||
# Set the scopes to authorize
|
||||
#
|
||||
# @param [String, Array] new_scope
|
||||
# Scopes to authorize. May be a space delimited string or array of strings
|
||||
def scope=(new_scope)
|
||||
case new_scope
|
||||
when Array
|
||||
@scope = new_scope.join(' ')
|
||||
when String
|
||||
@scope = new_scope
|
||||
when nil
|
||||
@scope = ''
|
||||
else
|
||||
raise TypeError, "Expected Array or String, got #{new_scope.class}"
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Request a new access token.
|
||||
#
|
||||
# @param [String] person
|
||||
# Email address of a user, if requesting a token to act on their behalf
|
||||
# @param [Hash] options
|
||||
# Pass through to Signet::OAuth2::Client.fetch_access_token
|
||||
# @return [Signet::OAuth2::Client] Access token
|
||||
#
|
||||
# @see Signet::OAuth2::Client.fetch_access_token!
|
||||
def authorize(person = nil, options={})
|
||||
authorization = self.to_authorization(person)
|
||||
authorization.fetch_access_token!(options)
|
||||
return authorization
|
||||
end
|
||||
|
||||
##
|
||||
# Builds a Signet OAuth2 client
|
||||
#
|
||||
# @return [Signet::OAuth2::Client] Access token
|
||||
def to_authorization(person = nil)
|
||||
return Signet::OAuth2::Client.new(
|
||||
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
|
||||
:audience => 'https://accounts.google.com/o/oauth2/token',
|
||||
:scope => self.scope,
|
||||
:issuer => @issuer,
|
||||
:signing_key => @key,
|
||||
:signing_algorithm => @algorithm,
|
||||
:person => person
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,93 +0,0 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
##
|
||||
# Helper for loading keys from the PKCS12 files downloaded when
|
||||
# setting up service accounts at the APIs Console.
|
||||
#
|
||||
module KeyUtils
|
||||
##
|
||||
# Loads a key from PKCS12 file, assuming a single private key
|
||||
# is present.
|
||||
#
|
||||
# @param [String] keyfile
|
||||
# Path of the PKCS12 file to load. If not a path to an actual file,
|
||||
# assumes the string is the content of the file itself.
|
||||
# @param [String] passphrase
|
||||
# Passphrase for unlocking the private key
|
||||
#
|
||||
# @return [OpenSSL::PKey] The private key for signing assertions.
|
||||
def self.load_from_pkcs12(keyfile, passphrase)
|
||||
load_key(keyfile, passphrase) do |content, pass_phrase|
|
||||
OpenSSL::PKCS12.new(content, pass_phrase).key
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
##
|
||||
# Loads a key from a PEM file.
|
||||
#
|
||||
# @param [String] keyfile
|
||||
# Path of the PEM file to load. If not a path to an actual file,
|
||||
# assumes the string is the content of the file itself.
|
||||
# @param [String] passphrase
|
||||
# Passphrase for unlocking the private key
|
||||
#
|
||||
# @return [OpenSSL::PKey] The private key for signing assertions.
|
||||
#
|
||||
def self.load_from_pem(keyfile, passphrase)
|
||||
load_key(keyfile, passphrase) do | content, pass_phrase|
|
||||
OpenSSL::PKey::RSA.new(content, pass_phrase)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
##
|
||||
# Helper for loading keys from file or memory. Accepts a block
|
||||
# to handle the specific file format.
|
||||
#
|
||||
# @param [String] keyfile
|
||||
# Path of thefile to load. If not a path to an actual file,
|
||||
# assumes the string is the content of the file itself.
|
||||
# @param [String] passphrase
|
||||
# Passphrase for unlocking the private key
|
||||
#
|
||||
# @yield [String, String]
|
||||
# Key file & passphrase to extract key from
|
||||
# @yieldparam [String] keyfile
|
||||
# Contents of the file
|
||||
# @yieldparam [String] passphrase
|
||||
# Passphrase to unlock key
|
||||
# @yieldreturn [OpenSSL::PKey]
|
||||
# Private key
|
||||
#
|
||||
# @return [OpenSSL::PKey] The private key for signing assertions.
|
||||
def self.load_key(keyfile, passphrase, &block)
|
||||
begin
|
||||
begin
|
||||
content = File.open(keyfile, 'rb') { |io| io.read }
|
||||
rescue
|
||||
content = keyfile
|
||||
end
|
||||
block.call(content, passphrase)
|
||||
rescue OpenSSL::OpenSSLError
|
||||
raise ArgumentError.new("Invalid keyfile or passphrase")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,41 +0,0 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'google/api_client/auth/key_utils'
|
||||
module Google
|
||||
class APIClient
|
||||
##
|
||||
# Helper for loading keys from the PKCS12 files downloaded when
|
||||
# setting up service accounts at the APIs Console.
|
||||
#
|
||||
module PKCS12
|
||||
##
|
||||
# Loads a key from PKCS12 file, assuming a single private key
|
||||
# is present.
|
||||
#
|
||||
# @param [String] keyfile
|
||||
# Path of the PKCS12 file to load. If not a path to an actual file,
|
||||
# assumes the string is the content of the file itself.
|
||||
# @param [String] passphrase
|
||||
# Passphrase for unlocking the private key
|
||||
#
|
||||
# @return [OpenSSL::PKey] The private key for signing assertions.
|
||||
# @deprecated
|
||||
# Use {Google::APIClient::KeyUtils} instead
|
||||
def self.load_key(keyfile, passphrase)
|
||||
KeyUtils.load_from_pkcs12(keyfile, passphrase)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,326 +0,0 @@
|
|||
# Copyright 2012 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'addressable/uri'
|
||||
require 'google/api_client/reference'
|
||||
require 'securerandom'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
|
||||
##
|
||||
# Helper class to contain a response to an individual batched call.
|
||||
#
|
||||
# @api private
|
||||
class BatchedCallResponse
|
||||
# @return [String] UUID of the call
|
||||
attr_reader :call_id
|
||||
# @return [Fixnum] HTTP status code
|
||||
attr_accessor :status
|
||||
# @return [Hash] HTTP response headers
|
||||
attr_accessor :headers
|
||||
# @return [String] HTTP response body
|
||||
attr_accessor :body
|
||||
|
||||
##
|
||||
# Initialize the call response
|
||||
#
|
||||
# @param [String] call_id
|
||||
# UUID of the original call
|
||||
# @param [Fixnum] status
|
||||
# HTTP status
|
||||
# @param [Hash] headers
|
||||
# HTTP response headers
|
||||
# @param [#read, #to_str] body
|
||||
# Response body
|
||||
def initialize(call_id, status = nil, headers = nil, body = nil)
|
||||
@call_id, @status, @headers, @body = call_id, status, headers, body
|
||||
end
|
||||
end
|
||||
|
||||
# Wraps multiple API calls into a single over-the-wire HTTP request.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# client = Google::APIClient.new
|
||||
# urlshortener = client.discovered_api('urlshortener')
|
||||
# batch = Google::APIClient::BatchRequest.new do |result|
|
||||
# puts result.data
|
||||
# end
|
||||
#
|
||||
# batch.add(:api_method => urlshortener.url.insert, :body_object => { 'longUrl' => 'http://example.com/foo' })
|
||||
# batch.add(:api_method => urlshortener.url.insert, :body_object => { 'longUrl' => 'http://example.com/bar' })
|
||||
#
|
||||
# client.execute(batch)
|
||||
#
|
||||
class BatchRequest < Request
|
||||
BATCH_BOUNDARY = "-----------RubyApiBatchRequest".freeze
|
||||
|
||||
# @api private
|
||||
# @return [Array<(String,Google::APIClient::Request,Proc)] List of API calls in the batch
|
||||
attr_reader :calls
|
||||
|
||||
##
|
||||
# Creates a new batch request.
|
||||
#
|
||||
# @param [Hash] options
|
||||
# Set of options for this request.
|
||||
# @param [Proc] block
|
||||
# Callback for every call's response. Won't be called if a call defined
|
||||
# a callback of its own.
|
||||
#
|
||||
# @return [Google::APIClient::BatchRequest]
|
||||
# The constructed object.
|
||||
#
|
||||
# @yield [Google::APIClient::Result]
|
||||
# block to be called when result ready
|
||||
def initialize(options = {}, &block)
|
||||
@calls = []
|
||||
@global_callback = nil
|
||||
@global_callback = block if block_given?
|
||||
@last_auto_id = 0
|
||||
|
||||
@base_id = SecureRandom.uuid
|
||||
|
||||
options[:uri] ||= 'https://www.googleapis.com/batch'
|
||||
options[:http_method] ||= 'POST'
|
||||
|
||||
super options
|
||||
end
|
||||
|
||||
##
|
||||
# Add a new call to the batch request.
|
||||
# Each call must have its own call ID; if not provided, one will
|
||||
# automatically be generated, avoiding collisions. If duplicate call IDs
|
||||
# are provided, an error will be thrown.
|
||||
#
|
||||
# @param [Hash, Google::APIClient::Request] call
|
||||
# the call to be added.
|
||||
# @param [String] call_id
|
||||
# the ID to be used for this call. Must be unique
|
||||
# @param [Proc] block
|
||||
# callback for this call's response.
|
||||
#
|
||||
# @return [Google::APIClient::BatchRequest]
|
||||
# the BatchRequest, for chaining
|
||||
#
|
||||
# @yield [Google::APIClient::Result]
|
||||
# block to be called when result ready
|
||||
def add(call, call_id = nil, &block)
|
||||
unless call.kind_of?(Google::APIClient::Reference)
|
||||
call = Google::APIClient::Reference.new(call)
|
||||
end
|
||||
call_id ||= new_id
|
||||
if @calls.assoc(call_id)
|
||||
raise BatchError,
|
||||
'A call with this ID already exists: %s' % call_id
|
||||
end
|
||||
callback = block_given? ? block : @global_callback
|
||||
@calls << [call_id, call, callback]
|
||||
return self
|
||||
end
|
||||
|
||||
##
|
||||
# Processes the HTTP response to the batch request, issuing callbacks.
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [Faraday::Response] response
|
||||
# the HTTP response.
|
||||
def process_http_response(response)
|
||||
content_type = find_header('Content-Type', response.headers)
|
||||
m = /.*boundary=(.+)/.match(content_type)
|
||||
if m
|
||||
boundary = m[1]
|
||||
parts = response.body.split(/--#{Regexp.escape(boundary)}/)
|
||||
parts = parts[1...-1]
|
||||
parts.each do |part|
|
||||
call_response = deserialize_call_response(part)
|
||||
_, call, callback = @calls.assoc(call_response.call_id)
|
||||
result = Google::APIClient::Result.new(call, call_response)
|
||||
callback.call(result) if callback
|
||||
end
|
||||
end
|
||||
Google::APIClient::Result.new(self, response)
|
||||
end
|
||||
|
||||
##
|
||||
# Return the request body for the BatchRequest's HTTP request.
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @return [String]
|
||||
# the request body.
|
||||
def to_http_request
|
||||
if @calls.nil? || @calls.empty?
|
||||
raise BatchError, 'Cannot make an empty batch request'
|
||||
end
|
||||
parts = @calls.map {|(call_id, call, _callback)| serialize_call(call_id, call)}
|
||||
build_multipart(parts, 'multipart/mixed', BATCH_BOUNDARY)
|
||||
super
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
|
||||
##
|
||||
# Helper method to find a header from its name, regardless of case.
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [String] name
|
||||
# the name of the header to find.
|
||||
# @param [Hash] headers
|
||||
# the hash of headers and their values.
|
||||
#
|
||||
# @return [String]
|
||||
# the value of the desired header.
|
||||
def find_header(name, headers)
|
||||
_, header = headers.detect do |h, v|
|
||||
h.downcase == name.downcase
|
||||
end
|
||||
return header
|
||||
end
|
||||
|
||||
##
|
||||
# Create a new call ID. Uses an auto-incrementing, conflict-avoiding ID.
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @return [String]
|
||||
# the new, unique ID.
|
||||
def new_id
|
||||
@last_auto_id += 1
|
||||
while @calls.assoc(@last_auto_id)
|
||||
@last_auto_id += 1
|
||||
end
|
||||
return @last_auto_id.to_s
|
||||
end
|
||||
|
||||
##
|
||||
# Convert a Content-ID header value to an id. Presumes the Content-ID
|
||||
# header conforms to the format that id_to_header() returns.
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [String] header
|
||||
# Content-ID header value.
|
||||
#
|
||||
# @return [String]
|
||||
# The extracted ID value.
|
||||
def header_to_id(header)
|
||||
if !header.start_with?('<') || !header.end_with?('>') ||
|
||||
!header.include?('+')
|
||||
raise BatchError, 'Invalid value for Content-ID: "%s"' % header
|
||||
end
|
||||
|
||||
_base, call_id = header[1...-1].split('+')
|
||||
return Addressable::URI.unencode(call_id)
|
||||
end
|
||||
|
||||
##
|
||||
# Auxiliary method to split the headers from the body in an HTTP response.
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [String] response
|
||||
# the response to parse.
|
||||
#
|
||||
# @return [Array<Hash>, String]
|
||||
# the headers and the body, separately.
|
||||
def split_headers_and_body(response)
|
||||
headers = {}
|
||||
payload = response.lstrip
|
||||
while payload
|
||||
line, payload = payload.split("\n", 2)
|
||||
line.sub!(/\s+\z/, '')
|
||||
break if line.empty?
|
||||
match = /\A([^:]+):\s*/.match(line)
|
||||
if match
|
||||
headers[match[1]] = match.post_match
|
||||
else
|
||||
raise BatchError, 'Invalid header line in response: %s' % line
|
||||
end
|
||||
end
|
||||
return headers, payload
|
||||
end
|
||||
|
||||
##
|
||||
# Convert a single batched response into a BatchedCallResponse object.
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [String] call_response
|
||||
# the request to deserialize.
|
||||
#
|
||||
# @return [Google::APIClient::BatchedCallResponse]
|
||||
# the parsed and converted response.
|
||||
def deserialize_call_response(call_response)
|
||||
outer_headers, outer_body = split_headers_and_body(call_response)
|
||||
status_line, payload = outer_body.split("\n", 2)
|
||||
_protocol, status, _reason = status_line.split(' ', 3)
|
||||
|
||||
headers, body = split_headers_and_body(payload)
|
||||
content_id = find_header('Content-ID', outer_headers)
|
||||
call_id = header_to_id(content_id)
|
||||
return BatchedCallResponse.new(call_id, status.to_i, headers, body)
|
||||
end
|
||||
|
||||
##
|
||||
# Serialize a single batched call for assembling the multipart message
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [Google::APIClient::Request] call
|
||||
# the call to serialize.
|
||||
#
|
||||
# @return [Faraday::UploadIO]
|
||||
# the serialized request
|
||||
def serialize_call(call_id, call)
|
||||
method, uri, headers, body = call.to_http_request
|
||||
request = "#{method.to_s.upcase} #{Addressable::URI.parse(uri).request_uri} HTTP/1.1"
|
||||
headers.each do |header, value|
|
||||
request << "\r\n%s: %s" % [header, value]
|
||||
end
|
||||
if body
|
||||
# TODO - CompositeIO if body is a stream
|
||||
request << "\r\n\r\n"
|
||||
if body.respond_to?(:read)
|
||||
request << body.read
|
||||
else
|
||||
request << body.to_s
|
||||
end
|
||||
end
|
||||
Faraday::UploadIO.new(StringIO.new(request), 'application/http', 'ruby-api-request', 'Content-ID' => id_to_header(call_id))
|
||||
end
|
||||
|
||||
##
|
||||
# Convert an id to a Content-ID header value.
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [String] call_id
|
||||
# identifier of individual call.
|
||||
#
|
||||
# @return [String]
|
||||
# A Content-ID header with the call_id encoded into it. A UUID is
|
||||
# prepended to the value because Content-ID headers are supposed to be
|
||||
# universally unique.
|
||||
def id_to_header(call_id)
|
||||
return '<%s+%s>' % [@base_id, Addressable::URI.encode(call_id)]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,33 +0,0 @@
|
|||
require 'faraday'
|
||||
require 'zlib'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
class Charset < Faraday::Response::Middleware
|
||||
include Google::APIClient::Logging
|
||||
|
||||
def charset_for_content_type(type)
|
||||
if type
|
||||
m = type.match(/(?:charset|encoding)="?([a-z0-9-]+)"?/i)
|
||||
if m
|
||||
return Encoding.find(m[1])
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def adjust_encoding(env)
|
||||
charset = charset_for_content_type(env[:response_headers]['content-type'])
|
||||
if charset && env[:body].encoding != charset
|
||||
env[:body].force_encoding(charset)
|
||||
end
|
||||
end
|
||||
|
||||
def on_complete(env)
|
||||
adjust_encoding(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Faraday::Response.register_middleware :charset => Google::APIClient::Charset
|
|
@ -1,310 +0,0 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
require 'addressable/uri'
|
||||
require 'multi_json'
|
||||
require 'active_support/inflector'
|
||||
require 'google/api_client/discovery/resource'
|
||||
require 'google/api_client/discovery/method'
|
||||
require 'google/api_client/discovery/media'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
##
|
||||
# A service that has been described by a discovery document.
|
||||
class API
|
||||
|
||||
##
|
||||
# Creates a description of a particular version of a service.
|
||||
#
|
||||
# @param [String] document_base
|
||||
# Base URI for the discovery document.
|
||||
# @param [Hash] discovery_document
|
||||
# The section of the discovery document that applies to this service
|
||||
# version.
|
||||
#
|
||||
# @return [Google::APIClient::API] The constructed service object.
|
||||
def initialize(document_base, discovery_document)
|
||||
@document_base = Addressable::URI.parse(document_base)
|
||||
@discovery_document = discovery_document
|
||||
metaclass = (class << self; self; end)
|
||||
self.discovered_resources.each do |resource|
|
||||
method_name = ActiveSupport::Inflector.underscore(resource.name).to_sym
|
||||
if !self.respond_to?(method_name)
|
||||
metaclass.send(:define_method, method_name) { resource }
|
||||
end
|
||||
end
|
||||
self.discovered_methods.each do |method|
|
||||
method_name = ActiveSupport::Inflector.underscore(method.name).to_sym
|
||||
if !self.respond_to?(method_name)
|
||||
metaclass.send(:define_method, method_name) { method }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# @return [String] unparsed discovery document for the API
|
||||
attr_reader :discovery_document
|
||||
|
||||
##
|
||||
# Returns the id of the service.
|
||||
#
|
||||
# @return [String] The service id.
|
||||
def id
|
||||
return (
|
||||
@discovery_document['id'] ||
|
||||
"#{self.name}:#{self.version}"
|
||||
)
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the identifier for the service.
|
||||
#
|
||||
# @return [String] The service identifier.
|
||||
def name
|
||||
return @discovery_document['name']
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the version of the service.
|
||||
#
|
||||
# @return [String] The service version.
|
||||
def version
|
||||
return @discovery_document['version']
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a human-readable title for the API.
|
||||
#
|
||||
# @return [Hash] The API title.
|
||||
def title
|
||||
return @discovery_document['title']
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a human-readable description of the API.
|
||||
#
|
||||
# @return [Hash] The API description.
|
||||
def description
|
||||
return @discovery_document['description']
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a URI for the API documentation.
|
||||
#
|
||||
# @return [Hash] The API documentation.
|
||||
def documentation
|
||||
return Addressable::URI.parse(@discovery_document['documentationLink'])
|
||||
end
|
||||
|
||||
##
|
||||
# Returns true if this is the preferred version of this API.
|
||||
#
|
||||
# @return [TrueClass, FalseClass]
|
||||
# Whether or not this is the preferred version of this API.
|
||||
def preferred
|
||||
return !!@discovery_document['preferred']
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the list of API features.
|
||||
#
|
||||
# @return [Array]
|
||||
# The features supported by this API.
|
||||
def features
|
||||
return @discovery_document['features'] || []
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the root URI for this service.
|
||||
#
|
||||
# @return [Addressable::URI] The root URI.
|
||||
def root_uri
|
||||
return @root_uri ||= (
|
||||
Addressable::URI.parse(self.discovery_document['rootUrl'])
|
||||
)
|
||||
end
|
||||
|
||||
##
|
||||
# Returns true if this API uses a data wrapper.
|
||||
#
|
||||
# @return [TrueClass, FalseClass]
|
||||
# Whether or not this API uses a data wrapper.
|
||||
def data_wrapper?
|
||||
return self.features.include?('dataWrapper')
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the base URI for the discovery document.
|
||||
#
|
||||
# @return [Addressable::URI] The base URI.
|
||||
attr_reader :document_base
|
||||
|
||||
##
|
||||
# Returns the base URI for this version of the service.
|
||||
#
|
||||
# @return [Addressable::URI] The base URI that methods are joined to.
|
||||
def method_base
|
||||
if @discovery_document['basePath']
|
||||
return @method_base ||= (
|
||||
self.root_uri.join(Addressable::URI.parse(@discovery_document['basePath']))
|
||||
).normalize
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Updates the hierarchy of resources and methods with the new base.
|
||||
#
|
||||
# @param [Addressable::URI, #to_str, String] new_method_base
|
||||
# The new base URI to use for the service.
|
||||
def method_base=(new_method_base)
|
||||
@method_base = Addressable::URI.parse(new_method_base)
|
||||
self.discovered_resources.each do |resource|
|
||||
resource.method_base = @method_base
|
||||
end
|
||||
self.discovered_methods.each do |method|
|
||||
method.method_base = @method_base
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the base URI for batch calls to this service.
|
||||
#
|
||||
# @return [Addressable::URI] The base URI that methods are joined to.
|
||||
def batch_path
|
||||
if @discovery_document['batchPath']
|
||||
return @batch_path ||= (
|
||||
self.document_base.join(Addressable::URI.parse('/' +
|
||||
@discovery_document['batchPath']))
|
||||
).normalize
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# A list of schemas available for this version of the API.
|
||||
#
|
||||
# @return [Hash] A list of {Google::APIClient::Schema} objects.
|
||||
def schemas
|
||||
return @schemas ||= (
|
||||
(@discovery_document['schemas'] || []).inject({}) do |accu, (k, v)|
|
||||
accu[k] = Google::APIClient::Schema.parse(self, v)
|
||||
accu
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a schema for a kind value.
|
||||
#
|
||||
# @return [Google::APIClient::Schema] The associated Schema object.
|
||||
def schema_for_kind(kind)
|
||||
api_name, schema_name = kind.split('#', 2)
|
||||
if api_name != self.name
|
||||
raise ArgumentError,
|
||||
"The kind does not match this API. " +
|
||||
"Expected '#{self.name}', got '#{api_name}'."
|
||||
end
|
||||
for k, v in self.schemas
|
||||
return v if k.downcase == schema_name.downcase
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
##
|
||||
# A list of resources available at the root level of this version of the
|
||||
# API.
|
||||
#
|
||||
# @return [Array] A list of {Google::APIClient::Resource} objects.
|
||||
def discovered_resources
|
||||
return @discovered_resources ||= (
|
||||
(@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
|
||||
accu << Google::APIClient::Resource.new(
|
||||
self, self.method_base, k, v
|
||||
)
|
||||
accu
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
##
|
||||
# A list of methods available at the root level of this version of the
|
||||
# API.
|
||||
#
|
||||
# @return [Array] A list of {Google::APIClient::Method} objects.
|
||||
def discovered_methods
|
||||
return @discovered_methods ||= (
|
||||
(@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
|
||||
accu << Google::APIClient::Method.new(self, self.method_base, k, v)
|
||||
accu
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
##
|
||||
# Allows deep inspection of the discovery document.
|
||||
def [](key)
|
||||
return @discovery_document[key]
|
||||
end
|
||||
|
||||
##
|
||||
# Converts the service to a flat mapping of RPC names and method objects.
|
||||
#
|
||||
# @return [Hash] All methods available on the service.
|
||||
#
|
||||
# @example
|
||||
# # Discover available methods
|
||||
# method_names = client.discovered_api('buzz').to_h.keys
|
||||
def to_h
|
||||
return @hash ||= (begin
|
||||
methods_hash = {}
|
||||
self.discovered_methods.each do |method|
|
||||
methods_hash[method.id] = method
|
||||
end
|
||||
self.discovered_resources.each do |resource|
|
||||
methods_hash.merge!(resource.to_h)
|
||||
end
|
||||
methods_hash
|
||||
end)
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a <code>String</code> representation of the service's state.
|
||||
#
|
||||
# @return [String] The service's state, as a <code>String</code>.
|
||||
def inspect
|
||||
sprintf(
|
||||
"#<%s:%#0x ID:%s>", self.class.to_s, self.object_id, self.id
|
||||
)
|
||||
end
|
||||
|
||||
##
|
||||
# Marshalling support - serialize the API to a string (doc base + original
|
||||
# discovery document).
|
||||
def _dump(level)
|
||||
MultiJson.dump([@document_base.to_s, @discovery_document])
|
||||
end
|
||||
|
||||
##
|
||||
# Marshalling support - Restore an API instance from serialized form
|
||||
def self._load(obj)
|
||||
new(*MultiJson.load(obj))
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,77 +0,0 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
require 'addressable/uri'
|
||||
require 'addressable/template'
|
||||
|
||||
require 'google/api_client/errors'
|
||||
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
##
|
||||
# Media upload elements for discovered methods
|
||||
class MediaUpload
|
||||
|
||||
##
|
||||
# Creates a description of a particular method.
|
||||
#
|
||||
# @param [Google::APIClient::API] api
|
||||
# Base discovery document for the API
|
||||
# @param [Addressable::URI] method_base
|
||||
# The base URI for the service.
|
||||
# @param [Hash] discovery_document
|
||||
# The media upload section of the discovery document.
|
||||
#
|
||||
# @return [Google::APIClient::Method] The constructed method object.
|
||||
def initialize(api, method_base, discovery_document)
|
||||
@api = api
|
||||
@method_base = method_base
|
||||
@discovery_document = discovery_document
|
||||
end
|
||||
|
||||
##
|
||||
# List of acceptable mime types
|
||||
#
|
||||
# @return [Array]
|
||||
# List of acceptable mime types for uploaded content
|
||||
def accepted_types
|
||||
@discovery_document['accept']
|
||||
end
|
||||
|
||||
##
|
||||
# Maximum size of an uplad
|
||||
# TODO: Parse & convert to numeric value
|
||||
#
|
||||
# @return [String]
|
||||
def max_size
|
||||
@discovery_document['maxSize']
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the URI template for the method. A parameter list can be
|
||||
# used to expand this into a URI.
|
||||
#
|
||||
# @return [Addressable::Template] The URI template.
|
||||
def uri_template
|
||||
return @uri_template ||= Addressable::Template.new(
|
||||
@api.method_base.join(Addressable::URI.parse(@discovery_document['protocols']['simple']['path']))
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,363 +0,0 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
require 'addressable/uri'
|
||||
require 'addressable/template'
|
||||
|
||||
require 'google/api_client/errors'
|
||||
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
##
|
||||
# A method that has been described by a discovery document.
|
||||
class Method
|
||||
|
||||
##
|
||||
# Creates a description of a particular method.
|
||||
#
|
||||
# @param [Google::APIClient::API] api
|
||||
# The API this method belongs to.
|
||||
# @param [Addressable::URI] method_base
|
||||
# The base URI for the service.
|
||||
# @param [String] method_name
|
||||
# The identifier for the method.
|
||||
# @param [Hash] discovery_document
|
||||
# The section of the discovery document that applies to this method.
|
||||
#
|
||||
# @return [Google::APIClient::Method] The constructed method object.
|
||||
def initialize(api, method_base, method_name, discovery_document)
|
||||
@api = api
|
||||
@method_base = method_base
|
||||
@name = method_name
|
||||
@discovery_document = discovery_document
|
||||
end
|
||||
|
||||
# @return [String] unparsed discovery document for the method
|
||||
attr_reader :discovery_document
|
||||
|
||||
##
|
||||
# Returns the API this method belongs to.
|
||||
#
|
||||
# @return [Google::APIClient::API] The API this method belongs to.
|
||||
attr_reader :api
|
||||
|
||||
##
|
||||
# Returns the identifier for the method.
|
||||
#
|
||||
# @return [String] The method identifier.
|
||||
attr_reader :name
|
||||
|
||||
##
|
||||
# Returns the base URI for the method.
|
||||
#
|
||||
# @return [Addressable::URI]
|
||||
# The base URI that this method will be joined to.
|
||||
attr_reader :method_base
|
||||
|
||||
##
|
||||
# Updates the method with the new base.
|
||||
#
|
||||
# @param [Addressable::URI, #to_str, String] new_method_base
|
||||
# The new base URI to use for the method.
|
||||
def method_base=(new_method_base)
|
||||
@method_base = Addressable::URI.parse(new_method_base)
|
||||
@uri_template = nil
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a human-readable description of the method.
|
||||
#
|
||||
# @return [Hash] The API description.
|
||||
def description
|
||||
return @discovery_document['description']
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the method ID.
|
||||
#
|
||||
# @return [String] The method identifier.
|
||||
def id
|
||||
return @discovery_document['id']
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the HTTP method or 'GET' if none is specified.
|
||||
#
|
||||
# @return [String] The HTTP method that will be used in the request.
|
||||
def http_method
|
||||
return @discovery_document['httpMethod'] || 'GET'
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the URI template for the method. A parameter list can be
|
||||
# used to expand this into a URI.
|
||||
#
|
||||
# @return [Addressable::Template] The URI template.
|
||||
def uri_template
|
||||
return @uri_template ||= Addressable::Template.new(
|
||||
self.method_base.join(Addressable::URI.parse("./" + @discovery_document['path']))
|
||||
)
|
||||
end
|
||||
|
||||
##
|
||||
# Returns media upload information for this method, if supported
|
||||
#
|
||||
# @return [Google::APIClient::MediaUpload] Description of upload endpoints
|
||||
def media_upload
|
||||
if @discovery_document['mediaUpload']
|
||||
return @media_upload ||= Google::APIClient::MediaUpload.new(self, self.method_base, @discovery_document['mediaUpload'])
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the Schema object for the method's request, if any.
|
||||
#
|
||||
# @return [Google::APIClient::Schema] The request schema.
|
||||
def request_schema
|
||||
if @discovery_document['request']
|
||||
schema_name = @discovery_document['request']['$ref']
|
||||
return @api.schemas[schema_name]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the Schema object for the method's response, if any.
|
||||
#
|
||||
# @return [Google::APIClient::Schema] The response schema.
|
||||
def response_schema
|
||||
if @discovery_document['response']
|
||||
schema_name = @discovery_document['response']['$ref']
|
||||
return @api.schemas[schema_name]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Normalizes parameters, converting to the appropriate types.
|
||||
#
|
||||
# @param [Hash, Array] parameters
|
||||
# The parameters to normalize.
|
||||
#
|
||||
# @return [Hash] The normalized parameters.
|
||||
def normalize_parameters(parameters={})
|
||||
# Convert keys to Strings when appropriate
|
||||
if parameters.kind_of?(Hash) || parameters.kind_of?(Array)
|
||||
# Returning an array since parameters can be repeated (ie, Adsense Management API)
|
||||
parameters = parameters.inject([]) do |accu, (k, v)|
|
||||
k = k.to_s if k.kind_of?(Symbol)
|
||||
k = k.to_str if k.respond_to?(:to_str)
|
||||
unless k.kind_of?(String)
|
||||
raise TypeError, "Expected String, got #{k.class}."
|
||||
end
|
||||
accu << [k, v]
|
||||
accu
|
||||
end
|
||||
else
|
||||
raise TypeError,
|
||||
"Expected Hash or Array, got #{parameters.class}."
|
||||
end
|
||||
return parameters
|
||||
end
|
||||
|
||||
##
|
||||
# Expands the method's URI template using a parameter list.
|
||||
#
|
||||
# @api private
|
||||
# @param [Hash, Array] parameters
|
||||
# The parameter list to use.
|
||||
#
|
||||
# @return [Addressable::URI] The URI after expansion.
|
||||
def generate_uri(parameters={})
|
||||
parameters = self.normalize_parameters(parameters)
|
||||
|
||||
self.validate_parameters(parameters)
|
||||
template_variables = self.uri_template.variables
|
||||
upload_type = parameters.assoc('uploadType') || parameters.assoc('upload_type')
|
||||
if upload_type
|
||||
unless self.media_upload
|
||||
raise ArgumentException, "Media upload not supported for this method"
|
||||
end
|
||||
case upload_type.last
|
||||
when 'media', 'multipart', 'resumable'
|
||||
uri = self.media_upload.uri_template.expand(parameters)
|
||||
else
|
||||
raise ArgumentException, "Invalid uploadType '#{upload_type}'"
|
||||
end
|
||||
else
|
||||
uri = self.uri_template.expand(parameters)
|
||||
end
|
||||
query_parameters = parameters.reject do |k, v|
|
||||
template_variables.include?(k)
|
||||
end
|
||||
# encode all non-template parameters
|
||||
params = ""
|
||||
unless query_parameters.empty?
|
||||
params = "?" + Addressable::URI.form_encode(query_parameters.sort)
|
||||
end
|
||||
# Normalization is necessary because of undesirable percent-escaping
|
||||
# during URI template expansion
|
||||
return uri.normalize + params
|
||||
end
|
||||
|
||||
##
|
||||
# Generates an HTTP request for this method.
|
||||
#
|
||||
# @api private
|
||||
# @param [Hash, Array] parameters
|
||||
# The parameters to send.
|
||||
# @param [String, StringIO] body The body for the HTTP request.
|
||||
# @param [Hash, Array] headers The HTTP headers for the request.
|
||||
# @option options [Faraday::Connection] :connection
|
||||
# The HTTP connection to use.
|
||||
#
|
||||
# @return [Array] The generated HTTP request.
|
||||
def generate_request(parameters={}, body='', headers={}, options={})
|
||||
if !headers.kind_of?(Array) && !headers.kind_of?(Hash)
|
||||
raise TypeError, "Expected Hash or Array, got #{headers.class}."
|
||||
end
|
||||
method = self.http_method.to_s.downcase.to_sym
|
||||
uri = self.generate_uri(parameters)
|
||||
headers = Faraday::Utils::Headers.new(headers)
|
||||
return [method, uri, headers, body]
|
||||
end
|
||||
|
||||
|
||||
##
|
||||
# Returns a <code>Hash</code> of the parameter descriptions for
|
||||
# this method.
|
||||
#
|
||||
# @return [Hash] The parameter descriptions.
|
||||
def parameter_descriptions
|
||||
@parameter_descriptions ||= (
|
||||
@discovery_document['parameters'] || {}
|
||||
).inject({}) { |h,(k,v)| h[k]=v; h }
|
||||
end
|
||||
|
||||
##
|
||||
# Returns an <code>Array</code> of the parameters for this method.
|
||||
#
|
||||
# @return [Array] The parameters.
|
||||
def parameters
|
||||
@parameters ||= ((
|
||||
@discovery_document['parameters'] || {}
|
||||
).inject({}) { |h,(k,v)| h[k]=v; h }).keys
|
||||
end
|
||||
|
||||
##
|
||||
# Returns an <code>Array</code> of the required parameters for this
|
||||
# method.
|
||||
#
|
||||
# @return [Array] The required parameters.
|
||||
#
|
||||
# @example
|
||||
# # A list of all required parameters.
|
||||
# method.required_parameters
|
||||
def required_parameters
|
||||
@required_parameters ||= ((self.parameter_descriptions.select do |k, v|
|
||||
v['required']
|
||||
end).inject({}) { |h,(k,v)| h[k]=v; h }).keys
|
||||
end
|
||||
|
||||
##
|
||||
# Returns an <code>Array</code> of the optional parameters for this
|
||||
# method.
|
||||
#
|
||||
# @return [Array] The optional parameters.
|
||||
#
|
||||
# @example
|
||||
# # A list of all optional parameters.
|
||||
# method.optional_parameters
|
||||
def optional_parameters
|
||||
@optional_parameters ||= ((self.parameter_descriptions.reject do |k, v|
|
||||
v['required']
|
||||
end).inject({}) { |h,(k,v)| h[k]=v; h }).keys
|
||||
end
|
||||
|
||||
##
|
||||
# Verifies that the parameters are valid for this method. Raises an
|
||||
# exception if validation fails.
|
||||
#
|
||||
# @api private
|
||||
# @param [Hash, Array] parameters
|
||||
# The parameters to verify.
|
||||
#
|
||||
# @return [NilClass] <code>nil</code> if validation passes.
|
||||
def validate_parameters(parameters={})
|
||||
parameters = self.normalize_parameters(parameters)
|
||||
required_variables = ((self.parameter_descriptions.select do |k, v|
|
||||
v['required']
|
||||
end).inject({}) { |h,(k,v)| h[k]=v; h }).keys
|
||||
missing_variables = required_variables - parameters.map { |(k, _)| k }
|
||||
if missing_variables.size > 0
|
||||
raise ArgumentError,
|
||||
"Missing required parameters: #{missing_variables.join(', ')}."
|
||||
end
|
||||
parameters.each do |k, v|
|
||||
# Handle repeated parameters.
|
||||
if self.parameter_descriptions[k] &&
|
||||
self.parameter_descriptions[k]['repeated'] &&
|
||||
v.kind_of?(Array)
|
||||
# If this is a repeated parameter and we've got an array as a
|
||||
# value, just provide the whole array to the loop below.
|
||||
items = v
|
||||
else
|
||||
# If this is not a repeated parameter, or if it is but we're
|
||||
# being given a single value, wrap the value in an array, so that
|
||||
# the loop below still works for the single element.
|
||||
items = [v]
|
||||
end
|
||||
|
||||
items.each do |item|
|
||||
if self.parameter_descriptions[k]
|
||||
enum = self.parameter_descriptions[k]['enum']
|
||||
if enum && !enum.include?(item)
|
||||
raise ArgumentError,
|
||||
"Parameter '#{k}' has an invalid value: #{item}. " +
|
||||
"Must be one of #{enum.inspect}."
|
||||
end
|
||||
pattern = self.parameter_descriptions[k]['pattern']
|
||||
if pattern
|
||||
regexp = Regexp.new("^#{pattern}$")
|
||||
if item !~ regexp
|
||||
raise ArgumentError,
|
||||
"Parameter '#{k}' has an invalid value: #{item}. " +
|
||||
"Must match: /^#{pattern}$/."
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a <code>String</code> representation of the method's state.
|
||||
#
|
||||
# @return [String] The method's state, as a <code>String</code>.
|
||||
def inspect
|
||||
sprintf(
|
||||
"#<%s:%#0x ID:%s>",
|
||||
self.class.to_s, self.object_id, self.id
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,156 +0,0 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
require 'addressable/uri'
|
||||
|
||||
require 'active_support/inflector'
|
||||
require 'google/api_client/discovery/method'
|
||||
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
##
|
||||
# A resource that has been described by a discovery document.
|
||||
class Resource
|
||||
|
||||
##
|
||||
# Creates a description of a particular version of a resource.
|
||||
#
|
||||
# @param [Google::APIClient::API] api
|
||||
# The API this resource belongs to.
|
||||
# @param [Addressable::URI] method_base
|
||||
# The base URI for the service.
|
||||
# @param [String] resource_name
|
||||
# The identifier for the resource.
|
||||
# @param [Hash] discovery_document
|
||||
# The section of the discovery document that applies to this resource.
|
||||
#
|
||||
# @return [Google::APIClient::Resource] The constructed resource object.
|
||||
def initialize(api, method_base, resource_name, discovery_document)
|
||||
@api = api
|
||||
@method_base = method_base
|
||||
@name = resource_name
|
||||
@discovery_document = discovery_document
|
||||
metaclass = (class <<self; self; end)
|
||||
self.discovered_resources.each do |resource|
|
||||
method_name = ActiveSupport::Inflector.underscore(resource.name).to_sym
|
||||
if !self.respond_to?(method_name)
|
||||
metaclass.send(:define_method, method_name) { resource }
|
||||
end
|
||||
end
|
||||
self.discovered_methods.each do |method|
|
||||
method_name = ActiveSupport::Inflector.underscore(method.name).to_sym
|
||||
if !self.respond_to?(method_name)
|
||||
metaclass.send(:define_method, method_name) { method }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# @return [String] unparsed discovery document for the resource
|
||||
attr_reader :discovery_document
|
||||
|
||||
##
|
||||
# Returns the identifier for the resource.
|
||||
#
|
||||
# @return [String] The resource identifier.
|
||||
attr_reader :name
|
||||
|
||||
##
|
||||
# Returns the base URI for this resource.
|
||||
#
|
||||
# @return [Addressable::URI] The base URI that methods are joined to.
|
||||
attr_reader :method_base
|
||||
|
||||
##
|
||||
# Returns a human-readable description of the resource.
|
||||
#
|
||||
# @return [Hash] The API description.
|
||||
def description
|
||||
return @discovery_document['description']
|
||||
end
|
||||
|
||||
##
|
||||
# Updates the hierarchy of resources and methods with the new base.
|
||||
#
|
||||
# @param [Addressable::URI, #to_str, String] new_method_base
|
||||
# The new base URI to use for the resource.
|
||||
def method_base=(new_method_base)
|
||||
@method_base = Addressable::URI.parse(new_method_base)
|
||||
self.discovered_resources.each do |resource|
|
||||
resource.method_base = @method_base
|
||||
end
|
||||
self.discovered_methods.each do |method|
|
||||
method.method_base = @method_base
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# A list of sub-resources available on this resource.
|
||||
#
|
||||
# @return [Array] A list of {Google::APIClient::Resource} objects.
|
||||
def discovered_resources
|
||||
return @discovered_resources ||= (
|
||||
(@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
|
||||
accu << Google::APIClient::Resource.new(
|
||||
@api, self.method_base, k, v
|
||||
)
|
||||
accu
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
##
|
||||
# A list of methods available on this resource.
|
||||
#
|
||||
# @return [Array] A list of {Google::APIClient::Method} objects.
|
||||
def discovered_methods
|
||||
return @discovered_methods ||= (
|
||||
(@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
|
||||
accu << Google::APIClient::Method.new(@api, self.method_base, k, v)
|
||||
accu
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
##
|
||||
# Converts the resource to a flat mapping of RPC names and method
|
||||
# objects.
|
||||
#
|
||||
# @return [Hash] All methods available on the resource.
|
||||
def to_h
|
||||
return @hash ||= (begin
|
||||
methods_hash = {}
|
||||
self.discovered_methods.each do |method|
|
||||
methods_hash[method.id] = method
|
||||
end
|
||||
self.discovered_resources.each do |resource|
|
||||
methods_hash.merge!(resource.to_h)
|
||||
end
|
||||
methods_hash
|
||||
end)
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a <code>String</code> representation of the resource's state.
|
||||
#
|
||||
# @return [String] The resource's state, as a <code>String</code>.
|
||||
def inspect
|
||||
sprintf(
|
||||
"#<%s:%#0x NAME:%s>", self.class.to_s, self.object_id, self.name
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,117 +0,0 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
require 'time'
|
||||
require 'multi_json'
|
||||
require 'compat/multi_json'
|
||||
require 'base64'
|
||||
require 'autoparse'
|
||||
require 'addressable/uri'
|
||||
require 'addressable/template'
|
||||
|
||||
require 'active_support/inflector'
|
||||
require 'google/api_client/errors'
|
||||
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
##
|
||||
# @api private
|
||||
module Schema
|
||||
def self.parse(api, schema_data)
|
||||
# This method is super-long, but hard to break up due to the
|
||||
# unavoidable dependence on closures and execution context.
|
||||
schema_name = schema_data['id']
|
||||
|
||||
# Due to an oversight, schema IDs may not be URI references.
|
||||
# TODO(bobaman): Remove this code once this has been resolved.
|
||||
schema_uri = (
|
||||
api.document_base +
|
||||
(schema_name[0..0] != '#' ? '#' + schema_name : schema_name)
|
||||
)
|
||||
|
||||
# Due to an oversight, schema IDs may not be URI references.
|
||||
# TODO(bobaman): Remove this whole lambda once this has been resolved.
|
||||
reformat_references = lambda do |data|
|
||||
# This code is not particularly efficient due to recursive traversal
|
||||
# and excess object creation, but this hopefully shouldn't be an
|
||||
# issue since it should only be called only once per schema per
|
||||
# process.
|
||||
if data.kind_of?(Hash) &&
|
||||
data['$ref'] && !data['$ref'].kind_of?(Hash)
|
||||
if data['$ref'].respond_to?(:to_str)
|
||||
reference = data['$ref'].to_str
|
||||
else
|
||||
raise TypeError, "Expected String, got #{data['$ref'].class}"
|
||||
end
|
||||
reference = '#' + reference if reference[0..0] != '#'
|
||||
data.merge({
|
||||
'$ref' => reference
|
||||
})
|
||||
elsif data.kind_of?(Hash)
|
||||
data.inject({}) do |accu, (key, value)|
|
||||
if value.kind_of?(Hash)
|
||||
accu[key] = reformat_references.call(value)
|
||||
else
|
||||
accu[key] = value
|
||||
end
|
||||
accu
|
||||
end
|
||||
else
|
||||
data
|
||||
end
|
||||
end
|
||||
schema_data = reformat_references.call(schema_data)
|
||||
|
||||
if schema_name
|
||||
api_name_string = ActiveSupport::Inflector.camelize(api.name)
|
||||
api_version_string = ActiveSupport::Inflector.camelize(api.version).gsub('.', '_')
|
||||
# This is for compatibility with Ruby 1.8.7.
|
||||
# TODO(bobaman) Remove this when we eventually stop supporting 1.8.7.
|
||||
args = []
|
||||
args << false if Class.method(:const_defined?).arity != 1
|
||||
if Google::APIClient::Schema.const_defined?(api_name_string, *args)
|
||||
api_name = Google::APIClient::Schema.const_get(
|
||||
api_name_string, *args
|
||||
)
|
||||
else
|
||||
api_name = Google::APIClient::Schema.const_set(
|
||||
api_name_string, Module.new
|
||||
)
|
||||
end
|
||||
if api_name.const_defined?(api_version_string, *args)
|
||||
api_version = api_name.const_get(api_version_string, *args)
|
||||
else
|
||||
api_version = api_name.const_set(api_version_string, Module.new)
|
||||
end
|
||||
if api_version.const_defined?(schema_name, *args)
|
||||
schema_class = api_version.const_get(schema_name, *args)
|
||||
end
|
||||
end
|
||||
|
||||
# It's possible the schema has already been defined. If so, don't
|
||||
# redefine it. This means that reloading a schema which has already
|
||||
# been loaded into memory is not possible.
|
||||
unless schema_class
|
||||
schema_class = AutoParse.generate(schema_data, :uri => schema_uri)
|
||||
if schema_name
|
||||
api_version.const_set(schema_name, schema_class)
|
||||
end
|
||||
end
|
||||
return schema_class
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,42 +0,0 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
module ENV
|
||||
OS_VERSION = begin
|
||||
if RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/
|
||||
# TODO(bobaman)
|
||||
# Confirm that all of these Windows environments actually have access
|
||||
# to the `ver` command.
|
||||
`ver`.sub(/\s*\[Version\s*/, '/').sub(']', '').strip
|
||||
elsif RUBY_PLATFORM =~ /darwin/i
|
||||
"Mac OS X/#{`sw_vers -productVersion`}"
|
||||
elsif RUBY_PLATFORM == 'java'
|
||||
# Get the information from java system properties to avoid spawning a
|
||||
# sub-process, which is not friendly in some contexts (web servers).
|
||||
require 'java'
|
||||
name = java.lang.System.getProperty('os.name')
|
||||
version = java.lang.System.getProperty('os.version')
|
||||
"#{name}/#{version}"
|
||||
else
|
||||
`uname -sr`.sub(' ', '/')
|
||||
end
|
||||
rescue Exception
|
||||
RUBY_PLATFORM
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,28 +0,0 @@
|
|||
require 'faraday'
|
||||
require 'zlib'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
class Gzip < Faraday::Response::Middleware
|
||||
include Google::APIClient::Logging
|
||||
|
||||
def on_complete(env)
|
||||
encoding = env[:response_headers]['content-encoding'].to_s.downcase
|
||||
case encoding
|
||||
when 'gzip'
|
||||
logger.debug { "Decompressing gzip encoded response (#{env[:body].length} bytes)" }
|
||||
env[:body] = Zlib::GzipReader.new(StringIO.new(env[:body])).read
|
||||
env[:response_headers].delete('content-encoding')
|
||||
logger.debug { "Decompressed (#{env[:body].length} bytes)" }
|
||||
when 'deflate'
|
||||
logger.debug{ "Decompressing deflate encoded response (#{env[:body].length} bytes)" }
|
||||
env[:body] = Zlib::Inflate.inflate(env[:body])
|
||||
env[:response_headers].delete('content-encoding')
|
||||
logger.debug { "Decompressed (#{env[:body].length} bytes)" }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Faraday::Response.register_middleware :gzip => Google::APIClient::Gzip
|
|
@ -1,32 +0,0 @@
|
|||
require 'logger'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
|
||||
class << self
|
||||
##
|
||||
# Logger for the API client
|
||||
#
|
||||
# @return [Logger] logger instance.
|
||||
attr_accessor :logger
|
||||
end
|
||||
|
||||
self.logger = Logger.new(STDOUT)
|
||||
self.logger.level = Logger::WARN
|
||||
|
||||
##
|
||||
# Module to make accessing the logger simpler
|
||||
module Logging
|
||||
##
|
||||
# Logger for the API client
|
||||
#
|
||||
# @return [Logger] logger instance.
|
||||
def logger
|
||||
Google::APIClient.logger
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
|
@ -1,259 +0,0 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
require 'google/api_client/reference'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
##
|
||||
# Uploadable media support. Holds an IO stream & content type.
|
||||
#
|
||||
# @see Faraday::UploadIO
|
||||
# @example
|
||||
# media = Google::APIClient::UploadIO.new('mymovie.m4v', 'video/mp4')
|
||||
class UploadIO < Faraday::UploadIO
|
||||
|
||||
# @return [Fixnum] Size of chunks to upload. Default is nil, meaning upload the entire file in a single request
|
||||
attr_accessor :chunk_size
|
||||
|
||||
##
|
||||
# Get the length of the stream
|
||||
#
|
||||
# @return [Fixnum]
|
||||
# Length of stream, in bytes
|
||||
def length
|
||||
io.respond_to?(:length) ? io.length : File.size(local_path)
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Wraps an input stream and limits data to a given range
|
||||
#
|
||||
# @example
|
||||
# chunk = Google::APIClient::RangedIO.new(io, 0, 1000)
|
||||
class RangedIO
|
||||
##
|
||||
# Bind an input stream to a specific range.
|
||||
#
|
||||
# @param [IO] io
|
||||
# Source input stream
|
||||
# @param [Fixnum] offset
|
||||
# Starting offset of the range
|
||||
# @param [Fixnum] length
|
||||
# Length of range
|
||||
def initialize(io, offset, length)
|
||||
@io = io
|
||||
@offset = offset
|
||||
@length = length
|
||||
self.rewind
|
||||
end
|
||||
|
||||
##
|
||||
# @see IO#read
|
||||
def read(amount = nil, buf = nil)
|
||||
buffer = buf || ''
|
||||
if amount.nil?
|
||||
size = @length - @pos
|
||||
done = ''
|
||||
elsif amount == 0
|
||||
size = 0
|
||||
done = ''
|
||||
else
|
||||
size = [@length - @pos, amount].min
|
||||
done = nil
|
||||
end
|
||||
|
||||
if size > 0
|
||||
result = @io.read(size)
|
||||
result.force_encoding("BINARY") if result.respond_to?(:force_encoding)
|
||||
buffer << result if result
|
||||
@pos = @pos + size
|
||||
end
|
||||
|
||||
if buffer.length > 0
|
||||
buffer
|
||||
else
|
||||
done
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# @see IO#rewind
|
||||
def rewind
|
||||
self.pos = 0
|
||||
end
|
||||
|
||||
##
|
||||
# @see IO#pos
|
||||
def pos
|
||||
@pos
|
||||
end
|
||||
|
||||
##
|
||||
# @see IO#pos=
|
||||
def pos=(pos)
|
||||
@pos = pos
|
||||
@io.pos = @offset + pos
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Resumable uploader.
|
||||
#
|
||||
class ResumableUpload < Request
|
||||
# @return [Fixnum] Max bytes to send in a single request
|
||||
attr_accessor :chunk_size
|
||||
|
||||
##
|
||||
# Creates a new uploader.
|
||||
#
|
||||
# @param [Hash] options
|
||||
# Request options
|
||||
def initialize(options={})
|
||||
super options
|
||||
self.uri = options[:uri]
|
||||
self.http_method = :put
|
||||
@offset = options[:offset] || 0
|
||||
@complete = false
|
||||
@expired = false
|
||||
end
|
||||
|
||||
##
|
||||
# Sends all remaining chunks to the server
|
||||
#
|
||||
# @deprecated Pass the instance to {Google::APIClient#execute} instead
|
||||
#
|
||||
# @param [Google::APIClient] api_client
|
||||
# API Client instance to use for sending
|
||||
def send_all(api_client)
|
||||
result = nil
|
||||
until complete?
|
||||
result = send_chunk(api_client)
|
||||
break unless result.status == 308
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
##
|
||||
# Sends the next chunk to the server
|
||||
#
|
||||
# @deprecated Pass the instance to {Google::APIClient#execute} instead
|
||||
#
|
||||
# @param [Google::APIClient] api_client
|
||||
# API Client instance to use for sending
|
||||
def send_chunk(api_client)
|
||||
return api_client.execute(self)
|
||||
end
|
||||
|
||||
##
|
||||
# Check if upload is complete
|
||||
#
|
||||
# @return [TrueClass, FalseClass]
|
||||
# Whether or not the upload complete successfully
|
||||
def complete?
|
||||
return @complete
|
||||
end
|
||||
|
||||
##
|
||||
# Check if the upload URL expired (upload not completed in alotted time.)
|
||||
# Expired uploads must be restarted from the beginning
|
||||
#
|
||||
# @return [TrueClass, FalseClass]
|
||||
# Whether or not the upload has expired and can not be resumed
|
||||
def expired?
|
||||
return @expired
|
||||
end
|
||||
|
||||
##
|
||||
# Check if upload is resumable. That is, neither complete nor expired
|
||||
#
|
||||
# @return [TrueClass, FalseClass] True if upload can be resumed
|
||||
def resumable?
|
||||
return !(self.complete? or self.expired?)
|
||||
end
|
||||
|
||||
##
|
||||
# Convert to an HTTP request. Returns components in order of method, URI,
|
||||
# request headers, and body
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @return [Array<(Symbol, Addressable::URI, Hash, [#read,#to_str])>]
|
||||
def to_http_request
|
||||
if @complete
|
||||
raise Google::APIClient::ClientError, "Upload already complete"
|
||||
elsif @offset.nil?
|
||||
self.headers.update({
|
||||
'Content-Length' => "0",
|
||||
'Content-Range' => "bytes */#{media.length}" })
|
||||
else
|
||||
start_offset = @offset
|
||||
remaining = self.media.length - start_offset
|
||||
chunk_size = self.media.chunk_size || self.chunk_size || self.media.length
|
||||
content_length = [remaining, chunk_size].min
|
||||
chunk = RangedIO.new(self.media.io, start_offset, content_length)
|
||||
end_offset = start_offset + content_length - 1
|
||||
self.headers.update({
|
||||
'Content-Length' => "#{content_length}",
|
||||
'Content-Type' => self.media.content_type,
|
||||
'Content-Range' => "bytes #{start_offset}-#{end_offset}/#{media.length}" })
|
||||
self.body = chunk
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
##
|
||||
# Check the result from the server, updating the offset and/or location
|
||||
# if available.
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [Faraday::Response] response
|
||||
# HTTP response
|
||||
#
|
||||
# @return [Google::APIClient::Result]
|
||||
# Processed API response
|
||||
def process_http_response(response)
|
||||
case response.status
|
||||
when 200...299
|
||||
@complete = true
|
||||
when 308
|
||||
range = response.headers['range']
|
||||
if range
|
||||
@offset = range.scan(/\d+/).collect{|x| Integer(x)}.last + 1
|
||||
end
|
||||
if response.headers['location']
|
||||
self.uri = response.headers['location']
|
||||
end
|
||||
when 400...499
|
||||
@expired = true
|
||||
when 500...599
|
||||
# Invalidate the offset to mark it needs to be queried on the
|
||||
# next request
|
||||
@offset = nil
|
||||
end
|
||||
return Google::APIClient::Result.new(self, response)
|
||||
end
|
||||
|
||||
##
|
||||
# Hashified verison of the API request
|
||||
#
|
||||
# @return [Hash]
|
||||
def to_hash
|
||||
super.merge(:offset => @offset)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,18 +0,0 @@
|
|||
require 'rails/railtie'
|
||||
require 'google/api_client/logging'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
|
||||
##
|
||||
# Optional support class for Rails. Currently replaces the built-in logger
|
||||
# with Rails' application log.
|
||||
#
|
||||
class Railtie < Rails::Railtie
|
||||
initializer 'google-api-client' do |app|
|
||||
logger = app.config.logger || Rails.logger
|
||||
Google::APIClient.logger = logger unless logger.nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,350 +0,0 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'faraday'
|
||||
require 'faraday/request/multipart'
|
||||
require 'compat/multi_json'
|
||||
require 'addressable/uri'
|
||||
require 'stringio'
|
||||
require 'google/api_client/discovery'
|
||||
require 'google/api_client/logging'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
|
||||
##
|
||||
# Represents an API request.
|
||||
class Request
|
||||
include Google::APIClient::Logging
|
||||
|
||||
MULTIPART_BOUNDARY = "-----------RubyApiMultipartPost".freeze
|
||||
|
||||
# @return [Hash] Request parameters
|
||||
attr_reader :parameters
|
||||
# @return [Hash] Additional HTTP headers
|
||||
attr_reader :headers
|
||||
# @return [Google::APIClient::Method] API method to invoke
|
||||
attr_reader :api_method
|
||||
# @return [Google::APIClient::UploadIO] File to upload
|
||||
attr_accessor :media
|
||||
# @return [#generated_authenticated_request] User credentials
|
||||
attr_accessor :authorization
|
||||
# @return [TrueClass,FalseClass] True if request should include credentials
|
||||
attr_accessor :authenticated
|
||||
# @return [#read, #to_str] Request body
|
||||
attr_accessor :body
|
||||
|
||||
##
|
||||
# Build a request
|
||||
#
|
||||
# @param [Hash] options
|
||||
# @option options [Hash, Array] :parameters
|
||||
# Request parameters for the API method.
|
||||
# @option options [Google::APIClient::Method] :api_method
|
||||
# API method to invoke. Either :api_method or :uri must be specified
|
||||
# @option options [TrueClass, FalseClass] :authenticated
|
||||
# True if request should include credentials. Implicitly true if
|
||||
# unspecified and :authorization present
|
||||
# @option options [#generate_signed_request] :authorization
|
||||
# OAuth credentials
|
||||
# @option options [Google::APIClient::UploadIO] :media
|
||||
# File to upload, if media upload request
|
||||
# @option options [#to_json, #to_hash] :body_object
|
||||
# Main body of the API request. Typically hash or object that can
|
||||
# be serialized to JSON
|
||||
# @option options [#read, #to_str] :body
|
||||
# Raw body to send in POST/PUT requests
|
||||
# @option options [String, Addressable::URI] :uri
|
||||
# URI to request. Either :api_method or :uri must be specified
|
||||
# @option options [String, Symbol] :http_method
|
||||
# HTTP method when requesting a URI
|
||||
def initialize(options={})
|
||||
@parameters = Faraday::Utils::ParamsHash.new
|
||||
@headers = Faraday::Utils::Headers.new
|
||||
|
||||
self.parameters.merge!(options[:parameters]) unless options[:parameters].nil?
|
||||
self.headers.merge!(options[:headers]) unless options[:headers].nil?
|
||||
self.api_method = options[:api_method]
|
||||
self.authenticated = options[:authenticated]
|
||||
self.authorization = options[:authorization]
|
||||
|
||||
# These parameters are handled differently because they're not
|
||||
# parameters to the API method, but rather to the API system.
|
||||
self.parameters['key'] ||= options[:key] if options[:key]
|
||||
self.parameters['userIp'] ||= options[:user_ip] if options[:user_ip]
|
||||
|
||||
if options[:media]
|
||||
self.initialize_media_upload(options)
|
||||
elsif options[:body]
|
||||
self.body = options[:body]
|
||||
elsif options[:body_object]
|
||||
self.headers['Content-Type'] ||= 'application/json'
|
||||
self.body = serialize_body(options[:body_object])
|
||||
else
|
||||
self.body = ''
|
||||
end
|
||||
|
||||
unless self.api_method
|
||||
self.http_method = options[:http_method] || 'GET'
|
||||
self.uri = options[:uri]
|
||||
end
|
||||
end
|
||||
|
||||
# @!attribute [r] upload_type
|
||||
# @return [String] protocol used for upload
|
||||
def upload_type
|
||||
return self.parameters['uploadType'] || self.parameters['upload_type']
|
||||
end
|
||||
|
||||
# @!attribute http_method
|
||||
# @return [Symbol] HTTP method if invoking a URI
|
||||
def http_method
|
||||
return @http_method ||= self.api_method.http_method.to_s.downcase.to_sym
|
||||
end
|
||||
|
||||
def http_method=(new_http_method)
|
||||
if new_http_method.kind_of?(Symbol)
|
||||
@http_method = new_http_method.to_s.downcase.to_sym
|
||||
elsif new_http_method.respond_to?(:to_str)
|
||||
@http_method = new_http_method.to_s.downcase.to_sym
|
||||
else
|
||||
raise TypeError,
|
||||
"Expected String or Symbol, got #{new_http_method.class}."
|
||||
end
|
||||
end
|
||||
|
||||
def api_method=(new_api_method)
|
||||
if new_api_method.nil? || new_api_method.kind_of?(Google::APIClient::Method)
|
||||
@api_method = new_api_method
|
||||
else
|
||||
raise TypeError,
|
||||
"Expected Google::APIClient::Method, got #{new_api_method.class}."
|
||||
end
|
||||
end
|
||||
|
||||
# @!attribute uri
|
||||
# @return [Addressable::URI] URI to send request
|
||||
def uri
|
||||
return @uri ||= self.api_method.generate_uri(self.parameters)
|
||||
end
|
||||
|
||||
def uri=(new_uri)
|
||||
@uri = Addressable::URI.parse(new_uri)
|
||||
@parameters.update(@uri.query_values) unless @uri.query_values.nil?
|
||||
end
|
||||
|
||||
|
||||
# Transmits the request with the given connection
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [Faraday::Connection] connection
|
||||
# the connection to transmit with
|
||||
# @param [TrueValue,FalseValue] is_retry
|
||||
# True if request has been previous sent
|
||||
#
|
||||
# @return [Google::APIClient::Result]
|
||||
# result of API request
|
||||
def send(connection, is_retry = false)
|
||||
self.body.rewind if is_retry && self.body.respond_to?(:rewind)
|
||||
env = self.to_env(connection)
|
||||
logger.debug { "#{self.class} Sending API request #{env[:method]} #{env[:url].to_s} #{env[:request_headers]}" }
|
||||
http_response = connection.app.call(env)
|
||||
result = self.process_http_response(http_response)
|
||||
|
||||
logger.debug { "#{self.class} Result: #{result.status} #{result.headers}" }
|
||||
|
||||
# Resumamble slightly different than other upload protocols in that it requires at least
|
||||
# 2 requests.
|
||||
if result.status == 200 && self.upload_type == 'resumable' && self.media
|
||||
upload = result.resumable_upload
|
||||
unless upload.complete?
|
||||
logger.debug { "#{self.class} Sending upload body" }
|
||||
result = upload.send(connection)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
# Convert to an HTTP request. Returns components in order of method, URI,
|
||||
# request headers, and body
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @return [Array<(Symbol, Addressable::URI, Hash, [#read,#to_str])>]
|
||||
def to_http_request
|
||||
request = (
|
||||
if self.api_method
|
||||
self.api_method.generate_request(self.parameters, self.body, self.headers)
|
||||
elsif self.uri
|
||||
unless self.parameters.empty?
|
||||
self.uri.query = Addressable::URI.form_encode(self.parameters)
|
||||
end
|
||||
[self.http_method, self.uri.to_s, self.headers, self.body]
|
||||
end)
|
||||
return request
|
||||
end
|
||||
|
||||
##
|
||||
# Hashified verison of the API request
|
||||
#
|
||||
# @return [Hash]
|
||||
def to_hash
|
||||
options = {}
|
||||
if self.api_method
|
||||
options[:api_method] = self.api_method
|
||||
options[:parameters] = self.parameters
|
||||
else
|
||||
options[:http_method] = self.http_method
|
||||
options[:uri] = self.uri
|
||||
end
|
||||
options[:headers] = self.headers
|
||||
options[:body] = self.body
|
||||
options[:media] = self.media
|
||||
unless self.authorization.nil?
|
||||
options[:authorization] = self.authorization
|
||||
end
|
||||
return options
|
||||
end
|
||||
|
||||
##
|
||||
# Prepares the request for execution, building a hash of parts
|
||||
# suitable for sending to Faraday::Connection.
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [Faraday::Connection] connection
|
||||
# Connection for building the request
|
||||
#
|
||||
# @return [Hash]
|
||||
# Encoded request
|
||||
def to_env(connection)
|
||||
method, uri, headers, body = self.to_http_request
|
||||
http_request = connection.build_request(method) do |req|
|
||||
req.url(uri.to_s)
|
||||
req.headers.update(headers)
|
||||
req.body = body
|
||||
end
|
||||
|
||||
if self.authorization.respond_to?(:generate_authenticated_request)
|
||||
http_request = self.authorization.generate_authenticated_request(
|
||||
:request => http_request,
|
||||
:connection => connection
|
||||
)
|
||||
end
|
||||
|
||||
http_request.to_env(connection)
|
||||
end
|
||||
|
||||
##
|
||||
# Convert HTTP response to an API Result
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [Faraday::Response] response
|
||||
# HTTP response
|
||||
#
|
||||
# @return [Google::APIClient::Result]
|
||||
# Processed API response
|
||||
def process_http_response(response)
|
||||
Result.new(self, response)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
##
|
||||
# Adjust headers & body for media uploads
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [Hash] options
|
||||
# @option options [Hash, Array] :parameters
|
||||
# Request parameters for the API method.
|
||||
# @option options [Google::APIClient::UploadIO] :media
|
||||
# File to upload, if media upload request
|
||||
# @option options [#to_json, #to_hash] :body_object
|
||||
# Main body of the API request. Typically hash or object that can
|
||||
# be serialized to JSON
|
||||
# @option options [#read, #to_str] :body
|
||||
# Raw body to send in POST/PUT requests
|
||||
def initialize_media_upload(options)
|
||||
self.media = options[:media]
|
||||
case self.upload_type
|
||||
when "media"
|
||||
if options[:body] || options[:body_object]
|
||||
raise ArgumentError, "Can not specify body & body object for simple uploads"
|
||||
end
|
||||
self.headers['Content-Type'] ||= self.media.content_type
|
||||
self.headers['Content-Length'] ||= self.media.length.to_s
|
||||
self.body = self.media
|
||||
when "multipart"
|
||||
unless options[:body_object]
|
||||
raise ArgumentError, "Multipart requested but no body object"
|
||||
end
|
||||
metadata = StringIO.new(serialize_body(options[:body_object]))
|
||||
build_multipart([Faraday::UploadIO.new(metadata, 'application/json', 'file.json'), self.media])
|
||||
when "resumable"
|
||||
file_length = self.media.length
|
||||
self.headers['X-Upload-Content-Type'] = self.media.content_type
|
||||
self.headers['X-Upload-Content-Length'] = file_length.to_s
|
||||
if options[:body_object]
|
||||
self.headers['Content-Type'] ||= 'application/json'
|
||||
self.body = serialize_body(options[:body_object])
|
||||
else
|
||||
self.body = ''
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Assemble a multipart message from a set of parts
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [Array<[#read,#to_str]>] parts
|
||||
# Array of parts to encode.
|
||||
# @param [String] mime_type
|
||||
# MIME type of the message
|
||||
# @param [String] boundary
|
||||
# Boundary for separating each part of the message
|
||||
def build_multipart(parts, mime_type = 'multipart/related', boundary = MULTIPART_BOUNDARY)
|
||||
env = Faraday::Env.new
|
||||
env.request = Faraday::RequestOptions.new
|
||||
env.request.boundary = boundary
|
||||
env.request_headers = {'Content-Type' => "#{mime_type};boundary=#{boundary}"}
|
||||
multipart = Faraday::Request::Multipart.new
|
||||
self.body = multipart.create_multipart(env, parts.map {|part| [nil, part]})
|
||||
self.headers.update(env[:request_headers])
|
||||
end
|
||||
|
||||
##
|
||||
# Serialize body object to JSON
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [#to_json,#to_hash] body
|
||||
# object to serialize
|
||||
#
|
||||
# @return [String]
|
||||
# JSON
|
||||
def serialize_body(body)
|
||||
return body.to_json if body.respond_to?(:to_json)
|
||||
return MultiJson.dump(body.to_hash) if body.respond_to?(:to_hash)
|
||||
raise TypeError, 'Could not convert body object to JSON.' +
|
||||
'Must respond to :to_json or :to_hash.'
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,259 +0,0 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
##
|
||||
# This class wraps a result returned by an API call.
|
||||
class Result
|
||||
extend Forwardable
|
||||
|
||||
##
|
||||
# Init the result
|
||||
#
|
||||
# @param [Google::APIClient::Request] request
|
||||
# The original request
|
||||
# @param [Faraday::Response] response
|
||||
# Raw HTTP Response
|
||||
def initialize(request, response)
|
||||
@request = request
|
||||
@response = response
|
||||
@media_upload = reference if reference.kind_of?(ResumableUpload)
|
||||
end
|
||||
|
||||
# @return [Google::APIClient::Request] Original request object
|
||||
attr_reader :request
|
||||
# @return [Faraday::Response] HTTP response
|
||||
attr_reader :response
|
||||
# @!attribute [r] reference
|
||||
# @return [Google::APIClient::Request] Original request object
|
||||
# @deprecated See {#request}
|
||||
alias_method :reference, :request # For compatibility with pre-beta clients
|
||||
|
||||
# @!attribute [r] status
|
||||
# @return [Fixnum] HTTP status code
|
||||
# @!attribute [r] headers
|
||||
# @return [Hash] HTTP response headers
|
||||
# @!attribute [r] body
|
||||
# @return [String] HTTP response body
|
||||
def_delegators :@response, :status, :headers, :body
|
||||
|
||||
# @!attribute [r] resumable_upload
|
||||
# @return [Google::APIClient::ResumableUpload] For resuming media uploads
|
||||
def resumable_upload
|
||||
@media_upload ||= (
|
||||
options = self.reference.to_hash.merge(
|
||||
:uri => self.headers['location'],
|
||||
:media => self.reference.media
|
||||
)
|
||||
Google::APIClient::ResumableUpload.new(options)
|
||||
)
|
||||
end
|
||||
|
||||
##
|
||||
# Get the content type of the response
|
||||
# @!attribute [r] media_type
|
||||
# @return [String]
|
||||
# Value of content-type header
|
||||
def media_type
|
||||
_, content_type = self.headers.detect do |h, v|
|
||||
h.downcase == 'Content-Type'.downcase
|
||||
end
|
||||
if content_type
|
||||
return content_type[/^([^;]*);?.*$/, 1].strip.downcase
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Check if request failed - which is anything other than 200/201 OK
|
||||
#
|
||||
# @!attribute [r] error?
|
||||
# @return [TrueClass, FalseClass]
|
||||
# true if result of operation is an error
|
||||
def error?
|
||||
return !self.success?
|
||||
end
|
||||
|
||||
##
|
||||
# Check if request was successful
|
||||
#
|
||||
# @!attribute [r] success?
|
||||
# @return [TrueClass, FalseClass]
|
||||
# true if result of operation was successful
|
||||
def success?
|
||||
if self.response.status == 200 || self.response.status == 201
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Extracts error messages from the response body
|
||||
#
|
||||
# @!attribute [r] error_message
|
||||
# @return [String]
|
||||
# error message, if available
|
||||
def error_message
|
||||
if self.data?
|
||||
if self.data.respond_to?(:error) &&
|
||||
self.data.error.respond_to?(:message)
|
||||
# You're going to get a terrible error message if the response isn't
|
||||
# parsed successfully as an error.
|
||||
return self.data.error.message
|
||||
elsif self.data['error'] && self.data['error']['message']
|
||||
return self.data['error']['message']
|
||||
end
|
||||
end
|
||||
return self.body
|
||||
end
|
||||
|
||||
##
|
||||
# Check for parsable data in response
|
||||
#
|
||||
# @!attribute [r] data?
|
||||
# @return [TrueClass, FalseClass]
|
||||
# true if body can be parsed
|
||||
def data?
|
||||
!(self.body.nil? || self.body.empty? || self.media_type != 'application/json')
|
||||
end
|
||||
|
||||
##
|
||||
# Return parsed version of the response body.
|
||||
#
|
||||
# @!attribute [r] data
|
||||
# @return [Object, Hash, String]
|
||||
# Object if body parsable from API schema, Hash if JSON, raw body if unable to parse
|
||||
def data
|
||||
return @data ||= (begin
|
||||
if self.data?
|
||||
media_type = self.media_type
|
||||
data = self.body
|
||||
case media_type
|
||||
when 'application/json'
|
||||
data = MultiJson.load(data)
|
||||
# Strip data wrapper, if present
|
||||
data = data['data'] if data.has_key?('data')
|
||||
else
|
||||
raise ArgumentError,
|
||||
"Content-Type not supported for parsing: #{media_type}"
|
||||
end
|
||||
if @request.api_method && @request.api_method.response_schema
|
||||
# Automatically parse using the schema designated for the
|
||||
# response of this API method.
|
||||
data = @request.api_method.response_schema.new(data)
|
||||
data
|
||||
else
|
||||
# Otherwise, return the raw unparsed value.
|
||||
# This value must be indexable like a Hash.
|
||||
data
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
##
|
||||
# Get the token used for requesting the next page of data
|
||||
#
|
||||
# @!attribute [r] next_page_token
|
||||
# @return [String]
|
||||
# next page token
|
||||
def next_page_token
|
||||
if self.data.respond_to?(:next_page_token)
|
||||
return self.data.next_page_token
|
||||
elsif self.data.respond_to?(:[])
|
||||
return self.data["nextPageToken"]
|
||||
else
|
||||
raise TypeError, "Data object did not respond to #next_page_token."
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Build a request for fetching the next page of data
|
||||
#
|
||||
# @return [Google::APIClient::Request]
|
||||
# API request for retrieving next page, nil if no page token available
|
||||
def next_page
|
||||
return nil unless self.next_page_token
|
||||
merged_parameters = Hash[self.reference.parameters].merge({
|
||||
self.page_token_param => self.next_page_token
|
||||
})
|
||||
# Because Requests can be coerced to Hashes, we can merge them,
|
||||
# preserving all context except the API method parameters that we're
|
||||
# using for pagination.
|
||||
return Google::APIClient::Request.new(
|
||||
Hash[self.reference].merge(:parameters => merged_parameters)
|
||||
)
|
||||
end
|
||||
|
||||
##
|
||||
# Get the token used for requesting the previous page of data
|
||||
#
|
||||
# @!attribute [r] prev_page_token
|
||||
# @return [String]
|
||||
# previous page token
|
||||
def prev_page_token
|
||||
if self.data.respond_to?(:prev_page_token)
|
||||
return self.data.prev_page_token
|
||||
elsif self.data.respond_to?(:[])
|
||||
return self.data["prevPageToken"]
|
||||
else
|
||||
raise TypeError, "Data object did not respond to #next_page_token."
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Build a request for fetching the previous page of data
|
||||
#
|
||||
# @return [Google::APIClient::Request]
|
||||
# API request for retrieving previous page, nil if no page token available
|
||||
def prev_page
|
||||
return nil unless self.prev_page_token
|
||||
merged_parameters = Hash[self.reference.parameters].merge({
|
||||
self.page_token_param => self.prev_page_token
|
||||
})
|
||||
# Because Requests can be coerced to Hashes, we can merge them,
|
||||
# preserving all context except the API method parameters that we're
|
||||
# using for pagination.
|
||||
return Google::APIClient::Request.new(
|
||||
Hash[self.reference].merge(:parameters => merged_parameters)
|
||||
)
|
||||
end
|
||||
|
||||
##
|
||||
# Pagination scheme used by this request/response
|
||||
#
|
||||
# @!attribute [r] pagination_type
|
||||
# @return [Symbol]
|
||||
# currently always :token
|
||||
def pagination_type
|
||||
return :token
|
||||
end
|
||||
|
||||
##
|
||||
# Name of the field that contains the pagination token
|
||||
#
|
||||
# @!attribute [r] page_token_param
|
||||
# @return [String]
|
||||
# currently always 'pageToken'
|
||||
def page_token_param
|
||||
return "pageToken"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,235 +0,0 @@
|
|||
# Copyright 2013 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'google/api_client'
|
||||
require 'google/api_client/service/stub_generator'
|
||||
require 'google/api_client/service/resource'
|
||||
require 'google/api_client/service/request'
|
||||
require 'google/api_client/service/result'
|
||||
require 'google/api_client/service/batch'
|
||||
require 'google/api_client/service/simple_file_store'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
|
||||
##
|
||||
# Experimental new programming interface at the API level.
|
||||
# Hides Google::APIClient. Designed to be easier to use, with less code.
|
||||
#
|
||||
# @example
|
||||
# calendar = Google::APIClient::Service.new('calendar', 'v3')
|
||||
# result = calendar.events.list('calendarId' => 'primary').execute()
|
||||
class Service
|
||||
include Google::APIClient::Service::StubGenerator
|
||||
extend Forwardable
|
||||
|
||||
DEFAULT_CACHE_FILE = 'discovery.cache'
|
||||
|
||||
# Cache for discovered APIs.
|
||||
@@discovered = {}
|
||||
|
||||
##
|
||||
# Creates a new Service.
|
||||
#
|
||||
# @param [String, Symbol] api_name
|
||||
# The name of the API this service will access.
|
||||
# @param [String, Symbol] api_version
|
||||
# The version of the API this service will access.
|
||||
# @param [Hash] options
|
||||
# The configuration parameters for the service.
|
||||
# @option options [Symbol, #generate_authenticated_request] :authorization
|
||||
# (:oauth_1)
|
||||
# The authorization mechanism used by the client. The following
|
||||
# mechanisms are supported out-of-the-box:
|
||||
# <ul>
|
||||
# <li><code>:two_legged_oauth_1</code></li>
|
||||
# <li><code>:oauth_1</code></li>
|
||||
# <li><code>:oauth_2</code></li>
|
||||
# </ul>
|
||||
# @option options [Boolean] :auto_refresh_token (true)
|
||||
# The setting that controls whether or not the api client attempts to
|
||||
# refresh authorization when a 401 is hit in #execute. If the token does
|
||||
# not support it, this option is ignored.
|
||||
# @option options [String] :application_name
|
||||
# The name of the application using the client.
|
||||
# @option options [String] :application_version
|
||||
# The version number of the application using the client.
|
||||
# @option options [String] :host ("www.googleapis.com")
|
||||
# The API hostname used by the client. This rarely needs to be changed.
|
||||
# @option options [String] :port (443)
|
||||
# The port number used by the client. This rarely needs to be changed.
|
||||
# @option options [String] :discovery_path ("/discovery/v1")
|
||||
# The discovery base path. This rarely needs to be changed.
|
||||
# @option options [String] :ca_file
|
||||
# Optional set of root certificates to use when validating SSL connections.
|
||||
# By default, a bundled set of trusted roots will be used.
|
||||
# @option options [#generate_authenticated_request] :authorization
|
||||
# The authorization mechanism for requests. Used only if
|
||||
# `:authenticated` is `true`.
|
||||
# @option options [TrueClass, FalseClass] :authenticated (default: true)
|
||||
# `true` if requests must be signed or somehow
|
||||
# authenticated, `false` otherwise.
|
||||
# @option options [TrueClass, FalseClass] :gzip (default: true)
|
||||
# `true` if gzip enabled, `false` otherwise.
|
||||
# @options options[Hash] :faraday_option
|
||||
# Pass through of options to set on the Faraday connection
|
||||
# @option options [Faraday::Connection] :connection
|
||||
# A custom connection to be used for all requests.
|
||||
# @option options [ActiveSupport::Cache::Store, :default] :discovery_cache
|
||||
# A cache store to place the discovery documents for loaded APIs.
|
||||
# Avoids unnecessary roundtrips to the discovery service.
|
||||
# :default loads the default local file cache store.
|
||||
def initialize(api_name, api_version, options = {})
|
||||
@api_name = api_name.to_s
|
||||
if api_version.nil?
|
||||
raise ArgumentError,
|
||||
"API version must be set"
|
||||
end
|
||||
@api_version = api_version.to_s
|
||||
if options && !options.respond_to?(:to_hash)
|
||||
raise ArgumentError,
|
||||
"expected options Hash, got #{options.class}"
|
||||
end
|
||||
|
||||
params = {}
|
||||
[:application_name, :application_version, :authorization, :host, :port,
|
||||
:discovery_path, :auto_refresh_token, :key, :user_ip,
|
||||
:ca_file, :faraday_option].each do |option|
|
||||
if options.include? option
|
||||
params[option] = options[option]
|
||||
end
|
||||
end
|
||||
|
||||
@client = Google::APIClient.new(params)
|
||||
|
||||
@connection = options[:connection] || @client.connection
|
||||
|
||||
@options = options
|
||||
|
||||
# Initialize cache store. Default to SimpleFileStore if :cache_store
|
||||
# is not provided and we have write permissions.
|
||||
if options.include? :cache_store
|
||||
@cache_store = options[:cache_store]
|
||||
else
|
||||
cache_exists = File.exists?(DEFAULT_CACHE_FILE)
|
||||
if (cache_exists && File.writable?(DEFAULT_CACHE_FILE)) ||
|
||||
(!cache_exists && File.writable?(Dir.pwd))
|
||||
@cache_store = Google::APIClient::Service::SimpleFileStore.new(
|
||||
DEFAULT_CACHE_FILE)
|
||||
end
|
||||
end
|
||||
|
||||
# Attempt to read API definition from memory cache.
|
||||
# Not thread-safe, but the worst that can happen is a cache miss.
|
||||
unless @api = @@discovered[[api_name, api_version]]
|
||||
# Attempt to read API definition from cache store, if there is one.
|
||||
# If there's a miss or no cache store, call discovery service.
|
||||
if !@cache_store.nil?
|
||||
@api = @cache_store.fetch("%s/%s" % [api_name, api_version]) do
|
||||
@client.discovered_api(api_name, api_version)
|
||||
end
|
||||
else
|
||||
@api = @client.discovered_api(api_name, api_version)
|
||||
end
|
||||
@@discovered[[api_name, api_version]] = @api
|
||||
end
|
||||
|
||||
generate_call_stubs(self, @api)
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the authorization mechanism used by the service.
|
||||
#
|
||||
# @return [#generate_authenticated_request] The authorization mechanism.
|
||||
def_delegators :@client, :authorization, :authorization=
|
||||
|
||||
##
|
||||
# The setting that controls whether or not the service attempts to
|
||||
# refresh authorization when a 401 is hit during an API call.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def_delegators :@client, :auto_refresh_token, :auto_refresh_token=
|
||||
|
||||
##
|
||||
# The application's API key issued by the API console.
|
||||
#
|
||||
# @return [String] The API key.
|
||||
def_delegators :@client, :key, :key=
|
||||
|
||||
##
|
||||
# The Faraday/HTTP connection used by this service.
|
||||
#
|
||||
# @return [Faraday::Connection]
|
||||
attr_accessor :connection
|
||||
|
||||
##
|
||||
# The cache store used for storing discovery documents.
|
||||
#
|
||||
# @return [ActiveSupport::Cache::Store,
|
||||
# Google::APIClient::Service::SimpleFileStore,
|
||||
# nil]
|
||||
attr_reader :cache_store
|
||||
|
||||
##
|
||||
# Prepares a Google::APIClient::BatchRequest object to make batched calls.
|
||||
# @param [Array] calls
|
||||
# Optional array of Google::APIClient::Service::Request to initialize
|
||||
# the batch request with.
|
||||
# @param [Proc] block
|
||||
# Callback for every call's response. Won't be called if a call defined
|
||||
# a callback of its own.
|
||||
#
|
||||
# @yield [Google::APIClient::Service::Result]
|
||||
# block to be called when result ready
|
||||
def batch(calls = nil, &block)
|
||||
Google::APIClient::Service::BatchRequest.new(self, calls, &block)
|
||||
end
|
||||
|
||||
##
|
||||
# Executes an API request.
|
||||
# Do not call directly; this method is only used by Request objects when
|
||||
# executing.
|
||||
#
|
||||
# @param [Google::APIClient::Service::Request,
|
||||
# Google::APIClient::Service::BatchCall] request
|
||||
# The request to be executed.
|
||||
def execute(request)
|
||||
if request.instance_of? Google::APIClient::Service::Request
|
||||
params = {:api_method => request.method,
|
||||
:parameters => request.parameters,
|
||||
:connection => @connection}
|
||||
if request.respond_to? :body
|
||||
if request.body.respond_to? :to_hash
|
||||
params[:body_object] = request.body
|
||||
else
|
||||
params[:body] = request.body
|
||||
end
|
||||
end
|
||||
if request.respond_to? :media
|
||||
params[:media] = request.media
|
||||
end
|
||||
[:authenticated, :gzip].each do |option|
|
||||
if @options.include? option
|
||||
params[option] = @options[option]
|
||||
end
|
||||
end
|
||||
result = @client.execute(params)
|
||||
return Google::APIClient::Service::Result.new(request, result)
|
||||
elsif request.instance_of? Google::APIClient::Service::BatchRequest
|
||||
@client.execute(request.base_batch, {:connection => @connection})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,110 +0,0 @@
|
|||
# Copyright 2013 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'google/api_client/service/result'
|
||||
require 'google/api_client/batch'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
class Service
|
||||
|
||||
##
|
||||
# Helper class to contain the result of an individual batched call.
|
||||
#
|
||||
class BatchedCallResult < Result
|
||||
# @return [Fixnum] Index of the call
|
||||
def call_index
|
||||
return @base_result.response.call_id.to_i - 1
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
#
|
||||
class BatchRequest
|
||||
##
|
||||
# Creates a new batch request.
|
||||
# This class shouldn't be instantiated directly, but rather through
|
||||
# Service.batch.
|
||||
#
|
||||
# @param [Array] calls
|
||||
# List of Google::APIClient::Service::Request to be made.
|
||||
# @param [Proc] block
|
||||
# Callback for every call's response. Won't be called if a call
|
||||
# defined a callback of its own.
|
||||
#
|
||||
# @yield [Google::APIClient::Service::Result]
|
||||
# block to be called when result ready
|
||||
def initialize(service, calls, &block)
|
||||
@service = service
|
||||
@base_batch = Google::APIClient::BatchRequest.new
|
||||
@global_callback = block if block_given?
|
||||
|
||||
if calls && calls.length > 0
|
||||
calls.each do |call|
|
||||
add(call)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Add a new call to the batch request.
|
||||
#
|
||||
# @param [Google::APIClient::Service::Request] call
|
||||
# the call to be added.
|
||||
# @param [Proc] block
|
||||
# callback for this call's response.
|
||||
#
|
||||
# @return [Google::APIClient::Service::BatchRequest]
|
||||
# the BatchRequest, for chaining
|
||||
#
|
||||
# @yield [Google::APIClient::Service::Result]
|
||||
# block to be called when result ready
|
||||
def add(call, &block)
|
||||
if !block_given? && @global_callback.nil?
|
||||
raise BatchError, 'Request needs a block'
|
||||
end
|
||||
callback = block || @global_callback
|
||||
base_call = {
|
||||
:api_method => call.method,
|
||||
:parameters => call.parameters
|
||||
}
|
||||
if call.respond_to? :body
|
||||
if call.body.respond_to? :to_hash
|
||||
base_call[:body_object] = call.body
|
||||
else
|
||||
base_call[:body] = call.body
|
||||
end
|
||||
end
|
||||
@base_batch.add(base_call) do |base_result|
|
||||
result = Google::APIClient::Service::BatchedCallResult.new(
|
||||
call, base_result)
|
||||
callback.call(result)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
##
|
||||
# Executes the batch request.
|
||||
def execute
|
||||
@service.execute(self)
|
||||
end
|
||||
|
||||
attr_reader :base_batch
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,144 +0,0 @@
|
|||
# Copyright 2013 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
class Service
|
||||
##
|
||||
# Handles an API request.
|
||||
# This contains a full definition of the request to be made (including
|
||||
# method name, parameters, body and media). The remote API call can be
|
||||
# invoked with execute().
|
||||
class Request
|
||||
##
|
||||
# Build a request.
|
||||
# This class should not be directly instantiated in user code;
|
||||
# instantiation is handled by the stub methods created on Service and
|
||||
# Resource objects.
|
||||
#
|
||||
# @param [Google::APIClient::Service] service
|
||||
# The parent Service instance that will execute the request.
|
||||
# @param [Google::APIClient::Method] method
|
||||
# The Method instance that describes the API method invoked by the
|
||||
# request.
|
||||
# @param [Hash] parameters
|
||||
# A Hash of parameter names and values to be sent in the API call.
|
||||
def initialize(service, method, parameters)
|
||||
@service = service
|
||||
@method = method
|
||||
@parameters = parameters
|
||||
@body = nil
|
||||
@media = nil
|
||||
|
||||
metaclass = (class << self; self; end)
|
||||
|
||||
# If applicable, add "body", "body=" and resource-named methods for
|
||||
# retrieving and setting the HTTP body for this request.
|
||||
# Examples of setting the body for files.insert in the Drive API:
|
||||
# request.body = object
|
||||
# request.execute
|
||||
# OR
|
||||
# request.file = object
|
||||
# request.execute
|
||||
# OR
|
||||
# request.body(object).execute
|
||||
# OR
|
||||
# request.file(object).execute
|
||||
# Examples of retrieving the body for files.insert in the Drive API:
|
||||
# object = request.body
|
||||
# OR
|
||||
# object = request.file
|
||||
if method.request_schema
|
||||
body_name = method.request_schema.data['id'].dup
|
||||
body_name[0] = body_name[0].chr.downcase
|
||||
body_name_equals = (body_name + '=').to_sym
|
||||
body_name = body_name.to_sym
|
||||
|
||||
metaclass.send(:define_method, :body) do |*args|
|
||||
if args.length == 1
|
||||
@body = args.first
|
||||
return self
|
||||
elsif args.length == 0
|
||||
return @body
|
||||
else
|
||||
raise ArgumentError,
|
||||
"wrong number of arguments (#{args.length}; expecting 0 or 1)"
|
||||
end
|
||||
end
|
||||
|
||||
metaclass.send(:define_method, :body=) do |body|
|
||||
@body = body
|
||||
end
|
||||
|
||||
metaclass.send(:alias_method, body_name, :body)
|
||||
metaclass.send(:alias_method, body_name_equals, :body=)
|
||||
end
|
||||
|
||||
# If applicable, add "media" and "media=" for retrieving and setting
|
||||
# the media object for this request.
|
||||
# Examples of setting the media object:
|
||||
# request.media = object
|
||||
# request.execute
|
||||
# OR
|
||||
# request.media(object).execute
|
||||
# Example of retrieving the media object:
|
||||
# object = request.media
|
||||
if method.media_upload
|
||||
metaclass.send(:define_method, :media) do |*args|
|
||||
if args.length == 1
|
||||
@media = args.first
|
||||
return self
|
||||
elsif args.length == 0
|
||||
return @media
|
||||
else
|
||||
raise ArgumentError,
|
||||
"wrong number of arguments (#{args.length}; expecting 0 or 1)"
|
||||
end
|
||||
end
|
||||
|
||||
metaclass.send(:define_method, :media=) do |media|
|
||||
@media = media
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the parent service capable of executing this request.
|
||||
#
|
||||
# @return [Google::APIClient::Service] The parent service.
|
||||
attr_reader :service
|
||||
|
||||
##
|
||||
# Returns the Method instance that describes the API method invoked by
|
||||
# the request.
|
||||
#
|
||||
# @return [Google::APIClient::Method] The API method description.
|
||||
attr_reader :method
|
||||
|
||||
##
|
||||
# Contains the Hash of parameter names and values to be sent as the
|
||||
# parameters for the API call.
|
||||
#
|
||||
# @return [Hash] The request parameters.
|
||||
attr_accessor :parameters
|
||||
|
||||
##
|
||||
# Executes the request.
|
||||
def execute
|
||||
@service.execute(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,40 +0,0 @@
|
|||
# Copyright 2013 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
class Service
|
||||
##
|
||||
# Handles an API resource.
|
||||
# Simple class that contains API methods and/or child resources.
|
||||
class Resource
|
||||
include Google::APIClient::Service::StubGenerator
|
||||
|
||||
##
|
||||
# Build a resource.
|
||||
# This class should not be directly instantiated in user code; resources
|
||||
# are instantiated by the stub generation mechanism on Service creation.
|
||||
#
|
||||
# @param [Google::APIClient::Service] service
|
||||
# The Service instance this resource belongs to.
|
||||
# @param [Google::APIClient::API, Google::APIClient::Resource] root
|
||||
# The node corresponding to this resource.
|
||||
def initialize(service, root)
|
||||
@service = service
|
||||
generate_call_stubs(service, root)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,164 +0,0 @@
|
|||
# Copyright 2013 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
class Service
|
||||
##
|
||||
# Handles an API result.
|
||||
# Wraps around the Google::APIClient::Result class, making it easier to
|
||||
# handle the result (e.g. pagination) and keeping it in line with the rest
|
||||
# of the Service programming interface.
|
||||
class Result
|
||||
extend Forwardable
|
||||
|
||||
##
|
||||
# Init the result.
|
||||
#
|
||||
# @param [Google::APIClient::Service::Request] request
|
||||
# The original request
|
||||
# @param [Google::APIClient::Result] base_result
|
||||
# The base result to be wrapped
|
||||
def initialize(request, base_result)
|
||||
@request = request
|
||||
@base_result = base_result
|
||||
end
|
||||
|
||||
# @!attribute [r] status
|
||||
# @return [Fixnum] HTTP status code
|
||||
# @!attribute [r] headers
|
||||
# @return [Hash] HTTP response headers
|
||||
# @!attribute [r] body
|
||||
# @return [String] HTTP response body
|
||||
def_delegators :@base_result, :status, :headers, :body
|
||||
|
||||
# @return [Google::APIClient::Service::Request] Original request object
|
||||
attr_reader :request
|
||||
|
||||
##
|
||||
# Get the content type of the response
|
||||
# @!attribute [r] media_type
|
||||
# @return [String]
|
||||
# Value of content-type header
|
||||
def_delegators :@base_result, :media_type
|
||||
|
||||
##
|
||||
# Check if request failed
|
||||
#
|
||||
# @!attribute [r] error?
|
||||
# @return [TrueClass, FalseClass]
|
||||
# true if result of operation is an error
|
||||
def_delegators :@base_result, :error?
|
||||
|
||||
##
|
||||
# Check if request was successful
|
||||
#
|
||||
# @!attribute [r] success?
|
||||
# @return [TrueClass, FalseClass]
|
||||
# true if result of operation was successful
|
||||
def_delegators :@base_result, :success?
|
||||
|
||||
##
|
||||
# Extracts error messages from the response body
|
||||
#
|
||||
# @!attribute [r] error_message
|
||||
# @return [String]
|
||||
# error message, if available
|
||||
def_delegators :@base_result, :error_message
|
||||
|
||||
##
|
||||
# Check for parsable data in response
|
||||
#
|
||||
# @!attribute [r] data?
|
||||
# @return [TrueClass, FalseClass]
|
||||
# true if body can be parsed
|
||||
def_delegators :@base_result, :data?
|
||||
|
||||
##
|
||||
# Return parsed version of the response body.
|
||||
#
|
||||
# @!attribute [r] data
|
||||
# @return [Object, Hash, String]
|
||||
# Object if body parsable from API schema, Hash if JSON, raw body if unable to parse
|
||||
def_delegators :@base_result, :data
|
||||
|
||||
##
|
||||
# Pagination scheme used by this request/response
|
||||
#
|
||||
# @!attribute [r] pagination_type
|
||||
# @return [Symbol]
|
||||
# currently always :token
|
||||
def_delegators :@base_result, :pagination_type
|
||||
|
||||
##
|
||||
# Name of the field that contains the pagination token
|
||||
#
|
||||
# @!attribute [r] page_token_param
|
||||
# @return [String]
|
||||
# currently always 'pageToken'
|
||||
def_delegators :@base_result, :page_token_param
|
||||
|
||||
##
|
||||
# Get the token used for requesting the next page of data
|
||||
#
|
||||
# @!attribute [r] next_page_token
|
||||
# @return [String]
|
||||
# next page tokenx =
|
||||
def_delegators :@base_result, :next_page_token
|
||||
|
||||
##
|
||||
# Get the token used for requesting the previous page of data
|
||||
#
|
||||
# @!attribute [r] prev_page_token
|
||||
# @return [String]
|
||||
# previous page token
|
||||
def_delegators :@base_result, :prev_page_token
|
||||
|
||||
# @!attribute [r] resumable_upload
|
||||
def resumable_upload
|
||||
# TODO(sgomes): implement resumable_upload for Service::Result
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
##
|
||||
# Build a request for fetching the next page of data
|
||||
#
|
||||
# @return [Google::APIClient::Service::Request]
|
||||
# API request for retrieving next page
|
||||
def next_page
|
||||
return nil unless self.next_page_token
|
||||
request = @request.clone
|
||||
# Make a deep copy of the parameters.
|
||||
request.parameters = Marshal.load(Marshal.dump(request.parameters))
|
||||
request.parameters[page_token_param] = self.next_page_token
|
||||
return request
|
||||
end
|
||||
|
||||
##
|
||||
# Build a request for fetching the previous page of data
|
||||
#
|
||||
# @return [Google::APIClient::Service::Request]
|
||||
# API request for retrieving previous page
|
||||
def prev_page
|
||||
return nil unless self.prev_page_token
|
||||
request = @request.clone
|
||||
# Make a deep copy of the parameters.
|
||||
request.parameters = Marshal.load(Marshal.dump(request.parameters))
|
||||
request.parameters[page_token_param] = self.prev_page_token
|
||||
return request
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,151 +0,0 @@
|
|||
# Copyright 2013 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
class Service
|
||||
|
||||
# Simple file store to be used in the event no ActiveSupport cache store
|
||||
# is provided. This is not thread-safe, and does not support a number of
|
||||
# features (such as expiration), but it's useful for the simple purpose of
|
||||
# caching discovery documents to disk.
|
||||
# Implements the basic cache methods of ActiveSupport::Cache::Store in a
|
||||
# limited fashion.
|
||||
class SimpleFileStore
|
||||
|
||||
# Creates a new SimpleFileStore.
|
||||
#
|
||||
# @param [String] file_path
|
||||
# The path to the cache file on disk.
|
||||
# @param [Object] options
|
||||
# The options to be used with this SimpleFileStore. Not implemented.
|
||||
def initialize(file_path, options = nil)
|
||||
@file_path = file_path.to_s
|
||||
end
|
||||
|
||||
# Returns true if a key exists in the cache.
|
||||
#
|
||||
# @param [String] name
|
||||
# The name of the key. Will always be converted to a string.
|
||||
# @param [Object] options
|
||||
# The options to be used with this query. Not implemented.
|
||||
def exist?(name, options = nil)
|
||||
read_file
|
||||
@cache.nil? ? nil : @cache.include?(name.to_s)
|
||||
end
|
||||
|
||||
# Fetches data from the cache and returns it, using the given key.
|
||||
# If the key is missing and no block is passed, returns nil.
|
||||
# If the key is missing and a block is passed, executes the block, sets
|
||||
# the key to its value, and returns it.
|
||||
#
|
||||
# @param [String] name
|
||||
# The name of the key. Will always be converted to a string.
|
||||
# @param [Object] options
|
||||
# The options to be used with this query. Not implemented.
|
||||
# @yield [String]
|
||||
# optional block with the default value if the key is missing
|
||||
def fetch(name, options = nil)
|
||||
read_file
|
||||
if block_given?
|
||||
entry = read(name.to_s, options)
|
||||
if entry.nil?
|
||||
value = yield name.to_s
|
||||
write(name.to_s, value)
|
||||
return value
|
||||
else
|
||||
return entry
|
||||
end
|
||||
else
|
||||
return read(name.to_s, options)
|
||||
end
|
||||
end
|
||||
|
||||
# Fetches data from the cache, using the given key.
|
||||
# Returns nil if the key is missing.
|
||||
#
|
||||
# @param [String] name
|
||||
# The name of the key. Will always be converted to a string.
|
||||
# @param [Object] options
|
||||
# The options to be used with this query. Not implemented.
|
||||
def read(name, options = nil)
|
||||
read_file
|
||||
@cache.nil? ? nil : @cache[name.to_s]
|
||||
end
|
||||
|
||||
# Writes the value to the cache, with the key.
|
||||
#
|
||||
# @param [String] name
|
||||
# The name of the key. Will always be converted to a string.
|
||||
# @param [Object] value
|
||||
# The value to be written.
|
||||
# @param [Object] options
|
||||
# The options to be used with this query. Not implemented.
|
||||
def write(name, value, options = nil)
|
||||
read_file
|
||||
@cache = {} if @cache.nil?
|
||||
@cache[name.to_s] = value
|
||||
write_file
|
||||
return nil
|
||||
end
|
||||
|
||||
# Deletes an entry in the cache.
|
||||
# Returns true if an entry is deleted.
|
||||
#
|
||||
# @param [String] name
|
||||
# The name of the key. Will always be converted to a string.
|
||||
# @param [Object] options
|
||||
# The options to be used with this query. Not implemented.
|
||||
def delete(name, options = nil)
|
||||
read_file
|
||||
return nil if @cache.nil?
|
||||
if @cache.include? name.to_s
|
||||
@cache.delete name.to_s
|
||||
write_file
|
||||
return true
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Read the entire cache file from disk.
|
||||
# Will avoid reading if there have been no changes.
|
||||
def read_file
|
||||
if !File.exist? @file_path
|
||||
@cache = nil
|
||||
else
|
||||
# Check for changes after our last read or write.
|
||||
if @last_change.nil? || File.mtime(@file_path) > @last_change
|
||||
File.open(@file_path) do |file|
|
||||
@cache = Marshal.load(file)
|
||||
@last_change = file.mtime
|
||||
end
|
||||
end
|
||||
end
|
||||
return @cache
|
||||
end
|
||||
|
||||
# Write the entire cache contents to disk.
|
||||
def write_file
|
||||
File.open(@file_path, 'w') do |file|
|
||||
Marshal.dump(@cache, file)
|
||||
end
|
||||
@last_change = File.mtime(@file_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,61 +0,0 @@
|
|||
# Copyright 2013 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'active_support/inflector'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
class Service
|
||||
##
|
||||
# Auxiliary mixin to generate resource and method stubs.
|
||||
# Used by the Service and Service::Resource classes to generate both
|
||||
# top-level and nested resources and methods.
|
||||
module StubGenerator
|
||||
def generate_call_stubs(service, root)
|
||||
metaclass = (class << self; self; end)
|
||||
|
||||
# Handle resources.
|
||||
root.discovered_resources.each do |resource|
|
||||
method_name = ActiveSupport::Inflector.underscore(resource.name).to_sym
|
||||
if !self.respond_to?(method_name)
|
||||
metaclass.send(:define_method, method_name) do
|
||||
Google::APIClient::Service::Resource.new(service, resource)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Handle methods.
|
||||
root.discovered_methods.each do |method|
|
||||
method_name = ActiveSupport::Inflector.underscore(method.name).to_sym
|
||||
if !self.respond_to?(method_name)
|
||||
metaclass.send(:define_method, method_name) do |*args|
|
||||
if args.length > 1
|
||||
raise ArgumentError,
|
||||
"wrong number of arguments (#{args.length} for 1)"
|
||||
elsif !args.first.respond_to?(:to_hash) && !args.first.nil?
|
||||
raise ArgumentError,
|
||||
"expected parameter Hash, got #{args.first.class}"
|
||||
else
|
||||
return Google::APIClient::Service::Request.new(
|
||||
service, method, args.first
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,48 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'google/apis/version'
|
||||
require 'logger'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
ROOT = File.expand_path('..', File.dirname(__dir__))
|
||||
|
||||
# @!attribute [rw] logger
|
||||
# @return [Logger] The logger.
|
||||
def self.logger
|
||||
@logger ||= rails_logger || default_logger
|
||||
end
|
||||
|
||||
class << self
|
||||
attr_writer :logger
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Create and configure a logger
|
||||
# @return [Logger]
|
||||
def self.default_logger
|
||||
logger = Logger.new($stdout)
|
||||
logger.level = Logger::WARN
|
||||
logger
|
||||
end
|
||||
|
||||
# Check to see if client is being used in a Rails environment and ge the logger if present
|
||||
# @return [Logger]
|
||||
def self.rails_logger
|
||||
::Rails.logger if defined?(::Rails) && ::Rails.respond_to?(:logger) && ::Rails.logger
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,128 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'active_support/inflector'
|
||||
require 'addressable/uri'
|
||||
require 'addressable/template'
|
||||
require 'google/apis/core/http_command'
|
||||
require 'google/apis/errors'
|
||||
require 'multi_json'
|
||||
require 'retriable'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
module Core
|
||||
# Command for executing most basic API request with JSON requests/responses
|
||||
class ApiCommand < HttpCommand
|
||||
JSON_CONTENT_TYPE = 'application/json'
|
||||
FIELDS_PARAM = 'fields'
|
||||
RATE_LIMIT_ERRORS = %w(rateLimitExceeded userRateLimitExceeded)
|
||||
|
||||
# JSON serializer for request objects
|
||||
# @return [Google::Apis::Core::JsonRepresentation]
|
||||
attr_accessor :request_representation
|
||||
|
||||
# Request body to serialize
|
||||
# @return [Object]
|
||||
attr_accessor :request_object
|
||||
|
||||
# JSON serializer for response objects
|
||||
# @return [Google::Apis::Core::JsonRepresentation]
|
||||
attr_accessor :response_representation
|
||||
|
||||
# Class to instantiate when de-serializing responses
|
||||
# @return [Object]
|
||||
attr_accessor :response_class
|
||||
|
||||
# Serialize the request body
|
||||
#
|
||||
# @return [void]
|
||||
def prepare!
|
||||
query[FIELDS_PARAM] = normalize_fields_param(query[FIELDS_PARAM]) if query.key?(FIELDS_PARAM)
|
||||
if request_representation && request_object
|
||||
header[:content_type] ||= JSON_CONTENT_TYPE
|
||||
self.body = request_representation.new(request_object).to_json(skip_undefined: true)
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
# Deserialize the response body if present
|
||||
#
|
||||
# @param [String] content_type
|
||||
# Content type of body
|
||||
# @param [String, #read] body
|
||||
# Response body
|
||||
# @return [Object]
|
||||
# Response object
|
||||
# noinspection RubyUnusedLocalVariable
|
||||
def decode_response_body(content_type, body)
|
||||
return super unless response_representation
|
||||
return super if content_type.nil?
|
||||
return nil unless content_type.start_with?(JSON_CONTENT_TYPE)
|
||||
instance = response_class.new
|
||||
response_representation.new(instance).from_json(body, unwrap: response_class)
|
||||
instance
|
||||
end
|
||||
|
||||
# Check the response and raise error if needed
|
||||
#
|
||||
# @param [Fixnum] status
|
||||
# HTTP status code of response
|
||||
# @param [String] body
|
||||
# HTTP response body
|
||||
# @return [void]
|
||||
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
||||
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
||||
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
||||
def check_status(status, body = nil)
|
||||
case status
|
||||
when 400, 402...500
|
||||
error = parse_error(body)
|
||||
if error
|
||||
logger.debug { error }
|
||||
fail Google::Apis::RateLimitError, error if RATE_LIMIT_ERRORS.include?(error['reason'])
|
||||
end
|
||||
super(status, error)
|
||||
else
|
||||
super(status, body)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Attempt to parse a JSON error message, returning the first found error
|
||||
# @param [String] body
|
||||
# HTTP response body
|
||||
# @return [Hash]
|
||||
def parse_error(body)
|
||||
hash = MultiJson.load(body)
|
||||
hash['error']['errors'].first
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
|
||||
# Convert field names from ruby conventions to original names in JSON
|
||||
#
|
||||
# @param [String] fields
|
||||
# Value of 'fields' param
|
||||
# @return [String]
|
||||
# Updated header value
|
||||
def normalize_fields_param(fields)
|
||||
# TODO: Generate map of parameter names during code gen. Small possibility that camelization fails
|
||||
fields.gsub(/:/, '').gsub(/[\w_]+/) { |str| ActiveSupport::Inflector.camelize(str, false) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,314 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'addressable/uri'
|
||||
require 'addressable/template'
|
||||
require 'google/apis/version'
|
||||
require 'google/apis/core/api_command'
|
||||
require 'google/apis/core/batch'
|
||||
require 'google/apis/core/upload'
|
||||
require 'google/apis/core/download'
|
||||
require 'google/apis/options'
|
||||
require 'googleauth'
|
||||
require 'hurley'
|
||||
require 'hurley/addressable'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
module Core
|
||||
# Base service for all APIs. Not to be used directly.
|
||||
#
|
||||
class BaseService
|
||||
# Root URL (host/port) for the API
|
||||
# @return [Addressable::URI]
|
||||
attr_accessor :root_url
|
||||
|
||||
# Additional path prefix for all API methods
|
||||
# @return [Addressable::URI]
|
||||
attr_accessor :base_path
|
||||
|
||||
# Alternate path prefix for media uploads
|
||||
# @return [Addressable::URI]
|
||||
attr_accessor :upload_path
|
||||
|
||||
# Alternate path prefix for all batch methods
|
||||
# @return [Addressable::URI]
|
||||
attr_accessor :batch_path
|
||||
|
||||
# HTTP client
|
||||
# @return [Hurley::Client]
|
||||
attr_accessor :client
|
||||
|
||||
# General settings
|
||||
# @return [Google::Apis::ClientOptions]
|
||||
attr_accessor :client_options
|
||||
|
||||
# Default options for all requests
|
||||
# @return [Google::Apis::RequestOptions]
|
||||
attr_accessor :request_options
|
||||
|
||||
# @param [String,Addressable::URI] root_url
|
||||
# Root URL for the API
|
||||
# @param [String,Addressable::URI] base_path
|
||||
# Additional path prefix for all API methods
|
||||
# @api private
|
||||
def initialize(root_url, base_path)
|
||||
self.root_url = root_url
|
||||
self.base_path = base_path
|
||||
self.upload_path = "upload/#{base_path}"
|
||||
self.batch_path = 'batch'
|
||||
self.client_options = Google::Apis::ClientOptions.default.dup
|
||||
self.request_options = Google::Apis::RequestOptions.default.dup
|
||||
end
|
||||
|
||||
# @!attribute [rw] authorization
|
||||
# @return [Signet::OAuth2::Client]
|
||||
# OAuth2 credentials
|
||||
def authorization=(authorization)
|
||||
request_options.authorization = authorization
|
||||
end
|
||||
|
||||
def authorization
|
||||
request_options.authorization
|
||||
end
|
||||
|
||||
# TODO: with(options) method
|
||||
|
||||
# Perform a batch request. Calls made within the block are sent in a single network
|
||||
# request to the server.
|
||||
#
|
||||
# @example
|
||||
# service.batch do |service|
|
||||
# service.get_item(id1) do |res, err|
|
||||
# # process response for 1st call
|
||||
# end
|
||||
# # ...
|
||||
# service.get_item(idN) do |res, err|
|
||||
# # process response for Nth call
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# @param [Hash, Google::Apis::RequestOptions] options
|
||||
# Request-specific options
|
||||
# @yield [self]
|
||||
# @return [void]
|
||||
def batch(options = nil)
|
||||
batch_command = BatchCommand.new(:post, Addressable::URI.parse(root_url + batch_path))
|
||||
batch_command.options = request_options.merge(options)
|
||||
apply_command_defaults(batch_command)
|
||||
begin
|
||||
Thread.current[:google_api_batch] = batch_command
|
||||
yield self
|
||||
ensure
|
||||
Thread.current[:google_api_batch] = nil
|
||||
end
|
||||
batch_command.execute(client)
|
||||
end
|
||||
|
||||
# Perform a batch upload request. Calls made within the block are sent in a single network
|
||||
# request to the server. Batch uploads are useful for uploading multiple small files. For larger
|
||||
# files, use single requests which use a resumable upload protocol.
|
||||
#
|
||||
# @example
|
||||
# service.batch do |service|
|
||||
# service.insert_item(upload_source: 'file1.txt') do |res, err|
|
||||
# # process response for 1st call
|
||||
# end
|
||||
# # ...
|
||||
# service.insert_item(upload_source: 'fileN.txt') do |res, err|
|
||||
# # process response for Nth call
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# @param [Hash, Google::Apis::RequestOptions] options
|
||||
# Request-specific options
|
||||
# @yield [self]
|
||||
# @return [void]
|
||||
def batch_upload(options = nil)
|
||||
batch_command = BatchUploadCommand.new(:put, Addressable::URI.parse(root_url + upload_path))
|
||||
batch_command.options = request_options.merge(options)
|
||||
apply_command_defaults(batch_command)
|
||||
begin
|
||||
Thread.current[:google_api_batch] = batch_command
|
||||
yield self
|
||||
ensure
|
||||
Thread.current[:google_api_batch] = nil
|
||||
end
|
||||
batch_command.execute(client)
|
||||
end
|
||||
|
||||
# Get the current HTTP client
|
||||
# @return [Hurley::Client]
|
||||
def client
|
||||
@client ||= new_client
|
||||
end
|
||||
|
||||
|
||||
# Simple escape hatch for making API requests directly to a given
|
||||
# URL. This is not intended to be used as a generic HTTP client
|
||||
# and should be used only in cases where no service method exists
|
||||
# (e.g. fetching an export link for a Google Drive file.)
|
||||
#
|
||||
# @param [Symbol] method
|
||||
# HTTP method as symbol (e.g. :get, :post, :put, ...)
|
||||
# @param [String] url
|
||||
# URL to call
|
||||
# @param [Hash<String,String] params
|
||||
# Optional hash of query parameters
|
||||
# @param [#read] body
|
||||
# Optional body for POST/PUT
|
||||
# @param [IO, String] download_dest
|
||||
# IO stream or filename to receive content download
|
||||
# @param [Google::Apis::RequestOptions] options
|
||||
# Request-specific options
|
||||
#
|
||||
# @yield [result, err] Result & error if block supplied
|
||||
# @yieldparam result [String] HTTP response body
|
||||
# @yieldparam err [StandardError] error object if request failed
|
||||
#
|
||||
# @return [String] HTTP response body
|
||||
def http(method, url, params: nil, body: nil, download_dest: nil, options: nil, &block)
|
||||
if download_dest
|
||||
command = DownloadCommand.new(method, url, body: body)
|
||||
else
|
||||
command = HttpCommand.new(method, url, body: body)
|
||||
end
|
||||
command.options = request_options.merge(options)
|
||||
apply_command_defaults(command)
|
||||
command.query.merge(Hash(params))
|
||||
execute_or_queue_command(command, &block)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Create a new upload command.
|
||||
#
|
||||
# @param [symbol] method
|
||||
# HTTP method for uploading (typically :put or :post)
|
||||
# @param [String] path
|
||||
# Additional path to upload endpoint, appended to API base path
|
||||
# @param [Hash, Google::Apis::RequestOptions] options
|
||||
# Request-specific options
|
||||
# @return [Google::Apis::Core::UploadCommand]
|
||||
def make_upload_command(method, path, options)
|
||||
template = Addressable::Template.new(root_url + upload_path + path)
|
||||
if batch?
|
||||
command = MultipartUploadCommand.new(method, template)
|
||||
else
|
||||
command = ResumableUploadCommand.new(method, template)
|
||||
end
|
||||
command.options = request_options.merge(options)
|
||||
apply_command_defaults(command)
|
||||
command
|
||||
end
|
||||
|
||||
# Create a new download command.
|
||||
#
|
||||
# @param [symbol] method
|
||||
# HTTP method for uploading (typically :get)
|
||||
# @param [String] path
|
||||
# Additional path to download endpoint, appended to API base path
|
||||
# @param [Hash, Google::Apis::RequestOptions] options
|
||||
# Request-specific options
|
||||
# @return [Google::Apis::Core::DownloadCommand]
|
||||
def make_download_command(method, path, options)
|
||||
template = Addressable::Template.new(root_url + base_path + path)
|
||||
command = DownloadCommand.new(method, template)
|
||||
command.options = request_options.merge(options)
|
||||
command.query['alt'] = 'media'
|
||||
apply_command_defaults(command)
|
||||
command
|
||||
end
|
||||
|
||||
# Create a new command.
|
||||
#
|
||||
# @param [symbol] method
|
||||
# HTTP method (:get, :post, :delete, etc...)
|
||||
# @param [String] path
|
||||
# Additional path, appended to API base path
|
||||
# @param [Hash, Google::Apis::RequestOptions] options
|
||||
# Request-specific options
|
||||
# @return [Google::Apis::Core::DownloadCommand]
|
||||
def make_simple_command(method, path, options)
|
||||
template = Addressable::Template.new(root_url + base_path + path)
|
||||
command = ApiCommand.new(method, template)
|
||||
command.options = request_options.merge(options)
|
||||
apply_command_defaults(command)
|
||||
command
|
||||
end
|
||||
|
||||
# Execute the request. If a batch is in progress, the request is added to the batch instead.
|
||||
#
|
||||
# @param [Google::Apis::Core::HttpCommand] command
|
||||
# Command to execute
|
||||
# @return [Object] response object if command executed and no callback supplied
|
||||
# @yield [result, err] Result & error if block supplied
|
||||
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
||||
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
||||
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
||||
def execute_or_queue_command(command, &callback)
|
||||
batch_command = current_batch
|
||||
if batch_command
|
||||
batch_command.add(command, &callback)
|
||||
nil
|
||||
else
|
||||
command.execute(client, &callback)
|
||||
end
|
||||
end
|
||||
|
||||
# Update commands with service-specific options. To be implemented by subclasses
|
||||
# @param [Google::Apis::Core::HttpCommand] _command
|
||||
def apply_command_defaults(_command)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Get the current batch context
|
||||
#
|
||||
# @return [Google:Apis::Core::BatchRequest]
|
||||
def current_batch
|
||||
Thread.current[:google_api_batch]
|
||||
end
|
||||
|
||||
# Check if a batch is in progress
|
||||
# @return [Boolean]
|
||||
def batch?
|
||||
!current_batch.nil?
|
||||
end
|
||||
|
||||
# Create a new HTTP client
|
||||
# @return [Hurley::Client]
|
||||
def new_client
|
||||
client = Hurley::Client.new
|
||||
client.request_options.timeout = request_options.timeout_sec
|
||||
client.request_options.proxy = client_options.proxy_url
|
||||
client.request_options.query_class = Hurley::Query::Flat
|
||||
client.ssl_options.ca_file = File.join(Google::Apis::ROOT, 'lib', 'cacerts.pem')
|
||||
client.header[:user_agent] = user_agent
|
||||
client
|
||||
end
|
||||
|
||||
# Build the user agent header
|
||||
# @return [String]
|
||||
def user_agent
|
||||
sprintf('%s/%s google-api-ruby-client/%s %s (gzip)',
|
||||
client_options.application_name,
|
||||
client_options.application_version,
|
||||
Google::Apis::VERSION,
|
||||
Google::Apis::OS_VERSION)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,222 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'hurley'
|
||||
require 'google/apis/core/multipart'
|
||||
require 'google/apis/core/http_command'
|
||||
require 'google/apis/core/upload'
|
||||
require 'google/apis/core/download'
|
||||
require 'addressable/uri'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
module Core
|
||||
# Wrapper request for batching multiple calls in a single server request
|
||||
class BatchCommand < HttpCommand
|
||||
BATCH_BOUNDARY = 'RubyApiBatchRequest'.freeze
|
||||
MULTIPART_MIXED = 'multipart/mixed'
|
||||
|
||||
# @param [symbol] method
|
||||
# HTTP method
|
||||
# @param [String,Addressable::URI, Addressable::Template] url
|
||||
# HTTP URL or template
|
||||
def initialize(method, url)
|
||||
super(method, url)
|
||||
@calls = []
|
||||
end
|
||||
|
||||
##
|
||||
# Add a new call to the batch request.
|
||||
#
|
||||
# @param [Google::Apis::Core::HttpCommand] call API Request to add
|
||||
# @yield [result, err] Result & error when response available
|
||||
# @return [Google::Apis::Core::BatchCommand] self
|
||||
def add(call, &block)
|
||||
ensure_valid_command(call)
|
||||
@calls << [call, block]
|
||||
self
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
##
|
||||
# Deconstruct the batch response and process the individual results
|
||||
#
|
||||
# @param [String] content_type
|
||||
# Content type of body
|
||||
# @param [String, #read] body
|
||||
# Response body
|
||||
# @return [Object]
|
||||
# Response object
|
||||
def decode_response_body(content_type, body)
|
||||
m = /.*boundary=(.+)/.match(content_type)
|
||||
if m
|
||||
parts = split_parts(body, m[1])
|
||||
deserializer = CallDeserializer.new
|
||||
parts.each_index do |index|
|
||||
call, callback = @calls[index]
|
||||
begin
|
||||
result = call.process_response(*deserializer.to_http_response(parts[index])) unless call.nil?
|
||||
success(result, &callback)
|
||||
rescue => e
|
||||
error(e, &callback)
|
||||
end
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def split_parts(body, boundary)
|
||||
parts = body.split(/\r?\n?--#{Regexp.escape(boundary)}/)
|
||||
parts[1...-1]
|
||||
end
|
||||
|
||||
# Encode the batch request
|
||||
# @return [void]
|
||||
# @raise [Google::Apis::BatchError] if batch is empty
|
||||
def prepare!
|
||||
fail BatchError, 'Cannot make an empty batch request' if @calls.empty?
|
||||
|
||||
serializer = CallSerializer.new
|
||||
multipart = Multipart.new(boundary: BATCH_BOUNDARY, content_type: MULTIPART_MIXED)
|
||||
@calls.each do |(call, _)|
|
||||
io = serializer.to_upload_io(call)
|
||||
multipart.add_upload(io)
|
||||
end
|
||||
self.body = multipart.assemble
|
||||
|
||||
header[:content_type] = multipart.content_type
|
||||
header[:content_length] = "#{body.length}"
|
||||
super
|
||||
end
|
||||
|
||||
def ensure_valid_command(command)
|
||||
if command.is_a?(Google::Apis::Core::BaseUploadCommand) || command.is_a?(Google::Apis::Core::DownloadCommand)
|
||||
fail Google::Apis::ClientError, 'Can not include media requests in batch'
|
||||
end
|
||||
fail Google::Apis::ClientError, 'Invalid command object' unless command.is_a?(HttpCommand)
|
||||
end
|
||||
end
|
||||
|
||||
# Wrapper request for batching multiple uploads in a single server request
|
||||
class BatchUploadCommand < BatchCommand
|
||||
def ensure_valid_command(command)
|
||||
fail Google::Apis::ClientError, 'Can only include upload commands in batch' \
|
||||
unless command.is_a?(Google::Apis::Core::BaseUploadCommand)
|
||||
end
|
||||
|
||||
def prepare!
|
||||
header['X-Goog-Upload-Protocol'] = 'batch'
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# Serializes a command for embedding in a multipart batch request
|
||||
# @private
|
||||
class CallSerializer
|
||||
HTTP_CONTENT_TYPE = 'application/http'
|
||||
|
||||
##
|
||||
# Serialize a single batched call for assembling the multipart message
|
||||
#
|
||||
# @param [Google::Apis::Core::HttpCommand] call
|
||||
# the call to serialize.
|
||||
# @return [Hurley::UploadIO]
|
||||
# the serialized request
|
||||
def to_upload_io(call)
|
||||
call.prepare!
|
||||
parts = []
|
||||
parts << build_head(call)
|
||||
parts << build_body(call) unless call.body.nil?
|
||||
length = parts.inject(0) { |a, e| a + e.length }
|
||||
Hurley::UploadIO.new(Hurley::CompositeReadIO.new(length, *parts),
|
||||
HTTP_CONTENT_TYPE,
|
||||
'ruby-api-request')
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def build_head(call)
|
||||
request_head = "#{call.method.to_s.upcase} #{Addressable::URI.parse(call.url).request_uri} HTTP/1.1"
|
||||
call.header.each do |key, value|
|
||||
request_head << sprintf("\r\n%s: %s", key, value)
|
||||
end
|
||||
request_head << sprintf("\r\nHost: %s", call.url.host)
|
||||
request_head << "\r\n\r\n"
|
||||
StringIO.new(request_head)
|
||||
end
|
||||
|
||||
def build_body(call)
|
||||
return nil if call.body.nil?
|
||||
return call.body if call.body.respond_to?(:read)
|
||||
StringIO.new(call.body)
|
||||
end
|
||||
end
|
||||
|
||||
# Deconstructs a raw HTTP response part
|
||||
# @private
|
||||
class CallDeserializer
|
||||
# Convert a single batched response into a BatchedCallResponse object.
|
||||
#
|
||||
# @param [String] call_response
|
||||
# the response to parse.
|
||||
# @return [Array<(Fixnum, Hurley::Header, String)>]
|
||||
# Status, header, and response body.
|
||||
def to_http_response(call_response)
|
||||
_, outer_body = split_header_and_body(call_response)
|
||||
status_line, payload = outer_body.split(/\n/, 2)
|
||||
_, status = status_line.split(' ', 3)
|
||||
|
||||
header, body = split_header_and_body(payload)
|
||||
[status.to_i, header, body]
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Auxiliary method to split the header from the body in an HTTP response.
|
||||
#
|
||||
# @param [String] response
|
||||
# the response to parse.
|
||||
# @return [Array<(Hurley::Header, String)>]
|
||||
# the header and the body, separately.
|
||||
def split_header_and_body(response)
|
||||
header = Hurley::Header.new
|
||||
payload = response.lstrip
|
||||
while payload
|
||||
line, payload = payload.split(/\n/, 2)
|
||||
line.sub!(/\s+\z/, '')
|
||||
break if line.empty?
|
||||
match = /\A([^:]+):\s*/.match(line)
|
||||
fail BatchError, sprintf('Invalid header line in response: %s', line) if match.nil?
|
||||
header[match[1]] = match.post_match
|
||||
end
|
||||
[header, payload]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,94 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'google/apis/core/multipart'
|
||||
require 'google/apis/core/api_command'
|
||||
require 'google/apis/errors'
|
||||
require 'addressable/uri'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
module Core
|
||||
# Streaming/resumable media download support
|
||||
class DownloadCommand < ApiCommand
|
||||
RANGE_HEADER = 'range'
|
||||
|
||||
# File or IO to write content to
|
||||
# @return [String, File, #write]
|
||||
attr_accessor :download_dest
|
||||
|
||||
# Ensure the download destination is a writable stream.
|
||||
#
|
||||
# @return [void]
|
||||
def prepare!
|
||||
@state = :start
|
||||
@download_url = nil
|
||||
@offset = 0
|
||||
if download_dest.respond_to?(:write)
|
||||
@download_io = download_dest
|
||||
@close_io_on_finish = false
|
||||
elsif download_dest.is_a?(String)
|
||||
@download_io = File.open(download_dest, 'wb')
|
||||
@close_io_on_finish = true
|
||||
else
|
||||
@download_io = StringIO.new('', 'wb')
|
||||
@close_io_on_finish = false
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
# Close IO stream when command done. Only closes the stream if it was opened by the command.
|
||||
def release!
|
||||
@download_io.close if @close_io_on_finish
|
||||
end
|
||||
|
||||
# Execute the upload request once. Overrides the default implementation to handle streaming/chunking
|
||||
# of file content.
|
||||
#
|
||||
# @private
|
||||
# @param [Hurley::Client] client
|
||||
# HTTP client
|
||||
# @yield [result, err] Result or error if block supplied
|
||||
# @return [Object]
|
||||
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
||||
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
||||
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
||||
def execute_once(client, &block)
|
||||
client.get(@download_url || url) do |req|
|
||||
apply_request_options(req)
|
||||
if @offset > 0
|
||||
logger.debug { sprintf('Resuming download from offset %d', @offset) }
|
||||
req.header[RANGE_HEADER] = sprintf('bytes=%d-', @offset)
|
||||
end
|
||||
req.on_body do |res, chunk|
|
||||
check_status(res.status_code, chunk) unless res.status_code.nil?
|
||||
logger.debug { sprintf('Writing chunk (%d bytes)', chunk.length) }
|
||||
@offset += chunk.length
|
||||
@download_io.write(chunk)
|
||||
@download_io.flush
|
||||
end
|
||||
end
|
||||
if @close_io_on_finish
|
||||
result = nil
|
||||
else
|
||||
result = @download_io
|
||||
end
|
||||
success(result, &block)
|
||||
rescue => e
|
||||
error(e, rethrow: true, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,44 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
module Core
|
||||
# Adds to_hash to objects
|
||||
module Hashable
|
||||
# Convert object to hash representation
|
||||
#
|
||||
# @return [Hash]
|
||||
def to_h
|
||||
Hash[instance_variables.map { |k| [k[1..-1].to_sym, Hashable.process_value(instance_variable_get(k))] }]
|
||||
end
|
||||
|
||||
# Recursively serialize an object
|
||||
#
|
||||
# @param [Object] val
|
||||
# @return [Hash]
|
||||
def self.process_value(val)
|
||||
case val
|
||||
when Hash
|
||||
Hash[val.map {|k, v| [k.to_sym, Hashable.process_value(v)] }]
|
||||
when Array
|
||||
val.map{ |v| Hashable.process_value(v) }
|
||||
else
|
||||
val.respond_to?(:to_h) ? val.to_h : val
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,275 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'addressable/uri'
|
||||
require 'addressable/template'
|
||||
require 'google/apis/options'
|
||||
require 'google/apis/errors'
|
||||
require 'retriable'
|
||||
require 'hurley'
|
||||
require 'hurley/addressable'
|
||||
require 'google/apis/core/logging'
|
||||
require 'pp'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
module Core
|
||||
# Command for HTTP request/response.
|
||||
class HttpCommand
|
||||
include Logging
|
||||
|
||||
RETRIABLE_ERRORS = [Google::Apis::ServerError, Google::Apis::RateLimitError, Google::Apis::TransmissionError]
|
||||
|
||||
# Request options
|
||||
# @return [Google::Apis::RequestOptions]
|
||||
attr_accessor :options
|
||||
|
||||
# HTTP request URL
|
||||
# @return [String, Addressable::URI]
|
||||
attr_accessor :url
|
||||
|
||||
# HTTP headers
|
||||
# @return [Hurley::Header]
|
||||
attr_accessor :header
|
||||
|
||||
# Request body
|
||||
# @return [#read]
|
||||
attr_accessor :body
|
||||
|
||||
# HTTP method
|
||||
# @return [symbol]
|
||||
attr_accessor :method
|
||||
|
||||
# HTTP Client
|
||||
# @return [Hurley::Client]
|
||||
attr_accessor :connection
|
||||
|
||||
# Query params
|
||||
# @return [Hash]
|
||||
attr_accessor :query
|
||||
|
||||
# Path params for URL Template
|
||||
# @return [Hash]
|
||||
attr_accessor :params
|
||||
|
||||
# @param [symbol] method
|
||||
# HTTP method
|
||||
# @param [String,Addressable::URI, Addressable::Template] url
|
||||
# HTTP URL or template
|
||||
# @param [String, #read] body
|
||||
# Request body
|
||||
def initialize(method, url, body: nil)
|
||||
self.options = Google::Apis::RequestOptions.default.dup
|
||||
self.url = url
|
||||
self.url = Addressable::Template.new(url) if url.is_a?(String)
|
||||
self.method = method
|
||||
self.header = Hurley::Header.new
|
||||
self.body = body
|
||||
self.query = {}
|
||||
self.params = {}
|
||||
end
|
||||
|
||||
# Execute the command, retrying as necessary
|
||||
#
|
||||
# @param [Hurley::Client] client
|
||||
# HTTP client
|
||||
# @yield [result, err] Result or error if block supplied
|
||||
# @return [Object]
|
||||
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
||||
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
||||
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
||||
def execute(client)
|
||||
prepare!
|
||||
proc = block_given? ? Proc.new : nil
|
||||
begin
|
||||
Retriable.retriable tries: options.retries + 1,
|
||||
base_interval: 1,
|
||||
multiplier: 2,
|
||||
on: RETRIABLE_ERRORS do |try|
|
||||
# This 2nd level retriable only catches auth errors, and supports 1 retry, which allows
|
||||
# auth to be re-attempted without having to retry all sorts of other failures like
|
||||
# NotFound, etc
|
||||
auth_tries = (try == 1 && authorization_refreshable? ? 2 : 1)
|
||||
Retriable.retriable tries: auth_tries,
|
||||
on: [Google::Apis::AuthorizationError],
|
||||
on_retry: proc { |*| refresh_authorization } do
|
||||
return execute_once(client, &proc)
|
||||
end
|
||||
end
|
||||
rescue => e
|
||||
raise e if proc.nil?
|
||||
end
|
||||
ensure
|
||||
release!
|
||||
end
|
||||
|
||||
# Refresh the authorization authorization after a 401 error
|
||||
#
|
||||
# @private
|
||||
# @return [void]
|
||||
def refresh_authorization
|
||||
# Handled implicitly by auth lib, here in case need to override
|
||||
logger.debug('Retrying after authentication failure')
|
||||
end
|
||||
|
||||
# Check if attached credentials can be automatically refreshed
|
||||
# @return [Boolean]
|
||||
def authorization_refreshable?
|
||||
options.authorization.respond_to?(:apply!)
|
||||
end
|
||||
|
||||
# Prepare the request (e.g. calculate headers, serialize data, etc) before sending
|
||||
#
|
||||
# @private
|
||||
# @return [void]
|
||||
def prepare!
|
||||
header.update(options.header) if options && options.header
|
||||
self.url = url.expand(params) if url.is_a?(Addressable::Template)
|
||||
url.query_values = query
|
||||
end
|
||||
|
||||
# Release any resources used by this command
|
||||
# @private
|
||||
# @return [void]
|
||||
def release!
|
||||
end
|
||||
|
||||
# Check the response and either decode body or raise error
|
||||
#
|
||||
# @param [Fixnum] status
|
||||
# HTTP status code of response
|
||||
# @param [Hurley::Header] header
|
||||
# Response headers
|
||||
# @param [String, #read] body
|
||||
# Response body
|
||||
# @return [Object]
|
||||
# Response object
|
||||
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
||||
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
||||
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
||||
def process_response(status, header, body)
|
||||
check_status(status, body)
|
||||
decode_response_body(header[:content_type], body)
|
||||
end
|
||||
|
||||
# Check the response and raise error if needed
|
||||
#
|
||||
# @param [Fixnum] status
|
||||
# HTTP status code of response
|
||||
# @param [String] body
|
||||
# HTTP response body
|
||||
# @return [void]
|
||||
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
||||
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
||||
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
||||
def check_status(status, body = nil)
|
||||
# TODO: 304 Not Modified depends on context...
|
||||
case status
|
||||
when 200...300
|
||||
nil
|
||||
when 301, 302, 303, 307
|
||||
fail Google::Apis::RedirectError, header[:location]
|
||||
when 401
|
||||
fail Google::Apis::AuthorizationError, body
|
||||
when 304, 400, 402...500
|
||||
fail Google::Apis::ClientError, body
|
||||
when 500...600
|
||||
fail Google::Apis::ServerError, body
|
||||
else
|
||||
logger.warn(sprintf('Encountered unexpected status code %s', status))
|
||||
fail Google::Apis::TransmissionError, body
|
||||
end
|
||||
end
|
||||
|
||||
# Process the actual response body. Intended to be overridden by subclasses
|
||||
#
|
||||
# @param [String] _content_type
|
||||
# Content type of body
|
||||
# @param [String, #read] body
|
||||
# Response body
|
||||
# @return [Object]
|
||||
def decode_response_body(_content_type, body)
|
||||
body
|
||||
end
|
||||
|
||||
# Process a success response
|
||||
# @param [Object] result
|
||||
# Result object
|
||||
# @return [Object] result if no block given
|
||||
# @yield [result, nil] if block given
|
||||
def success(result, &block)
|
||||
logger.debug { sprintf('Success - %s', PP.pp(result, '')) }
|
||||
block.call(result, nil) if block_given?
|
||||
result
|
||||
end
|
||||
|
||||
# Process an error response
|
||||
# @param [StandardError] err
|
||||
# Error object
|
||||
# @param [Boolean] rethrow
|
||||
# True if error should be raised again after handling
|
||||
# @return [void]
|
||||
# @yield [nil, err] if block given
|
||||
# @raise [StandardError] if no block
|
||||
def error(err, rethrow: false, &block)
|
||||
logger.debug { sprintf('Error - %s', PP.pp(err, '')) }
|
||||
err = Google::Apis::TransmissionError.new(err) if err.is_a?(Hurley::ClientError)
|
||||
block.call(nil, err) if block_given?
|
||||
fail err if rethrow || block.nil?
|
||||
end
|
||||
|
||||
# Execute the command once.
|
||||
#
|
||||
# @private
|
||||
# @param [Hurley::Client] client
|
||||
# HTTP client
|
||||
# @yield [result, err] Result or error if block supplied
|
||||
# @return [Object]
|
||||
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
||||
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
||||
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
||||
def execute_once(client, &block)
|
||||
body.rewind if body.respond_to?(:rewind)
|
||||
begin
|
||||
logger.debug { sprintf('Sending HTTP %s %s', method, url) }
|
||||
response = client.send(method, url, body) do |req|
|
||||
apply_request_options(req)
|
||||
end
|
||||
logger.debug { response.status_code }
|
||||
logger.debug { response.inspect }
|
||||
response = process_response(response.status_code, response.header, response.body)
|
||||
success(response, &block)
|
||||
rescue => e
|
||||
logger.debug { sprintf('Caught error %s', e) }
|
||||
error(e, rethrow: true, &block)
|
||||
end
|
||||
end
|
||||
|
||||
# Update the request with any specified options.
|
||||
# @param [Hurley::Request] req
|
||||
# HTTP request
|
||||
# @return [void]
|
||||
def apply_request_options(req)
|
||||
if options.authorization.respond_to?(:apply!)
|
||||
options.authorization.apply!(req.header)
|
||||
elsif options.authorization.is_a?(String)
|
||||
req.header[:authorization] = sprintf('Bearer %s', options.authorization)
|
||||
end
|
||||
req.header.update(header)
|
||||
req.options.timeout = options.timeout_sec
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,122 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'representable/json'
|
||||
require 'representable/json/hash'
|
||||
require 'representable/coercion'
|
||||
require 'base64'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
module Core
|
||||
# Support for serializing hashes + propery value/nil/unset tracking
|
||||
# To be included in representers as a feature.
|
||||
# @private
|
||||
module JsonRepresentationSupport
|
||||
def self.included(base)
|
||||
base.extend(JsonSupport)
|
||||
end
|
||||
|
||||
# @private
|
||||
module JsonSupport
|
||||
# Returns a customized getter function for Representable. Allows
|
||||
# indifferent hash/attribute access.
|
||||
#
|
||||
# @param [String] name Property name
|
||||
# @return [Proc]
|
||||
def getter_fn(name)
|
||||
ivar_name = "@#{name}".to_sym
|
||||
lambda do |_|
|
||||
if respond_to?(:[])
|
||||
self[name] || instance_variable_get(ivar_name)
|
||||
else
|
||||
instance_variable_get(ivar_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a customized function for Representable that checks whether or not
|
||||
# an attribute should be serialized. Allows proper patch semantics by distinguishing
|
||||
# between nil & unset values
|
||||
#
|
||||
# @param [String] name Property name
|
||||
# @return [Proc]
|
||||
def if_fn(name)
|
||||
ivar_name = "@#{name}".to_sym
|
||||
lambda do |opts|
|
||||
if opts[:skip_undefined]
|
||||
if respond_to?(:key?)
|
||||
self.key?(name) || instance_variable_defined?(ivar_name)
|
||||
else
|
||||
instance_variable_defined?(ivar_name)
|
||||
end
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def set_default_options(name, options)
|
||||
if options[:base64]
|
||||
options[:render_filter] = ->(value, _doc, *_args) { Base64.urlsafe_encode64(value) }
|
||||
options[:parse_filter] = ->(fragment, _doc, *_args) { Base64.urlsafe_decode64(fragment) }
|
||||
end
|
||||
options[:render_nil] = true
|
||||
options[:getter] = getter_fn(name)
|
||||
options[:if] = if_fn(name)
|
||||
end
|
||||
|
||||
# Define a single value property
|
||||
#
|
||||
# @param [String] name
|
||||
# Property name
|
||||
# @param [Hash] options
|
||||
def property(name, options = {})
|
||||
set_default_options(name, options)
|
||||
super(name, options)
|
||||
end
|
||||
|
||||
# Define a collection property
|
||||
#
|
||||
# @param [String] name
|
||||
# Property name
|
||||
# @param [Hash] options
|
||||
def collection(name, options = {})
|
||||
set_default_options(name, options)
|
||||
super(name, options)
|
||||
end
|
||||
|
||||
# Define a hash property
|
||||
#
|
||||
# @param [String] name
|
||||
# Property name
|
||||
# @param [Hash] options
|
||||
def hash(name, options)
|
||||
set_default_options(name, options)
|
||||
super(name, options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Base decorator for JSON representers
|
||||
#
|
||||
# @see https://github.com/apotonick/representable
|
||||
class JsonRepresentation < Representable::Decorator
|
||||
include Representable::JSON
|
||||
include Representable::Coercion
|
||||
feature JsonRepresentationSupport
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -12,15 +12,19 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'google/apis'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
module VERSION
|
||||
MAJOR = 0
|
||||
MINOR = 8
|
||||
TINY = 6
|
||||
PATCH = nil
|
||||
STRING = [MAJOR, MINOR, TINY, PATCH].compact.join('.')
|
||||
module Apis
|
||||
module Core
|
||||
# Logging support
|
||||
module Logging
|
||||
# Get the logger instance
|
||||
# @return [Logger]
|
||||
def logger
|
||||
Google::Apis.logger
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,173 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'hurley'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
module Core
|
||||
# Part of a multipart request for holding JSON data
|
||||
#
|
||||
# @private
|
||||
class JsonPart
|
||||
include Hurley::Multipart::Part
|
||||
|
||||
# @return [Fixnum]
|
||||
# Length of part
|
||||
attr_reader :length
|
||||
|
||||
# @param [String] boundary
|
||||
# Multipart boundary
|
||||
# @param [String] value
|
||||
# JSON content
|
||||
def initialize(boundary, value)
|
||||
@part = build_part(boundary, value)
|
||||
@length = @part.bytesize
|
||||
@io = StringIO.new(@part)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Format the part
|
||||
#
|
||||
# @param [String] boundary
|
||||
# Multipart boundary
|
||||
# @param [String] value
|
||||
# JSON content
|
||||
# @return [String]
|
||||
def build_part(boundary, value)
|
||||
part = ''
|
||||
part << "--#{boundary}\r\n"
|
||||
part << "Content-Type: application/json\r\n"
|
||||
part << "\r\n"
|
||||
part << "#{value}\r\n"
|
||||
end
|
||||
end
|
||||
|
||||
# Part of a multipart request for holding arbitrary content. Modified
|
||||
# from Hurley::Multipart::FilePart to remove Content-Disposition
|
||||
#
|
||||
# @private
|
||||
class FilePart
|
||||
include Hurley::Multipart::Part
|
||||
|
||||
# @return [Fixnum]
|
||||
# Length of part
|
||||
attr_reader :length
|
||||
|
||||
# @param [String] boundary
|
||||
# Multipart boundary
|
||||
# @param [Google::Apis::Core::UploadIO] io
|
||||
# IO stream
|
||||
# @param [Hash] header
|
||||
# Additional headers
|
||||
def initialize(boundary, io, header = {})
|
||||
file_length = io.respond_to?(:length) ? io.length : File.size(io.local_path)
|
||||
|
||||
@head = build_head(boundary, io.content_type, file_length,
|
||||
io.respond_to?(:opts) ? io.opts.merge(header) : header)
|
||||
|
||||
@length = @head.bytesize + file_length + FOOT.length
|
||||
@io = Hurley::CompositeReadIO.new(@length, StringIO.new(@head), io, StringIO.new(FOOT))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Construct the header for the part
|
||||
#
|
||||
# @param [String] boundary
|
||||
# Multipart boundary
|
||||
# @param [String] type
|
||||
# Content type for the part
|
||||
# @param [Fixnum] content_len
|
||||
# Length of the part
|
||||
# @param [Hash] header
|
||||
# Headers for the part
|
||||
def build_head(boundary, type, content_len, header)
|
||||
sprintf(HEAD_FORMAT,
|
||||
boundary,
|
||||
content_len.to_i,
|
||||
header[:content_type] || type,
|
||||
header[:content_transfer_encoding] || DEFAULT_TR_ENCODING)
|
||||
end
|
||||
|
||||
DEFAULT_TR_ENCODING = 'binary'.freeze
|
||||
FOOT = "\r\n".freeze
|
||||
HEAD_FORMAT = <<-END
|
||||
--%s\r
|
||||
Content-Length: %d\r
|
||||
Content-Type: %s\r
|
||||
Content-Transfer-Encoding: %s\r
|
||||
\r
|
||||
END
|
||||
end
|
||||
|
||||
# Helper for building multipart requests
|
||||
class Multipart
|
||||
MULTIPART_RELATED = 'multipart/related'
|
||||
DEFAULT_BOUNDARY = 'RubyApiClientMultiPart'
|
||||
|
||||
# @return [String]
|
||||
# Content type header
|
||||
attr_reader :content_type
|
||||
|
||||
# @param [String] content_type
|
||||
# Content type for the multipart request
|
||||
# @param [String] boundary
|
||||
# Part delimiter
|
||||
|
||||
def initialize(content_type: MULTIPART_RELATED, boundary: nil)
|
||||
@parts = []
|
||||
@boundary = boundary || DEFAULT_BOUNDARY
|
||||
@content_type = "#{content_type}; boundary=#{boundary}"
|
||||
end
|
||||
|
||||
# Append JSON data part
|
||||
#
|
||||
# @param [String] body
|
||||
# JSON text
|
||||
# @return [self]
|
||||
def add_json(body)
|
||||
@parts << Google::Apis::Core::JsonPart.new(@boundary, body)
|
||||
self
|
||||
end
|
||||
|
||||
# Append arbitrary data as a part
|
||||
#
|
||||
# @param [Google::Apis::Core::UploadIO] upload_io
|
||||
# IO stream
|
||||
# @return [self]
|
||||
def add_upload(upload_io)
|
||||
@parts << Google::Apis::Core::FilePart.new(@boundary, upload_io)
|
||||
self
|
||||
end
|
||||
|
||||
# Assemble the multipart requests
|
||||
#
|
||||
# @return [IO]
|
||||
# IO stream
|
||||
def assemble
|
||||
@parts << Hurley::Multipart::EpiloguePart.new(@boundary)
|
||||
ios = []
|
||||
len = 0
|
||||
@parts.each do |part|
|
||||
len += part.length
|
||||
ios << part.to_io
|
||||
end
|
||||
Hurley::CompositeReadIO.new(len, *ios)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,275 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'google/apis/core/multipart'
|
||||
require 'google/apis/core/http_command'
|
||||
require 'google/apis/core/api_command'
|
||||
require 'google/apis/errors'
|
||||
require 'addressable/uri'
|
||||
require 'mime-types'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
module Core
|
||||
# Extension of Hurley's UploadIO to add length accessor
|
||||
class UploadIO < Hurley::UploadIO
|
||||
OCTET_STREAM_CONTENT_TYPE = 'application/octet-stream'
|
||||
|
||||
# Get the length of the stream
|
||||
# @return [Fixnum]
|
||||
def length
|
||||
io.respond_to?(:length) ? io.length : File.size(local_path)
|
||||
end
|
||||
|
||||
# Create a new instance given a file path
|
||||
# @param [String, File] file_name
|
||||
# Path to file
|
||||
# @param [String] content_type
|
||||
# Optional content type. If nil, will attempt to auto-detect
|
||||
# @return [Google::Apis::Core::UploadIO]
|
||||
def self.from_file(file_name, content_type: nil)
|
||||
if content_type.nil?
|
||||
type = MIME::Types.of(file_name)
|
||||
content_type = type.first.content_type unless type.nil? || type.empty?
|
||||
end
|
||||
new(file_name, content_type || OCTET_STREAM_CONTENT_TYPE)
|
||||
end
|
||||
|
||||
# Wraps an IO stream in UploadIO
|
||||
# @param [#read] io
|
||||
# IO to wrap
|
||||
# @param [String] content_type
|
||||
# Optional content type.
|
||||
# @return [Google::Apis::Core::UploadIO]
|
||||
def self.from_io(io, content_type: OCTET_STREAM_CONTENT_TYPE)
|
||||
new(io, content_type)
|
||||
end
|
||||
end
|
||||
|
||||
# Base upload command. Not intended to be used directly
|
||||
# @private
|
||||
class BaseUploadCommand < ApiCommand
|
||||
UPLOAD_PROTOCOL_HEADER = 'X-Goog-Upload-Protocol'
|
||||
UPLOAD_CONTENT_TYPE_HEADER = 'X-Goog-Upload-Header-Content-Type'
|
||||
UPLOAD_CONTENT_LENGTH = 'X-Goog-Upload-Header-Content-Length'
|
||||
|
||||
# File name or IO containing the content to upload
|
||||
# @return [String, File, #read]
|
||||
attr_accessor :upload_source
|
||||
|
||||
# Content type of the upload material
|
||||
# @return [String]
|
||||
attr_accessor :upload_content_type
|
||||
|
||||
# Content, as UploadIO
|
||||
# @return [Google::Apis::Core::UploadIO]
|
||||
attr_accessor :upload_io
|
||||
|
||||
# Ensure the content is readable and wrapped in an {{Google::Apis::Core::UploadIO}} instance.
|
||||
#
|
||||
# @return [void]
|
||||
# @raise [Google::Apis::ClientError] if upload source is invalid
|
||||
def prepare!
|
||||
super
|
||||
if upload_source.is_a?(IO) || upload_source.is_a?(StringIO)
|
||||
self.upload_io = UploadIO.from_io(upload_source, content_type: upload_content_type)
|
||||
@close_io_on_finish = false
|
||||
elsif upload_source.is_a?(String)
|
||||
self.upload_io = UploadIO.from_file(upload_source, content_type: upload_content_type)
|
||||
@close_io_on_finish = true
|
||||
else
|
||||
fail Google::Apis::ClientError, 'Invalid upload source'
|
||||
end
|
||||
end
|
||||
|
||||
# Close IO stream when command done. Only closes the stream if it was opened by the command.
|
||||
def release!
|
||||
upload_io.close if @close_io_on_finish
|
||||
end
|
||||
end
|
||||
|
||||
# Implementation of the raw upload protocol
|
||||
class RawUploadCommand < BaseUploadCommand
|
||||
RAW_PROTOCOL = 'raw'
|
||||
|
||||
# Ensure the content is readable and wrapped in an {{Google::Apis::Core::UploadIO}} instance.
|
||||
#
|
||||
# @return [void]
|
||||
# @raise [Google::Apis::ClientError] if upload source is invalid
|
||||
def prepare!
|
||||
super
|
||||
self.body = upload_io
|
||||
header[UPLOAD_PROTOCOL_HEADER] = RAW_PROTOCOL
|
||||
header[UPLOAD_CONTENT_TYPE_HEADER] = upload_io.content_type
|
||||
end
|
||||
end
|
||||
|
||||
# Implementation of the multipart upload protocol
|
||||
class MultipartUploadCommand < BaseUploadCommand
|
||||
UPLOAD_BOUNDARY = 'RubyApiClientUpload'
|
||||
MULTIPART_PROTOCOL = 'multipart'
|
||||
MULTIPART_RELATED = 'multipart/related'
|
||||
|
||||
# Encode the multipart request
|
||||
#
|
||||
# @return [void]
|
||||
# @raise [Google::Apis::ClientError] if upload source is invalid
|
||||
def prepare!
|
||||
super
|
||||
@multipart = Multipart.new(boundary: UPLOAD_BOUNDARY, content_type: MULTIPART_RELATED)
|
||||
@multipart.add_json(body)
|
||||
@multipart.add_upload(upload_io)
|
||||
self.body = @multipart.assemble
|
||||
header[:content_type] = @multipart.content_type
|
||||
header[UPLOAD_PROTOCOL_HEADER] = MULTIPART_PROTOCOL
|
||||
end
|
||||
end
|
||||
|
||||
# Implementation of the resumable upload protocol
|
||||
class ResumableUploadCommand < BaseUploadCommand
|
||||
UPLOAD_COMMAND_HEADER = 'X-Goog-Upload-Command'
|
||||
UPLOAD_OFFSET_HEADER = 'X-Goog-Upload-Offset'
|
||||
BYTES_RECEIVED_HEADER = 'X-Goog-Upload-Size-Received'
|
||||
UPLOAD_URL_HEADER = 'X-Goog-Upload-URL'
|
||||
UPLOAD_STATUS_HEADER = 'X-Goog-Upload-Status'
|
||||
STATUS_ACTIVE = 'active'
|
||||
STATUS_FINAL = 'final'
|
||||
STATUS_CANCELLED = 'cancelled'
|
||||
RESUMABLE = 'resumable'
|
||||
START_COMMAND = 'start'
|
||||
QUERY_COMMAND = 'query'
|
||||
UPLOAD_COMMAND = 'upload, finalize'
|
||||
|
||||
# Reset upload to initial state.
|
||||
#
|
||||
# @return [void]
|
||||
# @raise [Google::Apis::ClientError] if upload source is invalid
|
||||
def prepare!
|
||||
@state = :start
|
||||
@upload_url = nil
|
||||
@offset = 0
|
||||
super
|
||||
end
|
||||
|
||||
# Check the to see if the upload is complete or needs to be resumed.
|
||||
#
|
||||
# @param [Fixnum] status
|
||||
# HTTP status code of response
|
||||
# @param [Hurley::Header] header
|
||||
# Response headers
|
||||
# @param [String, #read] body
|
||||
# Response body
|
||||
# @return [Object]
|
||||
# Response object
|
||||
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
||||
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
||||
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
||||
def process_response(status, header, body)
|
||||
@offset = Integer(header[BYTES_RECEIVED_HEADER]) if header.key?(BYTES_RECEIVED_HEADER)
|
||||
@upload_url = header[UPLOAD_URL_HEADER] if header.key?(UPLOAD_URL_HEADER)
|
||||
|
||||
upload_status = header[UPLOAD_STATUS_HEADER]
|
||||
logger.debug { sprintf('Upload status %s', upload_status) }
|
||||
if upload_status == STATUS_ACTIVE
|
||||
@state = :active
|
||||
elsif upload_status == STATUS_FINAL
|
||||
@state = :final
|
||||
elsif upload_status == STATUS_CANCELLED
|
||||
@state = :cancelled
|
||||
fail Google::Apis::ClientError, body
|
||||
end
|
||||
super(status, header, body)
|
||||
end
|
||||
|
||||
# Send the start command to initiate the upload
|
||||
#
|
||||
# @param [Hurley::Client] client
|
||||
# HTTP client
|
||||
# @return [Hurley::Response]
|
||||
# @raise [Google::Apis::ServerError] Unable to send the request
|
||||
def send_start_command(client)
|
||||
logger.debug { sprintf('Sending upload start command to %s', url) }
|
||||
client.send(method, url, body) do |req|
|
||||
apply_request_options(req)
|
||||
req.header[UPLOAD_PROTOCOL_HEADER] = RESUMABLE
|
||||
req.header[UPLOAD_COMMAND_HEADER] = START_COMMAND
|
||||
req.header[UPLOAD_CONTENT_LENGTH] = upload_io.length.to_s
|
||||
req.header[UPLOAD_CONTENT_TYPE_HEADER] = upload_io.content_type
|
||||
end
|
||||
rescue => e
|
||||
raise Google::Apis::ServerError, e.message
|
||||
end
|
||||
|
||||
# Query for the status of an incomplete upload
|
||||
#
|
||||
# @param [Hurley::Client] client
|
||||
# HTTP client
|
||||
# @return [Hurley::Response]
|
||||
# @raise [Google::Apis::ServerError] Unable to send the request
|
||||
def send_query_command(client)
|
||||
logger.debug { sprintf('Sending upload query command to %s', @upload_url) }
|
||||
client.post(@upload_url, nil) do |req|
|
||||
apply_request_options(req)
|
||||
req.header[UPLOAD_COMMAND_HEADER] = QUERY_COMMAND
|
||||
end
|
||||
end
|
||||
|
||||
# Send the actual content
|
||||
#
|
||||
# @param [Hurley::Client] client
|
||||
# HTTP client
|
||||
# @return [Hurley::Response]
|
||||
# @raise [Google::Apis::ServerError] Unable to send the request
|
||||
def send_upload_command(client)
|
||||
logger.debug { sprintf('Sending upload command to %s', @upload_url) }
|
||||
content = upload_io
|
||||
content.pos = @offset
|
||||
client.post(@upload_url, content) do |req|
|
||||
apply_request_options(req)
|
||||
req.header[UPLOAD_COMMAND_HEADER] = UPLOAD_COMMAND
|
||||
req.header[UPLOAD_OFFSET_HEADER] = @offset.to_s
|
||||
end
|
||||
end
|
||||
|
||||
# Execute the upload request once. This will typically perform two HTTP requests -- one to initiate or query
|
||||
# for the status of the upload, the second to send the (remaining) content.
|
||||
#
|
||||
# @private
|
||||
# @param [Hurley::Client] client
|
||||
# HTTP client
|
||||
# @yield [result, err] Result or error if block supplied
|
||||
# @return [Object]
|
||||
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
||||
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
||||
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
||||
def execute_once(client, &block)
|
||||
if @state == :start
|
||||
response = send_start_command(client)
|
||||
else
|
||||
response = send_query_command(client)
|
||||
end
|
||||
result = process_response(response.status_code, response.header, response.body)
|
||||
if @state == :active
|
||||
response = send_upload_command(client)
|
||||
result = process_response(response.status_code, response.header, response.body)
|
||||
end
|
||||
|
||||
success(result, &block) if @state == :final
|
||||
rescue => e
|
||||
error(e, rethrow: true, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -12,54 +12,58 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
##
|
||||
# An error which is raised when there is an unexpected response or other
|
||||
# transport error that prevents an operation from succeeding.
|
||||
class TransmissionError < StandardError
|
||||
attr_reader :result
|
||||
def initialize(message = nil, result = nil)
|
||||
super(message)
|
||||
@result = result
|
||||
module Apis
|
||||
# Base error, capable of wrapping another
|
||||
class Error < StandardError
|
||||
def initialize(err)
|
||||
@cause = nil
|
||||
|
||||
if err.respond_to?(:backtrace)
|
||||
super(err.message)
|
||||
@cause = err
|
||||
else
|
||||
super(err.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
def backtrace
|
||||
if @cause
|
||||
@cause.backtrace
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# An error which is raised when there is an unexpected response or other
|
||||
# transport error that prevents an operation from succeeding.
|
||||
class TransmissionError < Error
|
||||
end
|
||||
|
||||
# An exception that is raised if a redirect is required
|
||||
#
|
||||
class RedirectError < TransmissionError
|
||||
class RedirectError < Error
|
||||
end
|
||||
|
||||
##
|
||||
# An exception that is raised if a method is called with missing or
|
||||
# invalid parameter values.
|
||||
class ValidationError < StandardError
|
||||
end
|
||||
|
||||
##
|
||||
# A 4xx class HTTP error occurred.
|
||||
class ClientError < TransmissionError
|
||||
class ClientError < Error
|
||||
end
|
||||
|
||||
# A 4xx class HTTP error occurred.
|
||||
class RateLimitError < Error
|
||||
end
|
||||
|
||||
##
|
||||
# A 401 HTTP error occurred.
|
||||
class AuthorizationError < ClientError
|
||||
class AuthorizationError < Error
|
||||
end
|
||||
|
||||
##
|
||||
# A 5xx class HTTP error occurred.
|
||||
class ServerError < TransmissionError
|
||||
end
|
||||
|
||||
##
|
||||
# An exception that is raised if an ID token could not be validated.
|
||||
class InvalidIDTokenError < StandardError
|
||||
class ServerError < Error
|
||||
end
|
||||
|
||||
# Error class for problems in batch requests.
|
||||
class BatchError < StandardError
|
||||
class BatchError < Error
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,70 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'google/apis/discovery_v1'
|
||||
require 'google/apis/generator/annotator'
|
||||
require 'google/apis/generator/model'
|
||||
require 'google/apis/generator/template'
|
||||
require 'active_support/inflector'
|
||||
require 'yaml'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
# Generates ruby classes for APIs from discovery documents
|
||||
# @private
|
||||
class Generator
|
||||
Discovery = Google::Apis::DiscoveryV1
|
||||
|
||||
# Load templates
|
||||
def initialize(api_names: nil)
|
||||
@names = Google::Apis::Generator::Names.new(api_names || File.join(Google::Apis::ROOT, 'api_names.yaml'))
|
||||
@module_template = Template.load('module.rb')
|
||||
@service_template = Template.load('service.rb')
|
||||
@classes_template = Template.load('classes.rb')
|
||||
@representations_template = Template.load('representations.rb')
|
||||
end
|
||||
|
||||
# Generates ruby source for an API
|
||||
#
|
||||
# @param [String] json
|
||||
# API Description, as JSON text
|
||||
# @return [Hash<String,String>]
|
||||
# Hash of generated files keyed by path
|
||||
def render(json)
|
||||
api = parse_description(json)
|
||||
Annotator.process(api, @names)
|
||||
base_path = ActiveSupport::Inflector.underscore(api.qualified_name)
|
||||
context = {
|
||||
'api' => api
|
||||
}
|
||||
files = {}
|
||||
files[base_path + '.rb'] = @module_template.render(context)
|
||||
files[File.join(base_path, 'service.rb')] = @service_template.render(context)
|
||||
files[File.join(base_path, 'classes.rb')] = @classes_template.render(context)
|
||||
files[File.join(base_path, 'representations.rb')] = @representations_template.render(context)
|
||||
files
|
||||
end
|
||||
|
||||
# Dump mapping of API names
|
||||
# @return [String] Mapping of paths to ruby names in YAML format
|
||||
def dump_api_names
|
||||
@names.dump
|
||||
end
|
||||
|
||||
def parse_description(json)
|
||||
Discovery::RestDescription::Representation.new(Discovery::RestDescription.new).from_json(json)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,271 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'logger'
|
||||
require 'erb'
|
||||
require 'yaml'
|
||||
require 'multi_json'
|
||||
require 'active_support/inflector'
|
||||
require 'google/apis/core/logging'
|
||||
require 'google/apis/generator/template'
|
||||
require 'google/apis/generator/model'
|
||||
require 'google/apis/generator/helpers'
|
||||
require 'addressable/uri'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
# @private
|
||||
class Generator
|
||||
# Helper for picking names for methods, properties, types, etc. Performs various normaliations
|
||||
# as well as allows for overriding individual names from a configuration file for cases
|
||||
# where algorithmic approaches produce poor APIs.
|
||||
class Names
|
||||
include Google::Apis::Core::Logging
|
||||
include NameHelpers
|
||||
|
||||
def initialize(file_path = nil)
|
||||
if file_path
|
||||
logger.info { sprintf('Loading API names from %s', file_path) }
|
||||
@names = YAML.load(File.read(file_path)) || {}
|
||||
else
|
||||
@names = {}
|
||||
end
|
||||
@path = []
|
||||
end
|
||||
|
||||
def with_path(path)
|
||||
@path.push(path)
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
@path.pop
|
||||
end
|
||||
end
|
||||
|
||||
def infer_parameter_name
|
||||
pick_name(normalize_param_name(@path.last))
|
||||
end
|
||||
|
||||
# Determine the ruby method name to generate for a given method in discovery.
|
||||
# @param [Google::Apis::DiscoveryV1::RestMethod] method
|
||||
# Fragment of the discovery doc describing the method
|
||||
def infer_method_name(method)
|
||||
pick_name(infer_method_name_for_rpc(method) || infer_method_name_from_id(method))
|
||||
end
|
||||
|
||||
def infer_property_name
|
||||
pick_name(normalize_property_name(@path.last))
|
||||
end
|
||||
|
||||
def pick_name(alt_name)
|
||||
preferred_name = @names[key]
|
||||
if preferred_name && preferred_name == alt_name
|
||||
logger.warn { sprintf("Unnecessary name override '%s': %s", key, alt_name) }
|
||||
elsif preferred_name.nil?
|
||||
preferred_name = @names[key] = alt_name
|
||||
end
|
||||
preferred_name
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
@names[key] = value
|
||||
end
|
||||
|
||||
def dump
|
||||
YAML.dump(@names)
|
||||
end
|
||||
|
||||
def key
|
||||
@path.reduce('') { |a, e| a + '/' + e }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# For RPC style methods, pick a name based off the request objects.
|
||||
# @param [Google::Apis::DiscoveryV1::RestMethod] method
|
||||
# Fragment of the discovery doc describing the method
|
||||
def infer_method_name_for_rpc(method)
|
||||
return nil if method.request.nil?
|
||||
verb = ActiveSupport::Inflector.underscore(method.id.split('.').last)
|
||||
match = method.request._ref.match(/(.*)(?i:request)/)
|
||||
return nil if match.nil?
|
||||
name = ActiveSupport::Inflector.underscore(match[1])
|
||||
return nil unless name == verb || name.start_with?(verb + '_')
|
||||
name
|
||||
end
|
||||
|
||||
# For REST style methods, build a method name from the verb/resource(s) in the method
|
||||
# id. IDs are in the form <api>.<resource>.<verb>
|
||||
# @param [Google::Apis::DiscoveryV1::RestMethod] method
|
||||
# Fragment of the discovery doc describing the method
|
||||
def infer_method_name_from_id(method)
|
||||
parts = method.id.split('.')
|
||||
parts.shift
|
||||
verb = parts.pop
|
||||
return ActiveSupport::Inflector.underscore(verb) if parts.empty?
|
||||
resource_name = parts.pop
|
||||
method_name = verb + '_'
|
||||
method_name += parts.map { |p| ActiveSupport::Inflector.singularize(p) }.join('_') + '_' unless parts.empty?
|
||||
if pluralize_method?(verb)
|
||||
method_name += ActiveSupport::Inflector.pluralize(resource_name)
|
||||
else
|
||||
method_name += ActiveSupport::Inflector.singularize(resource_name)
|
||||
end
|
||||
ActiveSupport::Inflector.underscore(method_name)
|
||||
end
|
||||
end
|
||||
|
||||
# Modifies an API description to support ruby code generation. Primarily does:
|
||||
# - Ensure all names follow appopriate ruby conventions
|
||||
# - Maps types to ruby types, classes, and resolves $refs
|
||||
# - Attempts to simplify names where possible to make APIs more sensible
|
||||
class Annotator
|
||||
include NameHelpers
|
||||
include Google::Apis::Core::Logging
|
||||
|
||||
# Don't expose these in the API directly.
|
||||
PARAMETER_BLACKLIST = %w(alt access_token bearer_token oauth_token pp prettyPrint
|
||||
$.xgafv callback upload_protocol uploadType)
|
||||
|
||||
# Prepare the API for the templates.
|
||||
# @param [Google::Apis::DiscoveryV1::RestDescription] description
|
||||
# API Description
|
||||
def self.process(description, api_names = nil)
|
||||
Annotator.new(description, api_names).annotate_api
|
||||
end
|
||||
|
||||
# @param [Google::Apis::DiscoveryV1::RestDescription] description
|
||||
# API Description
|
||||
# @param [Google::Api::Generator::Names] api_names
|
||||
# Name helper instanace
|
||||
def initialize(description, api_names = nil)
|
||||
api_names = Names.new if api_names.nil?
|
||||
@names = api_names
|
||||
@rest_description = description
|
||||
@registered_types = []
|
||||
@deferred_types = []
|
||||
@strip_prefixes = []
|
||||
@all_methods = {}
|
||||
@path = []
|
||||
end
|
||||
|
||||
def annotate_api
|
||||
@names.with_path(@rest_description.id) do
|
||||
@strip_prefixes << @rest_description.name
|
||||
if @rest_description.auth
|
||||
@rest_description.auth.oauth2.scopes.each do |key, value|
|
||||
value.constant = constantize_scope(key)
|
||||
end
|
||||
end
|
||||
@rest_description.parameters.reject! { |k, _v| PARAMETER_BLACKLIST.include?(k) }
|
||||
annotate_parameters(@rest_description.parameters)
|
||||
annotate_resource(@rest_description.name, @rest_description)
|
||||
@rest_description.schemas.each do |k, v|
|
||||
annotate_type(k, v, @rest_description)
|
||||
end unless @rest_description.schemas.nil?
|
||||
end
|
||||
resolve_type_references
|
||||
resolve_variants
|
||||
end
|
||||
|
||||
def annotate_type(name, type, parent)
|
||||
@names.with_path(name) do
|
||||
type.name = name
|
||||
type.path = @names.key
|
||||
type.generated_name = @names.infer_property_name
|
||||
if type.type == 'object'
|
||||
type.generated_class_name = ActiveSupport::Inflector.camelize(type.generated_name)
|
||||
@registered_types << type
|
||||
end
|
||||
type.parent = parent
|
||||
@deferred_types << type if type._ref
|
||||
type.properties.each do |k, v|
|
||||
annotate_type(k, v, type)
|
||||
end unless type.properties.nil?
|
||||
if type.additional_properties
|
||||
type.type = 'hash'
|
||||
annotate_type(ActiveSupport::Inflector.singularize(type.generated_name), type.additional_properties,
|
||||
parent)
|
||||
end
|
||||
annotate_type(ActiveSupport::Inflector.singularize(type.generated_name), type.items, parent) if type.items
|
||||
end
|
||||
end
|
||||
|
||||
def annotate_resource(name, resource, parent_resource = nil)
|
||||
@strip_prefixes << name
|
||||
resource.parent = parent_resource unless parent_resource.nil?
|
||||
resource.api_methods.each do |_k, v|
|
||||
annotate_method(v, resource)
|
||||
end unless resource.api_methods.nil?
|
||||
|
||||
resource.resources.each do |k, v|
|
||||
annotate_resource(k, v, resource)
|
||||
end unless resource.resources.nil?
|
||||
end
|
||||
|
||||
def annotate_method(method, parent_resource = nil)
|
||||
@names.with_path(method.id) do
|
||||
method.parent = parent_resource
|
||||
method.generated_name = @names.infer_method_name(method)
|
||||
check_duplicate_method(method)
|
||||
annotate_parameters(method.parameters)
|
||||
end
|
||||
end
|
||||
|
||||
def annotate_parameters(parameters)
|
||||
parameters.each do |key, value|
|
||||
@names.with_path(key) do
|
||||
value.name = key
|
||||
value.generated_name = @names.infer_parameter_name
|
||||
@deferred_types << value if value._ref
|
||||
end
|
||||
end unless parameters.nil?
|
||||
end
|
||||
|
||||
def resolve_type_references
|
||||
@deferred_types.each do |type|
|
||||
if type._ref
|
||||
ref = @rest_description.schemas[type._ref]
|
||||
ivars = ref.instance_variables - [:@name, :@generated_name]
|
||||
(ivars).each do |var|
|
||||
type.instance_variable_set(var, ref.instance_variable_get(var))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def resolve_variants
|
||||
@deferred_types.each do |type|
|
||||
if type.variant
|
||||
type.variant.map.each do |v|
|
||||
ref = @rest_description.schemas[v._ref]
|
||||
ref.base_ref = type
|
||||
ref.discriminant = type.variant.discriminant
|
||||
ref.discriminant_value = v.type_value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def check_duplicate_method(m)
|
||||
if @all_methods.include?(m.generated_name)
|
||||
logger.error { sprintf('Duplicate method %s generated', m.generated_name) }
|
||||
fail 'Duplicate name generated'
|
||||
end
|
||||
@all_methods[m.generated_name] = m
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,74 @@
|
|||
module Google
|
||||
module Apis
|
||||
# @private
|
||||
class Generator
|
||||
# Methods for validating & normalizing symbols
|
||||
module NameHelpers
|
||||
KEYWORDS = %w(__ENCODING__ def in self __LINE__ defined? module super __FILE__ do next then BEGIN
|
||||
else nil true END elsif not undef alias end or unless and ensure redo until begin
|
||||
false rescue when break for retry while case if return yield class)
|
||||
PLURAL_METHODS = %w(list search)
|
||||
|
||||
# Check to see if the method name should be plauralized
|
||||
# @return [Boolean]
|
||||
def pluralize_method?(method_name)
|
||||
PLURAL_METHODS.include?(method_name)
|
||||
end
|
||||
|
||||
# Check to see if the method is either a keyword or built-in method on object
|
||||
# @return [Boolean]
|
||||
def reserved?(name)
|
||||
keyword?(name) || object_method?(name)
|
||||
end
|
||||
|
||||
# Check to see if the name is a ruby keyword
|
||||
# @return [Boolean]
|
||||
def keyword?(name)
|
||||
KEYWORDS.include?(name)
|
||||
end
|
||||
|
||||
# Check to see if the method already exists on ruby objects
|
||||
# @return [Boolean]
|
||||
def object_method?(name)
|
||||
Object.new.respond_to?(name)
|
||||
end
|
||||
|
||||
# Convert a parameter name to ruby conventions
|
||||
# @param [String] name
|
||||
# @return [String] updated param name
|
||||
def normalize_param_name(name)
|
||||
name = ActiveSupport::Inflector.underscore(name.gsub(/\W/, '_'))
|
||||
if reserved?(name)
|
||||
logger.warn { sprintf('Found reserved keyword \'%1$s\'', name) }
|
||||
name += '_'
|
||||
logger.warn { sprintf('Changed to \'%1$s\'', name) }
|
||||
end
|
||||
name
|
||||
end
|
||||
|
||||
# Convert a property name to ruby conventions
|
||||
# @param [String] name
|
||||
# @return [String]
|
||||
def normalize_property_name(name)
|
||||
name = ActiveSupport::Inflector.underscore(name.gsub(/\W/, '_'))
|
||||
if object_method?(name)
|
||||
logger.warn { sprintf('Found reserved property \'%1$s\'', name) }
|
||||
name += '_prop'
|
||||
logger.warn { sprintf('Changed to \'%1$s\'', name) }
|
||||
end
|
||||
name
|
||||
end
|
||||
|
||||
# Converts a scope string into a ruby constant
|
||||
# @param [String] url
|
||||
# Url to convert
|
||||
# @return [String]
|
||||
def constantize_scope(url)
|
||||
scope = Addressable::URI.parse(url).path[1..-1].upcase.gsub(/\W/, '_')
|
||||
scope = 'AUTH_SCOPE' if scope.nil? || scope.empty?
|
||||
scope
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,130 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'active_support/inflector'
|
||||
require 'google/apis/discovery_v1'
|
||||
|
||||
# Extend the discovery API classes with additional data needed to make
|
||||
# code generation produce better results
|
||||
module Google
|
||||
module Apis
|
||||
module DiscoveryV1
|
||||
TYPE_MAP = {
|
||||
'string' => 'String',
|
||||
'boolean' => 'Boolean',
|
||||
'number' => 'Float',
|
||||
'integer' => 'Fixnum',
|
||||
'any' => 'Object'
|
||||
}
|
||||
|
||||
class JsonSchema
|
||||
attr_accessor :name
|
||||
attr_accessor :generated_name
|
||||
attr_accessor :generated_class_name
|
||||
attr_accessor :base_ref
|
||||
attr_accessor :parent
|
||||
attr_accessor :discriminant
|
||||
attr_accessor :discriminant_value
|
||||
attr_accessor :path
|
||||
|
||||
def properties
|
||||
@properties ||= {}
|
||||
end
|
||||
|
||||
def qualified_name
|
||||
parent.qualified_name + '::' + generated_class_name
|
||||
end
|
||||
|
||||
def generated_type
|
||||
case type
|
||||
when 'string', 'boolean', 'number', 'integer', 'any'
|
||||
return 'DateTime' if format == 'date-time'
|
||||
return 'Date' if format == 'date'
|
||||
return TYPE_MAP[type]
|
||||
when 'array'
|
||||
return sprintf('Array<%s>', items.generated_type)
|
||||
when 'hash'
|
||||
return sprintf('Hash<String,%s>', additional_properties.generated_type)
|
||||
when 'object'
|
||||
return qualified_name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class RestMethod
|
||||
attr_accessor :generated_name
|
||||
attr_accessor :parent
|
||||
|
||||
def path_parameters
|
||||
return [] if parameter_order.nil? || parameters.nil?
|
||||
parameter_order.map { |name| parameters[name] }.select { |param| param.location == 'path' }
|
||||
end
|
||||
|
||||
def query_parameters
|
||||
return [] if parameters.nil?
|
||||
parameters.values.select { |param| param.location == 'query' }
|
||||
end
|
||||
end
|
||||
|
||||
class RestResource
|
||||
attr_accessor :parent
|
||||
|
||||
def all_methods
|
||||
m = []
|
||||
m << api_methods.values unless api_methods.nil?
|
||||
m << resources.map { |_k, r| r.all_methods } unless resources.nil?
|
||||
m.flatten
|
||||
end
|
||||
end
|
||||
|
||||
class RestDescription
|
||||
def version
|
||||
ActiveSupport::Inflector.camelize(@version.gsub(/\W/, '-')).gsub(/-/, '_')
|
||||
end
|
||||
|
||||
def name
|
||||
ActiveSupport::Inflector.camelize(@name)
|
||||
end
|
||||
|
||||
def module_name
|
||||
name + version
|
||||
end
|
||||
|
||||
def qualified_name
|
||||
sprintf('Google::Apis::%s', module_name)
|
||||
end
|
||||
|
||||
def service_name
|
||||
class_name = (canonical_name || name).gsub(/\W/, '')
|
||||
ActiveSupport::Inflector.camelize(sprintf('%sService', class_name))
|
||||
end
|
||||
|
||||
def all_methods
|
||||
m = []
|
||||
m << api_methods.values unless api_methods.nil?
|
||||
m << resources.map { |_k, r| r.all_methods } unless resources.nil?
|
||||
m.flatten
|
||||
end
|
||||
|
||||
class Auth
|
||||
class Oauth2
|
||||
class Scope
|
||||
attr_accessor :constant
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,124 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'active_support/inflector'
|
||||
require 'erb'
|
||||
require 'ostruct'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
# @private
|
||||
class Generator
|
||||
# Directory containing ERB templates
|
||||
TEMPLATE_DIR = File.expand_path('../templates', __FILE__)
|
||||
|
||||
# Helpers used in ERB templates
|
||||
module TemplateHelpers
|
||||
# Get the include path for a ruby module/class
|
||||
#
|
||||
# @param [String] module_name
|
||||
# Fully qualified module/class name
|
||||
# @return [String]
|
||||
# Path to file
|
||||
def to_path(module_name)
|
||||
ActiveSupport::Inflector.underscore(module_name)
|
||||
end
|
||||
|
||||
# Render a block comment
|
||||
#
|
||||
# @param [String] str
|
||||
# Comment string
|
||||
# @param [Fixnum] spaces_before
|
||||
# Number of spaces to indent the comment hash
|
||||
# @param [Fixnum] spaces_after
|
||||
# Number of spaces to indent after the comment hash for subsequent lines
|
||||
# @return [String] formatted comment
|
||||
def block_comment(str, spaces_before = 0, spaces_after = 0)
|
||||
return '' if str.nil?
|
||||
pre = ' ' * spaces_before
|
||||
post = ' ' * spaces_after
|
||||
lines = str.gsub(/([{}])/, '`').scan(/.{1,78}(?:\W|$)/).map(&:strip)
|
||||
lines.join("\n" + pre + '#' + post)
|
||||
end
|
||||
|
||||
# Indent a block of text
|
||||
#
|
||||
# @param [String] str
|
||||
# Content to indent
|
||||
# @param [Fixnum] spaces
|
||||
# Number of spaces to indent
|
||||
# @return [String] formatted content
|
||||
def indent(str, spaces)
|
||||
pre = ' ' * spaces
|
||||
str = pre + str.split(/\n/).join("\n" + pre) + "\n"
|
||||
return str unless str.strip.empty?
|
||||
nil
|
||||
end
|
||||
|
||||
# Include a partial inside a template.
|
||||
#
|
||||
# @private
|
||||
# @param [String] partial
|
||||
# Name of the template
|
||||
# @param [Hash] context
|
||||
# Context used to render
|
||||
# @return [String] rendered content
|
||||
def include(partial, context)
|
||||
template = Template.new(sprintf('_%s.tmpl', partial))
|
||||
template.render(context)
|
||||
end
|
||||
end
|
||||
|
||||
# Holds local vars/helpers for template rendering
|
||||
class Context < OpenStruct
|
||||
include TemplateHelpers
|
||||
|
||||
# Get the context for ERB evaluation
|
||||
# @return [Binding]
|
||||
def to_binding
|
||||
binding
|
||||
end
|
||||
end
|
||||
|
||||
# ERB template for the code generator
|
||||
class Template
|
||||
# Loads a template from the template dir. Automatically
|
||||
# appends the .tmpl suffix
|
||||
#
|
||||
# @param [String] template_name
|
||||
# Name of the template file
|
||||
def self.load(template_name)
|
||||
Template.new(sprintf('%s.tmpl', template_name))
|
||||
end
|
||||
|
||||
# @param [String] template_name
|
||||
# Name of the template file
|
||||
def initialize(template_name)
|
||||
file = File.join(TEMPLATE_DIR, template_name)
|
||||
@erb = ERB.new(File.read(file), nil, '-')
|
||||
end
|
||||
|
||||
# Render the template
|
||||
#
|
||||
# @param [Hash] context
|
||||
# Variables to set when rendering the template
|
||||
# @return [String] rendered template
|
||||
def render(context)
|
||||
ctx = Context.new(context)
|
||||
@erb.result(ctx.to_binding)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,40 @@
|
|||
<% if cls.type == 'object' -%>
|
||||
|
||||
# <%= block_comment(cls.description, 0, 1) %>
|
||||
class <%= cls.generated_class_name %><% if cls.base_ref %> < <%= cls.base_ref.generated_type %><% end %>
|
||||
include Google::Apis::Core::Hashable
|
||||
<% for property in cls.properties.values -%>
|
||||
|
||||
# <%= block_comment(property.description, 2, 1) %>
|
||||
# Corresponds to the JSON property `<%= property.name %>`
|
||||
# @return [<%= property.generated_type %>]
|
||||
attr_accessor :<%= property.generated_name %>
|
||||
<% if property.type == 'boolean' -%>
|
||||
alias_method :<%= property.generated_name %>?, :<%= property.generated_name %>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
|
||||
def initialize(**args)
|
||||
<% if cls.discriminant -%>
|
||||
@<%= cls.properties[cls.discriminant].generated_name %> = '<%= cls.discriminant_value %>'
|
||||
<% end -%>
|
||||
update!(**args)
|
||||
end
|
||||
|
||||
# Update properties of this object
|
||||
def update!(**args)
|
||||
<% for property in cls.properties.values -%>
|
||||
@<%= property.generated_name %> = args[:<%= property.generated_name %>] unless args[:<%= property.generated_name %>].nil?
|
||||
<% end -%>
|
||||
end
|
||||
<% for child_class in cls.properties.values -%>
|
||||
<% if child_class._ref.nil? -%>
|
||||
<%= indent(include('class', :cls => child_class, :api => api), 2) -%>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
end
|
||||
<% elsif cls.items && cls.items._ref.nil? -%>
|
||||
<%= include('class', :cls => cls.items, :api => api) -%>
|
||||
<% elsif cls.additional_properties && cls.additional_properties._ref.nil? -%>
|
||||
<%= include('class', :cls => cls.additional_properties, :api => api) -%>
|
||||
<% end -%>
|
|
@ -0,0 +1,90 @@
|
|||
|
||||
# <%= block_comment(api_method.description, 0, 1) %>
|
||||
<% for param in api_method.path_parameters -%>
|
||||
# @param [<% if param.repeated? %>Array<<%= param.generated_type %>>, <% end %><%= param.generated_type %>] <%= param.generated_name %>
|
||||
<% if param.description -%>
|
||||
# <%= block_comment(param.description, 0, 3) %>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
<% if api_method.request -%>
|
||||
# @param [<%= api.schemas[api_method.request._ref].generated_type %>] <%= api.schemas[api_method.request._ref].generated_name %>_object
|
||||
<% end -%>
|
||||
<% for param in api_method.query_parameters -%>
|
||||
# @param [<% if param.repeated? %>Array<<%= param.generated_type %>>, <% end %><%= param.generated_type %>] <%= param.generated_name %>
|
||||
<% if param.description -%>
|
||||
# <%= block_comment(param.description, 0, 3) %>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
<% for param in api.parameters.values.reject {|p| p.name == 'key'} -%>
|
||||
# @param [<% if param.repeated? %>Array<<%= param.generated_type %>>, <% end %><%= param.generated_type %>] <%= param.generated_name %>
|
||||
<% if param.description -%>
|
||||
# <%= block_comment(param.description, 0, 3) %>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
<% if api_method.supports_media_upload? -%>
|
||||
# @param [IO, String] upload_source
|
||||
# IO stream or filename containing content to upload
|
||||
# @param [String] content_type
|
||||
# Content type of the uploaded content.
|
||||
<% elsif api_method.supports_media_download? -%>
|
||||
# @param [IO, String] download_dest
|
||||
# IO stream or filename to receive content download
|
||||
<% end -%>
|
||||
# @param [Google::Apis::RequestOptions] options
|
||||
# Request-specific options
|
||||
#
|
||||
# @yield [result, err] Result & error if block supplied
|
||||
<% if api_method.response -%>
|
||||
# @yieldparam result [<%= api.schemas[api_method.response._ref].generated_type %>] parsed result object
|
||||
# @yieldparam err [StandardError] error object if request failed
|
||||
#
|
||||
# @return [<%= api.schemas[api_method.response._ref].generated_type %>]
|
||||
<% else -%>
|
||||
# @yieldparam result [NilClass] No result returned for this method
|
||||
# @yieldparam err [StandardError] error object if request failed
|
||||
#
|
||||
# @return [void]
|
||||
<% end -%>
|
||||
#
|
||||
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
||||
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
||||
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
||||
def <%= api_method.generated_name %>(<% for param in api_method.path_parameters %><%= param.generated_name %>, <% end %><% if api_method.request %><%= api.schemas[api_method.request._ref].generated_name %>_object = nil, <% end %><% for param in api_method.query_parameters %><%= param.generated_name %>: nil, <% end %><% for param in api.parameters.values.reject {|p| p.name == 'key'} %><%= param.generated_name %>: nil, <% end %><% if api_method.supports_media_upload? %>upload_source: nil, content_type: nil, <% elsif api_method.supports_media_download? %>download_dest: nil, <% end %>options: nil, &block)
|
||||
path = '<%= api_method.path %>'
|
||||
<% if api_method.supports_media_upload? -%>
|
||||
if upload_source.nil?
|
||||
command = make_simple_command(:<%= api_method.http_method.downcase %>, path, options)
|
||||
else
|
||||
command = make_upload_command(:<%= api_method.http_method.downcase %>, path, options)
|
||||
command.upload_source = upload_source
|
||||
command.upload_content_type = content_type
|
||||
end
|
||||
<% elsif api_method.supports_media_download? -%>
|
||||
if download_dest.nil?
|
||||
command = make_simple_command(:<%= api_method.http_method.downcase %>, path, options)
|
||||
else
|
||||
command = make_download_command(:<%= api_method.http_method.downcase %>, path, options)
|
||||
command.download_dest = download_dest
|
||||
end
|
||||
<% else -%>
|
||||
command = make_simple_command(:<%= api_method.http_method.downcase %>, path, options)
|
||||
<% end -%>
|
||||
<% if api_method.request -%>
|
||||
command.request_representation = <%= api.schemas[api_method.request._ref].generated_type %>::Representation
|
||||
command.request_object = <%= api.schemas[api_method.request._ref].generated_name %>_object
|
||||
<% end -%>
|
||||
<% if api_method.response -%>
|
||||
command.response_representation = <%= api.schemas[api_method.response._ref].generated_type %>::Representation
|
||||
command.response_class = <%= api.schemas[api_method.response._ref].generated_type %>
|
||||
<% end -%>
|
||||
<% for param in api_method.path_parameters -%>
|
||||
command.params['<%= param.name %>'] = <%= param.generated_name %> unless <%= param.generated_name %>.nil?
|
||||
<% end -%>
|
||||
<% for param in api_method.query_parameters -%>
|
||||
command.query['<%= param.name %>'] = <%= param.generated_name %> unless <%= param.generated_name %>.nil?
|
||||
<% end -%>
|
||||
<% for param in api.parameters.values.reject {|p| p.name == 'key'} -%>
|
||||
command.query['<%= param.name %>'] = <%= param.generated_name %> unless <%= param.generated_name %>.nil?
|
||||
<% end -%>
|
||||
execute_or_queue_command(command, &block)
|
||||
end
|
|
@ -0,0 +1,51 @@
|
|||
<% if cls.type == 'object' -%>
|
||||
|
||||
# @private
|
||||
class <%= cls.generated_class_name %>
|
||||
class Representation < Google::Apis::Core::JsonRepresentation
|
||||
<% if api.features && api.features.include?('dataWrapper') -%>
|
||||
self.representation_wrap = lambda { |args| :data if args[:unwrap] == <%= cls.generated_type %> }
|
||||
<% end -%>
|
||||
<% if cls.variant -%>
|
||||
def from_hash(hash, *args)
|
||||
case hash['<%= cls.variant.discriminant %>']
|
||||
<% for v in cls.variant.map -%>
|
||||
<% ref = api.schemas[v._ref] %>
|
||||
when '<%= v.type_value %>'
|
||||
<%= ref.generated_type %>::Representation.new(<%= ref.generated_type %>.new).from_hash(hash, *args)
|
||||
<% end -%>
|
||||
end
|
||||
end
|
||||
|
||||
def to_hash(*args)
|
||||
case represented
|
||||
<% for v in cls.variant.map -%>
|
||||
<% ref = api.schemas[v._ref] %>
|
||||
when <%= ref.generated_type %>
|
||||
<%= ref.generated_type %>::Representation.new(represented).to_hash(*args)
|
||||
<% end -%>
|
||||
end
|
||||
end
|
||||
<% else -%>
|
||||
<% for property in cls.properties.values -%>
|
||||
<% if property.type == 'hash' -%>
|
||||
hash :<%= property.generated_name %>, as: '<%= property.name %>'<%= include('representation_type', :lead => ', ', :type => property.additional_properties, :api => api) %>
|
||||
<% elsif property.type == 'array' -%>
|
||||
collection :<%= property.generated_name %>, as: '<%= property.name %>'<%= include('representation_type', :lead => ', ', :type => property.items, :api => api) %>
|
||||
<% else -%>
|
||||
property :<%= property.generated_name %>,<% if property.format == 'byte' %> :base64 => true,<%end%> as: '<%= property.name %>'<%= include('representation_type', :lead => ', ', :type => property, :api => api) %>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
end
|
||||
<% for child_class in cls.properties.values -%>
|
||||
<% if child_class._ref.nil? -%>
|
||||
<%= indent(include('representation', :cls => child_class, :api => api), 2) -%>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
end
|
||||
<% elsif cls.items && cls.items._ref.nil? -%>
|
||||
<%= include('representation', :cls => cls.items, :api => api) -%>
|
||||
<% elsif cls.additional_properties && cls.additional_properties._ref.nil? -%>
|
||||
<%= include('representation', :cls => cls.additional_properties, :api => api) -%>
|
||||
<% end -%>
|
|
@ -0,0 +1,15 @@
|
|||
<% if cls.type == 'object' -%>
|
||||
|
||||
class <%= cls.generated_class_name %>
|
||||
class Representation < Google::Apis::Core::JsonRepresentation; end
|
||||
<% for child_class in cls.properties.values -%>
|
||||
<% if child_class._ref.nil? -%>
|
||||
<%= indent(include('representation_stub', :cls => child_class), 2) -%>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
end
|
||||
<% elsif cls.items && cls.items._ref.nil? -%>
|
||||
<%= include('representation_stub', :cls => cls.items, :api => api) -%>
|
||||
<% elsif cls.additional_properties && cls.additional_properties._ref.nil? -%>
|
||||
<%= include('representation_stub', :cls => cls.additional_properties, :api => api) -%>
|
||||
<% end -%>
|
|
@ -0,0 +1,10 @@
|
|||
<% if type.type == 'array' -%>
|
||||
<%= lead %>:class => Array do
|
||||
include Representable::JSON::Collection
|
||||
items<%= include('representation_type', :lead => ' ' , :type => type.items, :api => api) %>
|
||||
end
|
||||
<% elsif ['date', 'date-time'].include?(type.format) -%>
|
||||
<%= lead %>type: <%= type.generated_type %>
|
||||
<% elsif type.type == 'object' -%>
|
||||
<%= lead %>class: <%= type.generated_type %>, decorator: <%= type.generated_type %>::Representation
|
||||
<% end -%>
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -12,16 +12,18 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'google/api_client/request'
|
||||
require 'date'
|
||||
require 'google/apis/core/base_service'
|
||||
require 'google/apis/core/json_representation'
|
||||
require 'google/apis/core/hashable'
|
||||
require 'google/apis/errors'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
##
|
||||
# Subclass of Request for backwards compatibility with pre-0.5.0 versions of the library
|
||||
#
|
||||
# @deprecated
|
||||
# use {Google::APIClient::Request} instead
|
||||
class Reference < Request
|
||||
module Apis
|
||||
module <%= api.module_name %>
|
||||
<% for cls in api.schemas.values.partition(&:variant).flatten -%>
|
||||
<%= indent(include('class', :cls => cls, :api => api), 6) -%>
|
||||
<% end -%>
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,40 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require '<%= to_path(api.qualified_name) %>/service.rb'
|
||||
require '<%= to_path(api.qualified_name) %>/classes.rb'
|
||||
require '<%= to_path(api.qualified_name) %>/representations.rb'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
# <%= api.title %>
|
||||
#
|
||||
# <%= block_comment(api.description, 4, 1) %>
|
||||
#
|
||||
<% if api.documentation_link -%>
|
||||
# @see <%= api.documentation_link %>
|
||||
<% end -%>
|
||||
module <%= api.module_name %>
|
||||
VERSION = '<%= api.version %>'
|
||||
REVISION = '<%= api.revision %>'
|
||||
<% if api.auth && api.auth.oauth2 -%>
|
||||
<% for scope_string, scope in api.auth.oauth2.scopes -%>
|
||||
|
||||
# <%= scope.description %>
|
||||
<%= scope.constant %> = '<%= scope_string %>'
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2012 Google Inc.
|
||||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -12,18 +12,21 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'spec_helper'
|
||||
require 'date'
|
||||
require 'google/apis/core/base_service'
|
||||
require 'google/apis/core/json_representation'
|
||||
require 'google/apis/core/hashable'
|
||||
require 'google/apis/errors'
|
||||
|
||||
require 'google/api_client'
|
||||
|
||||
RSpec.describe Google::APIClient::Request do
|
||||
CLIENT = Google::APIClient.new(:application_name => 'API Client Tests') unless defined?(CLIENT)
|
||||
|
||||
it 'should normalize parameter names to strings' do
|
||||
request = Google::APIClient::Request.new(:uri => 'https://www.google.com', :parameters => {
|
||||
:a => '1', 'b' => '2'
|
||||
})
|
||||
expect(request.parameters['a']).to eq('1')
|
||||
expect(request.parameters['b']).to eq('2')
|
||||
module Google
|
||||
module Apis
|
||||
module <%= api.module_name %>
|
||||
<% for cls in api.schemas.values.partition(&:variant).flatten -%>
|
||||
<%= indent(include('representation_stub', :cls => cls), 6) -%>
|
||||
<% end -%>
|
||||
<% for cls in api.schemas.values.partition(&:variant).flatten -%>
|
||||
<%= indent(include('representation', :cls => cls, :api => api), 6) -%>
|
||||
<% end -%>
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,60 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'google/apis/core/base_service'
|
||||
require 'google/apis/core/json_representation'
|
||||
require 'google/apis/core/hashable'
|
||||
require 'google/apis/errors'
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
module <%= api.module_name %>
|
||||
# <%= api.title %>
|
||||
#
|
||||
# <%= block_comment(api.description, 6, 2) %>
|
||||
#
|
||||
# @example
|
||||
# require '<%= to_path(api.qualified_name) %>'
|
||||
#
|
||||
# <%= api.name %> = <%= api.qualified_name %> # Alias the module
|
||||
# service = <%= api.name %>::<%= api.service_name %>.new
|
||||
#
|
||||
<% if api.documentation_link -%>
|
||||
# @see <%= api.documentation_link %>
|
||||
<% end -%>
|
||||
class <%= api.service_name %> < Google::Apis::Core::BaseService
|
||||
<% for param in api.parameters.values.reject {|p| p.name == 'fields'} -%>
|
||||
# @return [<%= param.generated_type %>]
|
||||
# <%= block_comment(param.description, 8, 2) %>
|
||||
attr_accessor :<%= param.generated_name %>
|
||||
|
||||
<% end -%>
|
||||
def initialize
|
||||
super('<%= api.root_url %>', '<%= api.service_path %>')
|
||||
end
|
||||
<% for api_method in api.all_methods -%>
|
||||
<%= indent(include('method', :api_method => api_method, :api => api), 8) -%>
|
||||
<% end -%>
|
||||
|
||||
protected
|
||||
|
||||
def apply_command_defaults(command)
|
||||
<% for param in api.parameters.values.reject {|p| p.name == 'fields'} -%>
|
||||
command.query['<%= param.name %>'] = <%= param.generated_name %> unless <%= param.generated_name %>.nil?
|
||||
<% end -%>
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,79 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
# General options for API requests
|
||||
ClientOptions = Struct.new(
|
||||
:application_name,
|
||||
:application_version,
|
||||
:proxy_url)
|
||||
|
||||
RequestOptions = Struct.new(
|
||||
:authorization,
|
||||
:retries,
|
||||
:header,
|
||||
:timeout_sec)
|
||||
|
||||
# General client options
|
||||
class ClientOptions
|
||||
# @!attribute [rw] application_name
|
||||
# @return [String] Name of the application, for identification in the User-Agent header
|
||||
# @!attribute [rw] application_version
|
||||
# @return [String] Version of the application, for identification in the User-Agent header
|
||||
# @!attribute [rw] proxy_url
|
||||
# @return [String] URL of a proxy server
|
||||
|
||||
# Get the default options
|
||||
# @return [Google::Apis::ClientOptions]
|
||||
def self.default
|
||||
@options ||= ClientOptions.new
|
||||
end
|
||||
end
|
||||
|
||||
# Request options
|
||||
class RequestOptions
|
||||
# @!attribute [rw] credentials
|
||||
# @return [Signet::OAuth2::Client, #apply(Hash)] OAuth2 credentials
|
||||
# @!attribute [rw] retries
|
||||
# @return [Fixnum] Number of times to retry requests on server error
|
||||
# @!attribute [rw] timeout_sec
|
||||
# @return [Fixnum] How long, in seconds, before requests time out
|
||||
# @!attribute [rw] header
|
||||
# @return [Hash<String,String] Additional HTTP headers to include in requests
|
||||
|
||||
# Get the default options
|
||||
# @return [Google::Apis::RequestOptions]
|
||||
def self.default
|
||||
@options ||= RequestOptions.new
|
||||
end
|
||||
|
||||
def merge(options)
|
||||
return self if options.nil?
|
||||
|
||||
new_options = dup
|
||||
%w(authorization retries timeout_sec).each do |opt|
|
||||
opt = opt.to_sym
|
||||
new_options[opt] = options[opt] unless options[opt].nil?
|
||||
end
|
||||
new_options
|
||||
end
|
||||
end
|
||||
|
||||
ClientOptions.default.application_name = 'unknown'
|
||||
ClientOptions.default.application_version = '0.0.0'
|
||||
|
||||
RequestOptions.default.retries = 0
|
||||
end
|
||||
end
|
|
@ -0,0 +1,39 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module Google
|
||||
module Apis
|
||||
# Client library version
|
||||
VERSION = '0.9.pre1'
|
||||
|
||||
# Current operating system
|
||||
# @private
|
||||
OS_VERSION = begin
|
||||
if RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/
|
||||
`ver`.sub(/\s*\[Version\s*/, '/').sub(']', '').strip
|
||||
elsif RUBY_PLATFORM =~ /darwin/i
|
||||
"Mac OS X/#{`sw_vers -productVersion`}"
|
||||
elsif RUBY_PLATFORM == 'java'
|
||||
require 'java'
|
||||
name = java.lang.System.getProperty('os.name')
|
||||
version = java.lang.System.getProperty('os.version')
|
||||
"#{name}/#{version}"
|
||||
else
|
||||
`uname -sr`.sub(' ', '/')
|
||||
end
|
||||
rescue
|
||||
RUBY_PLATFORM
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,34 +0,0 @@
|
|||
require "rubygems/package_task"
|
||||
|
||||
namespace :gem do
|
||||
|
||||
desc "Build the gem"
|
||||
task :build do
|
||||
system "gem build signet.gemspec"
|
||||
end
|
||||
|
||||
desc "Install the gem"
|
||||
task :install => ["clobber", "gem:package"] do
|
||||
sh "#{SUDO} gem install --local pkg/#{GEM_SPEC.full_name}"
|
||||
end
|
||||
|
||||
desc "Uninstall the gem"
|
||||
task :uninstall do
|
||||
installed_list = Gem.source_index.find_name(PKG_NAME)
|
||||
if installed_list &&
|
||||
(installed_list.collect { |s| s.version.to_s}.include?(PKG_VERSION))
|
||||
sh(
|
||||
"#{SUDO} gem uninstall --version '#{PKG_VERSION}' " +
|
||||
"--ignore-dependencies --executables #{PKG_NAME}"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
desc "Reinstall the gem"
|
||||
task :reinstall => [:uninstall, :install]
|
||||
end
|
||||
|
||||
desc "Alias to gem:package"
|
||||
task "gem" => "gem:package"
|
||||
|
||||
task "clobber" => ["gem:clobber_package"]
|
|
@ -1,45 +0,0 @@
|
|||
namespace :git do
|
||||
namespace :tag do
|
||||
desc 'List tags from the Git repository'
|
||||
task :list do
|
||||
tags = `git tag -l`
|
||||
tags.gsub!("\r", '')
|
||||
tags = tags.split("\n").sort {|a, b| b <=> a }
|
||||
puts tags.join("\n")
|
||||
end
|
||||
|
||||
desc 'Create a new tag in the Git repository'
|
||||
task :create do
|
||||
changelog = File.open('CHANGELOG.md', 'r') { |file| file.read }
|
||||
puts '-' * 80
|
||||
puts changelog
|
||||
puts '-' * 80
|
||||
puts
|
||||
|
||||
v = ENV['VERSION'] or abort 'Must supply VERSION=x.y.z'
|
||||
abort "Versions don't match #{v} vs #{PKG_VERSION}" if v != PKG_VERSION
|
||||
|
||||
git_status = `git status`
|
||||
if git_status !~ /nothing to commit \(working directory clean\)/
|
||||
abort "Working directory isn't clean."
|
||||
end
|
||||
|
||||
tag = "#{PKG_NAME}-#{PKG_VERSION}"
|
||||
msg = "Release #{PKG_NAME}-#{PKG_VERSION}"
|
||||
|
||||
existing_tags = `git tag -l #{PKG_NAME}-*`.split('\n')
|
||||
if existing_tags.include?(tag)
|
||||
warn('Tag already exists, deleting...')
|
||||
unless system "git tag -d #{tag}"
|
||||
abort 'Tag deletion failed.'
|
||||
end
|
||||
end
|
||||
puts "Creating git tag '#{tag}'..."
|
||||
unless system "git tag -a -m \"#{msg}\" #{tag}"
|
||||
abort 'Tag creation failed.'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
task 'gem:release' => 'git:tag:create'
|
|
@ -1,7 +1,7 @@
|
|||
namespace :metrics do
|
||||
task :lines do
|
||||
lines, codelines, total_lines, total_codelines = 0, 0, 0, 0
|
||||
for file_name in FileList['lib/**/*.rb']
|
||||
for file_name in FileList['lib/**/*.rb', 'bin/generate-api']
|
||||
f = File.open(file_name)
|
||||
while line = f.gets
|
||||
lines += 1
|
||||
|
@ -10,7 +10,7 @@ namespace :metrics do
|
|||
codelines += 1
|
||||
end
|
||||
puts "L: #{sprintf('%4d', lines)}, " +
|
||||
"LOC #{sprintf('%4d', codelines)} | #{file_name}"
|
||||
"LOC #{sprintf('%4d', codelines)} | #{file_name}"
|
||||
total_lines += lines
|
||||
total_codelines += codelines
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
require 'rubocop/rake_task'
|
||||
|
||||
desc 'Run RuboCop on the lib directory'
|
||||
RuboCop::RakeTask.new(:rubocop) do |task|
|
||||
task.patterns = ['lib/**/*.rb']
|
||||
# only show the files with failures
|
||||
task.formatters = ['progress']
|
||||
# don't abort rake on failure
|
||||
task.fail_on_error = false
|
||||
end
|
|
@ -1,21 +1,10 @@
|
|||
require 'rake/clean'
|
||||
require 'rspec/core/rake_task'
|
||||
|
||||
CLOBBER.include('coverage', 'specdoc')
|
||||
CLOBBER.include('coverage')
|
||||
|
||||
namespace :spec do
|
||||
RSpec::Core::RakeTask.new(:all) do |t|
|
||||
t.pattern = FileList['spec/**/*_spec.rb']
|
||||
t.rspec_opts = ['--color', '--format', 'documentation']
|
||||
end
|
||||
|
||||
desc 'Generate HTML Specdocs for all specs.'
|
||||
RSpec::Core::RakeTask.new(:specdoc) do |t|
|
||||
specdoc_path = File.expand_path('../../specdoc', __FILE__)
|
||||
|
||||
t.rspec_opts = %W( --format html --out #{File.join(specdoc_path, 'index.html')} )
|
||||
t.fail_on_error = false
|
||||
end
|
||||
RSpec::Core::RakeTask.new(:all)
|
||||
end
|
||||
|
||||
desc 'Alias to spec:all'
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
require 'rake'
|
||||
require 'rake/clean'
|
||||
|
||||
CLOBBER.include('wiki')
|
||||
|
||||
CACHE_PREFIX =
|
||||
"http://www.gmodules.com/gadgets/proxy/container=default&debug=0&nocache=0/"
|
||||
|
||||
namespace :wiki do
|
||||
desc 'Autogenerate wiki pages'
|
||||
task :supported_apis do
|
||||
output = <<-WIKI
|
||||
#summary The list of supported APIs
|
||||
|
||||
The Google API Client for Ruby is a small flexible client library for accessing
|
||||
the following Google APIs.
|
||||
|
||||
WIKI
|
||||
preferred_apis = {}
|
||||
require 'google/api_client'
|
||||
client = Google::APIClient.new
|
||||
for api in client.discovered_apis
|
||||
if !preferred_apis.has_key?(api.name)
|
||||
preferred_apis[api.name] = api
|
||||
elsif api.preferred
|
||||
preferred_apis[api.name] = api
|
||||
end
|
||||
end
|
||||
for api_name, api in preferred_apis
|
||||
if api.documentation.to_s != "" && api.title != ""
|
||||
output += (
|
||||
"||#{CACHE_PREFIX}#{api['icons']['x16']}||" +
|
||||
"[#{api.documentation} #{api.title}]||" +
|
||||
"#{api.description}||\n"
|
||||
)
|
||||
end
|
||||
end
|
||||
output.gsub!(/-32\./, "-16.")
|
||||
wiki_path = File.expand_path(
|
||||
File.join(File.dirname(__FILE__), '../wiki/'))
|
||||
Dir.mkdir(wiki_path) unless File.exists?(wiki_path)
|
||||
File.open(File.join(wiki_path, 'SupportedAPIs.wiki'), 'w') do |file|
|
||||
file.write(output)
|
||||
end
|
||||
end
|
||||
|
||||
task 'generate' => ['wiki:supported_apis']
|
||||
end
|
||||
|
||||
begin
|
||||
$LOAD_PATH.unshift(
|
||||
File.expand_path(File.join(File.dirname(__FILE__), '../yard/lib'))
|
||||
)
|
||||
$LOAD_PATH.unshift(File.expand_path('.'))
|
||||
$LOAD_PATH.uniq!
|
||||
|
||||
require 'yard'
|
||||
require 'yard/rake/wikidoc_task'
|
||||
|
||||
namespace :wiki do
|
||||
desc 'Generate Wiki Documentation with YARD'
|
||||
YARD::Rake::WikidocTask.new do |yardoc|
|
||||
yardoc.name = 'reference'
|
||||
yardoc.options = [
|
||||
'--verbose',
|
||||
'--markup', 'markdown',
|
||||
'-e', 'yard/lib/yard-google-code.rb',
|
||||
'-p', 'yard/templates',
|
||||
'-f', 'wiki',
|
||||
'-o', 'wiki'
|
||||
]
|
||||
yardoc.files = [
|
||||
'lib/**/*.rb', 'ext/**/*.c', '-', 'README.md', 'CHANGELOG.md'
|
||||
]
|
||||
end
|
||||
|
||||
task 'generate' => ['wiki:reference', 'wiki:supported_apis']
|
||||
end
|
||||
rescue LoadError
|
||||
# If yard isn't available, it's not the end of the world
|
||||
warn('YARD unavailable. Cannot fully generate wiki.')
|
||||
end
|
|
@ -1,29 +1,11 @@
|
|||
require 'rake'
|
||||
require 'rake/clean'
|
||||
|
||||
CLOBBER.include('doc', '.yardoc')
|
||||
CLOBBER.uniq!
|
||||
|
||||
begin
|
||||
require 'yard'
|
||||
require 'yard/rake/yardoc_task'
|
||||
require 'yard'
|
||||
require 'yard/rake/yardoc_task'
|
||||
|
||||
namespace :doc do
|
||||
desc 'Generate Yardoc documentation'
|
||||
YARD::Rake::YardocTask.new do |yardoc|
|
||||
yardoc.name = 'yard'
|
||||
yardoc.options = ['--verbose', '--markup', 'markdown']
|
||||
yardoc.files = [
|
||||
'lib/**/*.rb', 'ext/**/*.c', '-',
|
||||
'README.md', 'CONTRIB.md', 'CHANGELOG.md', 'LICENSE'
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Alias to doc:yard'
|
||||
task 'doc' => 'doc:yard'
|
||||
YARD::Rake::YardocTask.new do |t|
|
||||
t.files = ['lib/**/*.rb', 'generated/**/*.rb']
|
||||
t.options = ['--verbose', '--markup', 'markdown']
|
||||
end
|
||||
rescue LoadError
|
||||
# If yard isn't available, it's not the end of the world
|
||||
desc 'Alias to doc:rdoc'
|
||||
task 'doc' => 'doc:rdoc'
|
||||
puts "YARD not available"
|
||||
end
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'googleauth'
|
||||
require 'google/apis/calendar_v3'
|
||||
|
||||
Calendar = Google::Apis::CalendarV3
|
||||
|
||||
calendar = Calendar::CalendarService.new
|
||||
calendar.authorization = Google::Auth.get_application_default([Calendar::AUTH_CALENDAR])
|
||||
|
||||
# Create an event, adding any emails listed in the command line as attendees
|
||||
event = Calendar::Event.new(summary: 'A sample event',
|
||||
location: '1600 Amphitheatre Parkway, Mountain View, CA 94045',
|
||||
attendees: ARGV.map { |email| Calendar::EventAttendee.new(email: email) },
|
||||
start: Calendar::EventDateTime.new(date_time: DateTime.parse('2015-12-31T20:00:00')),
|
||||
end: Calendar::EventDateTime.new(date_time: DateTime.parse('2016-01-01T02:00:00')))
|
||||
event = calendar.insert_event('primary', event, send_notifications: true)
|
||||
puts "Created event '#{event.summary}' (#{event.id})"
|
||||
|
||||
# List upcoming events
|
||||
events = calendar.list_events('primary', max_results: 10, single_events: true,
|
||||
order_by: 'startTime', time_min: Time.now.iso8601)
|
||||
puts "Upcoming events:"
|
||||
events.items.each do |evt|
|
||||
start = event.start.date || event.start.date_time
|
||||
puts "- #{event.summary} (#{start}) (ID: #{event.id})"
|
||||
end
|
||||
|
||||
# Delete the event we created earlier
|
||||
calendar.delete_event('primary', event.id, send_notifications: true)
|
||||
puts "Event deleted"
|
|
@ -0,0 +1,40 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'tempfile'
|
||||
require 'googleauth'
|
||||
require 'google/apis/drive_v2'
|
||||
|
||||
Drive = Google::Apis::DriveV2
|
||||
|
||||
drive = Drive::DriveService.new
|
||||
drive.authorization = Google::Auth.get_application_default([Drive::AUTH_DRIVE])
|
||||
|
||||
# Insert a file
|
||||
file = drive.insert_file({title: 'drive.rb'}, upload_source: 'drive.rb')
|
||||
puts "Created file #{file.title} (#{file.id})"
|
||||
|
||||
# Search for it
|
||||
files = drive.list_files(q: "title = 'drive.rb'")
|
||||
puts "Search results:"
|
||||
files.items.each do |file|
|
||||
puts "- File: #{file.title} (#{file.id})"
|
||||
end
|
||||
|
||||
# Read it back
|
||||
tmp = drive.get_file(file.id, download_dest: Tempfile.new('drive'))
|
||||
|
||||
# Delete it
|
||||
drive.delete_file(file.id)
|
||||
puts "File deleted"
|
|
@ -0,0 +1,52 @@
|
|||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'googleauth'
|
||||
require 'google/apis/pubsub_v1beta2'
|
||||
|
||||
Pubsub = Google::Apis::PubsubV1beta2
|
||||
|
||||
pubsub = Pubsub::PubsubService.new
|
||||
pubsub.authorization = Google::Auth.get_application_default([Pubsub::AUTH_PUBSUB])
|
||||
|
||||
project = ARGV[0] || 'YOUR_PROJECT_NAME'
|
||||
|
||||
topic = "projects/#{project}/topics/foo"
|
||||
subscription = "projects/#{project}/subscriptions/bar"
|
||||
|
||||
# Create topic & subscription
|
||||
pubsub.create_topic(topic)
|
||||
pubsub.create_subscription(subscription, Pubsub::Subscription.new(topic: topic))
|
||||
|
||||
# Publish messages
|
||||
request = Pubsub::PublishRequest.new(messages: [])
|
||||
request.messages << Pubsub::Message.new(attributes: { "language" => "en" }, data: 'Hello')
|
||||
request.messages << Pubsub::Message.new(attributes: { "language" => "en" }, data: 'World')
|
||||
pubsub.publish(topic, request)
|
||||
|
||||
# Pull messages
|
||||
response = pubsub.pull(subscription, Pubsub::PullRequest.new(max_messages: 5))
|
||||
response.received_messages.each do |received_message|
|
||||
data = received_message.message.data
|
||||
puts "Received #{data}"
|
||||
end
|
||||
|
||||
# Acknowledge receipt
|
||||
ack_ids = response.received_messages.map{ |msg| msg.ack_id }
|
||||
pubsub.acknowledge(subscription, Pubsub::AcknowledgeRequest.new(ack_ids: ack_ids))
|
||||
|
||||
# Delete the subscription & topic
|
||||
pubsub.delete_subscription(subscription)
|
||||
pubsub.delete_topic(topic)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2010 Google Inc.
|
||||
# Copyright 2015 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -12,8 +12,17 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'tempfile'
|
||||
require 'googleauth'
|
||||
require 'google/apis/translate_v2'
|
||||
|
||||
Google::Apis.logger.level = Logger::DEBUG
|
||||
|
||||
Translate = Google::Apis::TranslateV2
|
||||
|
||||
translate = Translate::TranslateService.new
|
||||
translate.key = ARGV[0] || 'YOUR_API_KEY'
|
||||
|
||||
result = translate.list_translations(source: 'en', target: 'es', q: 'Hello world!')
|
||||
puts result.translations.first.translated_text
|
||||
|
||||
require 'google/api_client/discovery/api'
|
||||
require 'google/api_client/discovery/resource'
|
||||
require 'google/api_client/discovery/method'
|
||||
require 'google/api_client/discovery/schema'
|
|
@ -0,0 +1,79 @@
|
|||
#!/usr/bin/env bash
|
||||
# Usage: script/generate
|
||||
# Update packaged APIs
|
||||
|
||||
DIR=$(dirname $( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ))
|
||||
|
||||
APIS=(adexchangebuyer:v1.3 \
|
||||
adexchangeseller:v2.0 \
|
||||
admin:directory_v1 \
|
||||
admin:reports_v1 \
|
||||
adsense:v1.4 \
|
||||
adsensehost:v4.1 \
|
||||
analytics:v3 \
|
||||
androidenterprise:v1 \
|
||||
androidpublisher:v2 \
|
||||
appsactivity:v1 \
|
||||
appstate:v1 \
|
||||
autoscaler:v1beta2 \
|
||||
bigquery:v2 \
|
||||
blogger:v3 \
|
||||
books:v1 \
|
||||
calendar:v3 \
|
||||
civicinfo:v2 \
|
||||
cloudmonitoring:v2beta2 \
|
||||
cloudresourcemanager:v1beta1 \
|
||||
compute:v1 \
|
||||
container:v1beta1 \
|
||||
content:v2 \
|
||||
coordinate:v1 \
|
||||
customsearch:v1 \
|
||||
datastore:v1beta2 \
|
||||
deploymentmanager:v2beta2 \
|
||||
dfareporting:v2.1 \
|
||||
discovery:v1 \
|
||||
dns:v1 \
|
||||
doubleclickbidmanager:v1 \
|
||||
doubleclicksearch:v2 \
|
||||
drive:v2 \
|
||||
fitness:v1 \
|
||||
fusiontables:v2 \
|
||||
games:v1 \
|
||||
gamesConfiguration:v1configuration \
|
||||
gamesConfiguration:v1management \
|
||||
gan:v1beta1 \
|
||||
genomics:v1beta2 \
|
||||
gmail:v1 \
|
||||
groupsmigration:v1 \
|
||||
groupssettings:v1 \
|
||||
identitytoolkit:v3 \
|
||||
licensing:v1 \
|
||||
logging:v1beta3 \
|
||||
manager:v1beta2 \
|
||||
mapsengine:v1 \
|
||||
mirror:v1 \
|
||||
oauth2:v2 \
|
||||
pagespeedonline:v2 \
|
||||
plus:v1 \
|
||||
plusDomains:v1 \
|
||||
prediction:v1.6 \
|
||||
pubsub:v1beta2 \
|
||||
qpxExpress:v1 \
|
||||
replicapool:v1beta2 \
|
||||
replicapoolupdater:v1beta1 \
|
||||
reseller:v1 \
|
||||
resourceviews:v1beta2 \
|
||||
siteVerification:v1 \
|
||||
sqladmin:v1beta4 \
|
||||
storage:v1 \
|
||||
tagmanager:v1 \
|
||||
taskqueue:v1beta2 \
|
||||
tasks:v1 \
|
||||
translate:v2 \
|
||||
urlshortener:v1 \
|
||||
webmasters:v3 \
|
||||
youtube:v3 \
|
||||
youtubeAnalytics:v1 \
|
||||
)
|
||||
|
||||
echo 'a' | bundle exec bin/generate-api gen generated --names_out=$DIR/api_names_out.yaml --id=${APIS[*]}
|
|
@ -1,4 +1,5 @@
|
|||
age: script/release
|
||||
#!/usr/bin/env bash
|
||||
# Usage: script/release
|
||||
# Build the package, tag a commit, push it to origin, and then release the
|
||||
# package publicly.
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
"/test:v1/TestAnotherThing": another_thing
|
||||
|
Binary file not shown.
|
@ -1,33 +0,0 @@
|
|||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus posuere urna bibendum diam vulputate fringilla. Fusce elementum fermentum justo id aliquam. Integer vel felis ut arcu elementum lacinia. Duis congue urna eget nisl dapibus tristique molestie turpis sollicitudin. Vivamus in justo quam. Proin condimentum mollis tortor at molestie. Cras luctus, nunc a convallis iaculis, est risus consequat nisi, sit amet sollicitudin metus mi a urna. Aliquam accumsan, massa quis condimentum varius, sapien massa faucibus nibh, a dignissim magna nibh a lacus. Nunc aliquet, nunc ac pulvinar consectetur, sapien lacus hendrerit enim, nec dapibus lorem mi eget risus. Praesent vitae justo eget dolor blandit ullamcorper. Duis id nibh vitae sem aliquam vehicula et ac massa. In neque elit, molestie pulvinar viverra at, vestibulum quis velit.
|
||||
|
||||
Mauris sit amet placerat enim. Duis vel tellus ac dui auctor tincidunt id nec augue. Donec ut blandit turpis. Mauris dictum urna id urna vestibulum accumsan. Maecenas sagittis urna vitae erat facilisis gravida. Phasellus tellus augue, commodo ut iaculis vitae, interdum ut dolor. Proin at dictum lorem. Quisque pellentesque neque ante, vitae rutrum elit. Pellentesque sit amet erat orci. Praesent justo diam, tristique eu tempus ut, vestibulum eget dui. Maecenas et elementum justo. Cras a augue a elit porttitor placerat eget ut magna.
|
||||
|
||||
Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam adipiscing tellus in arcu bibendum volutpat. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed laoreet faucibus tristique. Duis metus eros, molestie eget dignissim in, imperdiet fermentum nulla. Vestibulum laoreet lorem eu justo vestibulum lobortis. Praesent pharetra leo vel mauris rhoncus commodo sollicitudin ante auctor. Ut sagittis, tortor nec placerat rutrum, neque ipsum cursus nisl, ut lacinia magna risus ac risus. Sed volutpat commodo orci, sodales fermentum dui accumsan eu. Donec egestas ullamcorper elit at condimentum. In euismod sodales posuere. Nullam lacinia tempus molestie. Etiam vitae ullamcorper dui. Fusce congue suscipit arcu, at consectetur diam gravida id. Quisque augue urna, commodo eleifend volutpat vitae, tincidunt ac ligula. Curabitur eget orci nisl, vel placerat ipsum.
|
||||
|
||||
Curabitur rutrum euismod nisi, consectetur varius tortor condimentum non. Pellentesque rhoncus nisi eu purus ultricies suscipit. Morbi ante nisi, varius nec molestie bibendum, pharetra quis enim. Proin eget nunc ante. Cras aliquam enim vel nunc laoreet ut facilisis nunc interdum. Fusce libero ipsum, posuere eget blandit quis, bibendum vitae quam. Integer dictum faucibus lacus eget facilisis. Duis adipiscing tortor magna, vel tincidunt risus. In non augue eu nisl sodales cursus vel eget nisi. Maecenas dignissim lectus elementum eros fermentum gravida et eget leo. Aenean quis cursus arcu. Mauris posuere purus non diam mattis vehicula. Integer nec orci velit.
|
||||
|
||||
Integer ac justo ac magna adipiscing condimentum vitae tincidunt dui. Morbi augue arcu, blandit nec interdum sit amet, condimentum vel nisl. Nulla vehicula tincidunt laoreet. Aliquam ornare elementum urna, sed vehicula magna porta id. Vestibulum dictum ultrices tortor sit amet tincidunt. Praesent bibendum, metus vel volutpat interdum, nisl nunc cursus libero, vel congue ligula mi et felis. Nulla mollis elementum nulla, in accumsan risus consequat at. Suspendisse potenti. Vestibulum enim lorem, dignissim ut porta vestibulum, porta eget mi. Fusce a elit ac dui sodales gravida. Pellentesque sed elit at dui dapibus mattis a non arcu.
|
||||
|
||||
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In nec posuere augue. Praesent non suscipit arcu. Sed nibh risus, lacinia ut molestie vitae, tristique eget turpis. Sed pretium volutpat arcu, non rutrum leo volutpat sed. Maecenas quis neque nisl, sit amet ornare dolor. Nulla pharetra pulvinar tellus sed eleifend. Aliquam eget mattis nulla. Nulla dictum vehicula velit, non facilisis lorem volutpat id. Fusce scelerisque sem vitae purus dapibus lobortis. Mauris ac turpis nec nibh consequat porttitor. Ut sit amet iaculis lorem. Vivamus blandit erat ac odio venenatis fringilla a sit amet ante. Quisque ut urna sed augue laoreet sagittis.
|
||||
|
||||
Integer nisl urna, bibendum id lobortis in, tempor non velit. Fusce sed volutpat quam. Suspendisse eu placerat purus. Maecenas quis feugiat lectus. Sed accumsan malesuada dui, a pretium purus facilisis quis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nunc ac purus id lacus malesuada placerat et in nunc. Ut imperdiet tincidunt est, at consectetur augue egestas hendrerit. Pellentesque eu erat a dui dignissim adipiscing. Integer quis leo non felis placerat eleifend. Fusce luctus mi a lorem mattis eget accumsan libero posuere. Sed pellentesque, odio id pharetra tempus, enim quam placerat metus, auctor aliquam elit mi facilisis quam. Nam at velit et eros rhoncus accumsan.
|
||||
|
||||
Donec tellus diam, fringilla ac viverra fringilla, rhoncus sit amet purus. Cras et ligula sed nibh tempor gravida. Aliquam id tempus mauris. Ut convallis quam sed arcu varius eget mattis magna tincidunt. Aliquam et suscipit est. Sed metus augue, tristique sed accumsan eget, euismod et augue. Nam augue sapien, placerat vel facilisis eu, tempor id risus. Aliquam mollis egestas mi. Fusce scelerisque convallis mauris quis blandit. Mauris nec ante id lacus sagittis tincidunt ornare vehicula dui. Curabitur tristique mattis nunc, vel cursus libero viverra feugiat. Suspendisse at sapien velit, a lacinia dolor. Vivamus in est non odio feugiat lacinia sodales ut magna.
|
||||
|
||||
Donec interdum ligula id ipsum dapibus consectetur. Pellentesque vitae posuere ligula. Morbi rhoncus bibendum eleifend. Suspendisse fringilla nunc at elit malesuada vitae ullamcorper lorem laoreet. Suspendisse a ante at ipsum iaculis cursus. Duis accumsan ligula quis nibh luctus pretium. Duis ultrices scelerisque dolor, et vulputate lectus commodo ut.
|
||||
|
||||
Vestibulum ac tincidunt lorem. Vestibulum lorem massa, dictum a scelerisque ut, convallis vitae eros. Morbi ipsum nisl, lacinia non tempor nec, lobortis id diam. Fusce quis magna nunc. Proin ultricies congue justo sed mattis. Vestibulum sit amet arcu tellus. Quisque ultricies porta massa iaculis vehicula. Vestibulum sollicitudin tempor urna vel sodales. Pellentesque ultricies tellus vel metus porta nec iaculis sapien mollis. Maecenas ullamcorper, metus eget imperdiet sagittis, odio orci dapibus neque, in vulputate nunc nibh non libero. Donec velit quam, lobortis quis tempus a, hendrerit id arcu.
|
||||
|
||||
Donec nec ante at tortor dignissim mattis. Curabitur vehicula tincidunt magna id sagittis. Proin euismod dignissim porta. Curabitur non turpis purus, in rutrum nulla. Nam turpis nulla, tincidunt et hendrerit non, posuere nec enim. Curabitur leo enim, lobortis ut placerat id, condimentum nec massa. In bibendum, lectus sit amet molestie commodo, felis massa rutrum nisl, ac fermentum ligula lacus in ipsum.
|
||||
|
||||
Pellentesque mi nulla, scelerisque vitae tempus id, consequat a augue. Quisque vel nisi sit amet ipsum faucibus laoreet sed vitae lorem. Praesent nunc tortor, volutpat ac commodo non, pharetra sed neque. Curabitur nec felis at mi blandit aliquet eu ornare justo. Mauris dignissim purus quis nisl porttitor interdum. Aenean id ipsum enim, blandit commodo justo. Quisque facilisis elit quis velit commodo scelerisque lobortis sapien condimentum. Cras sit amet porttitor velit. Praesent nec tempor arcu.
|
||||
|
||||
Donec varius mi adipiscing elit semper vel feugiat ipsum dictum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec non quam nisl, ac mattis justo. Vestibulum sed massa eget velit tristique auctor ut ac sapien. Curabitur aliquet ligula eget dui ornare at scelerisque mauris faucibus. Vestibulum id mauris metus, sed vestibulum nibh. Nulla egestas dictum blandit. Mauris vitae nibh at dui mollis lobortis. Phasellus sem leo, euismod at fringilla quis, mollis in nibh. Aenean vel lacus et elit pharetra elementum. Aliquam at ligula id sem bibendum volutpat. Pellentesque quis elit a massa dapibus viverra ut et lorem. Donec nulla eros, iaculis nec commodo vel, suscipit sit amet tortor. Integer tempor, elit at viverra imperdiet, velit sapien laoreet nunc, id laoreet ligula risus vel risus. Nullam sed tortor metus.
|
||||
|
||||
In nunc orci, tempor vulputate pretium vel, suscipit quis risus. Suspendisse accumsan facilisis felis eget posuere. Donec a faucibus felis. Proin nibh erat, sollicitudin quis vestibulum id, tincidunt quis justo. In sed purus eu nisi dignissim condimentum. Sed mattis dapibus lorem id vulputate. Suspendisse nec elit a augue interdum consequat quis id magna. In eleifend aliquam tempor. In in lacus augue.
|
||||
|
||||
Ut euismod sollicitudin lorem, id aliquam magna dictum sed. Nunc fringilla lobortis nisi sed consectetur. Nulla facilisi. Aenean nec lobortis augue. Curabitur ullamcorper dapibus libero, vel pellentesque arcu sollicitudin non. Praesent varius, turpis nec sollicitudin bibendum, elit tortor rhoncus lacus, gravida luctus leo nisi in felis. Ut metus eros, molestie non faucibus vel, condimentum ac elit.
|
||||
|
||||
Suspendisse nisl justo, lacinia sit amet interdum nec, tincidunt placerat urna. Suspendisse potenti. In et odio sed purus malesuada cursus sed nec lectus. Cras commodo, orci sit amet hendrerit iaculis, nunc urna facilisis tellus, vel laoreet odio nulla quis nibh. Maecenas ut justo ut lacus posuere sodales. Vestibulum facilisis fringilla diam at volutpat. Proin a hendrerit urna. Aenean placerat pulvinar arcu, sit amet lobortis neque eleifend in. Aenean risus nulla, facilisis ut tincidunt vitae, fringilla at ligula. Praesent eleifend est at sem lacinia auctor. Nulla ornare nunc in erat laoreet blandit.
|
||||
|
||||
Suspendisse pharetra leo ac est porta consequat. Nunc sem nibh, gravida vel aliquam a, ornare in tortor. Nulla vel sapien et felis placerat pellentesque id scelerisque nisl. Praesent et posuere.
|
|
@ -1,19 +0,0 @@
|
|||
Bag Attributes
|
||||
friendlyName: privatekey
|
||||
localKeyID: 54 69 6D 65 20 31 33 35 31 38 38 38 31 37 38 36 39 36
|
||||
Key Attributes: <No Attributes>
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQDYDyPb3GhyFx5i/wxS/jFsO6wSLys1ehAk6QZoBXGlg7ETVrIJ
|
||||
HYh9gXQUno4tJiQoaO8wOvleIRrqI0LkiftCXKWVSrzOiV+O9GkKx1byw1yAIZus
|
||||
QdwMT7X0O9hrZLZwhICWC9s6cGhnlCVxLIP/+JkVK7hxEq/LxoSszNV77wIDAQAB
|
||||
AoGAa2G69L7quil7VMBmI6lqbtyJfNAsrXtpIq8eG/z4qsZ076ObAKTI/XeldcoH
|
||||
57CZL+xXVKU64umZMt0rleJuGXdlauEUbsSx+biGewRfGTgC4rUSjmE539rBvmRW
|
||||
gaKliorepPMp/+B9CcG/2YfDPRvG/2cgTXJHVvneo+xHL4ECQQD2Jx5Mvs8z7s2E
|
||||
jY1mkpRKqh4Z7rlitkAwe1NXcVC8hz5ASu7ORyTl8EPpKAfRMYl1ofK/ozT1URXf
|
||||
kL5nChPfAkEA4LPUJ6cqrY4xrrtdGaM4iGIxzen5aZlKz/YNlq5LuQKbnLLHMuXU
|
||||
ohp/ynpqNWbcAFbmtGSMayxGKW5+fJgZ8QJAUBOZv82zCmn9YcnK3juBEmkVMcp/
|
||||
dKVlbGAyVJgAc9RrY+78kQ6D6mmnLgpfwKYk2ae9mKo3aDbgrsIfrtWQcQJAfFGi
|
||||
CEpJp3orbLQG319ZsMM7MOTJdC42oPZOMFbAWFzkAX88DKHx0bn9h+XQizkccSej
|
||||
Ppz+v3DgZJ3YZ1Cz0QJBALiqIokZ+oa3AY6oT0aiec6txrGvNPPbwOsrBpFqGNbu
|
||||
AByzWWBoBi40eKMSIR30LqN9H8YnJ91Aoy1njGYyQaw=
|
||||
-----END RSA PRIVATE KEY-----
|
|
@ -0,0 +1 @@
|
|||
test
|
|
@ -0,0 +1 @@
|
|||
Hello world
|
|
@ -0,0 +1,440 @@
|
|||
{
|
||||
"kind": "discovery#describeItem",
|
||||
"name": "test",
|
||||
"version": "v1",
|
||||
"id": "test:v1",
|
||||
"description": "Discovery doc API used for testing the code generator",
|
||||
"basePath": "/test/",
|
||||
"rootUrl": "https://www.googleapis.com/",
|
||||
"servicePath": "test/v1/",
|
||||
"rpcPath": "/rpc",
|
||||
"auth": {
|
||||
"oauth2": {
|
||||
"scopes": {
|
||||
"https://www.googleapis.com/auth/test": {
|
||||
"description": "View and manage things"
|
||||
},
|
||||
"https://www.googleapis.com/auth/test.readonly": {
|
||||
"description": "View things"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
"alt": {
|
||||
"type": "string",
|
||||
"description": "Data format for the response.",
|
||||
"default": "json",
|
||||
"enum": [
|
||||
"json"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Responses with Content-Type of application/json"
|
||||
],
|
||||
"location": "query"
|
||||
},
|
||||
"fields": {
|
||||
"type": "string",
|
||||
"description": "Selector specifying which fields to include in a partial response.",
|
||||
"location": "query"
|
||||
},
|
||||
"key": {
|
||||
"type": "string",
|
||||
"description": "API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token.",
|
||||
"location": "query"
|
||||
},
|
||||
"oauth_token": {
|
||||
"type": "string",
|
||||
"description": "OAuth 2.0 token for the current user.",
|
||||
"location": "query"
|
||||
},
|
||||
"prettyPrint": {
|
||||
"type": "boolean",
|
||||
"description": "Returns response with indentations and line breaks.",
|
||||
"default": "true",
|
||||
"location": "query"
|
||||
},
|
||||
"quotaUser": {
|
||||
"type": "string",
|
||||
"description": "Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Overrides userIp if both are provided.",
|
||||
"location": "query"
|
||||
},
|
||||
"userIp": {
|
||||
"type": "string",
|
||||
"description": "IP address of the site where the request originates. Use this if you want to enforce per-user limits.",
|
||||
"location": "query"
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"Thing": {
|
||||
"id": "Thing",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"etag": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"default": "test#thing"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"hat": {
|
||||
"$ref": "Hat"
|
||||
},
|
||||
"properties": {
|
||||
"$ref": "HashLikeThing"
|
||||
},
|
||||
"photo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string"
|
||||
},
|
||||
"hash": {
|
||||
"type": "string"
|
||||
},
|
||||
"hashAlgorithm": {
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"type": "integer"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Hat": {
|
||||
"type": "object",
|
||||
"variant": {
|
||||
"discriminant": "type",
|
||||
"map": [
|
||||
{
|
||||
"type_value": "topHat",
|
||||
"$ref": "TopHat"
|
||||
},
|
||||
{
|
||||
"type_value": "baseballHat",
|
||||
"$ref": "BaseballHat"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"TopHat": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"height": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BaseballHat": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"color": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"HashLikeThing": {
|
||||
"id": "HashLikeThing",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string",
|
||||
"description": "A mapping from export format to URL"
|
||||
}
|
||||
},
|
||||
"TestThing": {
|
||||
"id": "TestThing",
|
||||
"type": "object",
|
||||
"properties" :{}
|
||||
},
|
||||
"TestAnotherThing": {
|
||||
"id": "TestAnotherThing",
|
||||
"type": "object",
|
||||
"properties" :{}
|
||||
},
|
||||
"ThingList": {
|
||||
"id": "ThingList",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "array",
|
||||
"description": "The actual list of files.",
|
||||
"items": {
|
||||
"$ref": "Thing"
|
||||
}
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"default": "test#thinglist"
|
||||
}
|
||||
}
|
||||
},
|
||||
"QueryResults": {
|
||||
"id": "QueryResults",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"rows": {
|
||||
"$ref": "Rows"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Rows": {
|
||||
"id": "QueryResults",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"methods": {
|
||||
"query": {
|
||||
"path": "query",
|
||||
"id": "test.query",
|
||||
"httpMethod": "GET",
|
||||
"response": {
|
||||
"$ref": "QueryResults"
|
||||
//"$ref": "Rows" TODO: Support naked collections as a return value
|
||||
},
|
||||
"parameters": {
|
||||
"s": {
|
||||
"type": "string",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": false
|
||||
},
|
||||
"i": {
|
||||
"type": "integer",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": false,
|
||||
"minimum": "0",
|
||||
"maximum": "4294967295",
|
||||
"default": "20"
|
||||
},
|
||||
"n": {
|
||||
"type": "number",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": false
|
||||
},
|
||||
"b": {
|
||||
"type": "boolean",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": false
|
||||
},
|
||||
"a": {
|
||||
"type": "any",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": false
|
||||
},
|
||||
"e": {
|
||||
"type": "string",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": false,
|
||||
"enum": [
|
||||
"foo",
|
||||
"bar"
|
||||
]
|
||||
},
|
||||
"er": {
|
||||
"type": "string",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": true,
|
||||
"enum": [
|
||||
"one",
|
||||
"two",
|
||||
"three"
|
||||
]
|
||||
},
|
||||
"sr": {
|
||||
"type": "string",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": true,
|
||||
"pattern": "[a-z]+"
|
||||
},
|
||||
"do": {
|
||||
"type": "string",
|
||||
"location": "query",
|
||||
"required": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
"things": {
|
||||
"resources": {
|
||||
"subthings": {
|
||||
"methods": {
|
||||
"list": {
|
||||
"path": "things",
|
||||
"id": "test.things.subthings.list",
|
||||
"httpMethod": "GET",
|
||||
"parameters": {
|
||||
"max-results": {
|
||||
"type": "number",
|
||||
"location": "query",
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
"response": {
|
||||
"$ref": "ThingList"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"methods": {
|
||||
"list": {
|
||||
"path": "things",
|
||||
"id": "test.things.list",
|
||||
"httpMethod": "GET",
|
||||
"parameters": {
|
||||
"max-results": {
|
||||
"type": "number",
|
||||
"location": "query",
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
"response": {
|
||||
"$ref": "ThingList"
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"path": "things/{id}",
|
||||
"id": "test.things.delete",
|
||||
"httpMethod": "DELETE",
|
||||
"description": "Delete things",
|
||||
"parameters": {
|
||||
"id": {
|
||||
"location": "path",
|
||||
"required": true,
|
||||
"description": "ID of the thing to delete",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"parameterOrder": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"get": {
|
||||
"path": "things/{id}",
|
||||
"id": "test.things.get",
|
||||
"httpMethod": "GET",
|
||||
"description": "Get things",
|
||||
"supportsMediaDownload": true,
|
||||
"parameters": {
|
||||
"id": {
|
||||
"location": "path",
|
||||
"required": true,
|
||||
"description": "ID of the thing to get",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"supportsMediaDownload": true,
|
||||
"parameterOrder": [
|
||||
"id"
|
||||
],
|
||||
"response": {
|
||||
"$ref": "Thing"
|
||||
}
|
||||
},
|
||||
"create": {
|
||||
"path": "things",
|
||||
"id": "test.things.create",
|
||||
"httpMethod": "POST",
|
||||
"description": "Create things",
|
||||
"request": {
|
||||
"$ref": "Thing"
|
||||
},
|
||||
"response": {
|
||||
"$ref": "Thing"
|
||||
},
|
||||
"supportsMediaUpload": true,
|
||||
"mediaUpload": {
|
||||
"accept": [
|
||||
"*/*"
|
||||
],
|
||||
"maxSize": "1KB",
|
||||
"protocols": {
|
||||
"simple": {
|
||||
"multipart": true,
|
||||
"path": "upload/things/{id}"
|
||||
},
|
||||
"resumable": {
|
||||
"multipart": true,
|
||||
"path": "/resumable/upload/things/{id}"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"update": {
|
||||
"path": "things/{id}",
|
||||
"id": "test.things.update",
|
||||
"httpMethod": "PUT",
|
||||
"description": "Update things",
|
||||
"parameters": {
|
||||
"id": {
|
||||
"location": "path",
|
||||
"description": "ID of the thing to update",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"parameterOrder": [
|
||||
"id"
|
||||
],
|
||||
"request": {
|
||||
"$ref": "Thing"
|
||||
},
|
||||
"response": {
|
||||
"$ref": "Thing"
|
||||
},
|
||||
"supportsMediaUpload": true,
|
||||
"mediaUpload": {
|
||||
"accept": [
|
||||
"*/*"
|
||||
],
|
||||
"maxSize": "1KB",
|
||||
"protocols": {
|
||||
"simple": {
|
||||
"multipart": true,
|
||||
"path": "upload/things/{id}"
|
||||
},
|
||||
"resumable": {
|
||||
"multipart": true,
|
||||
"path": "/resumable/upload/things/{id}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,584 +0,0 @@
|
|||
{
|
||||
"kind": "discovery#describeItem",
|
||||
"name": "zoo",
|
||||
"version": "v1",
|
||||
"description": "Zoo API used for testing",
|
||||
"basePath": "/zoo/",
|
||||
"rootUrl": "https://www.googleapis.com/",
|
||||
"servicePath": "zoo/v1/",
|
||||
"rpcPath": "/rpc",
|
||||
"parameters": {
|
||||
"alt": {
|
||||
"type": "string",
|
||||
"description": "Data format for the response.",
|
||||
"default": "json",
|
||||
"enum": [
|
||||
"json"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Responses with Content-Type of application/json"
|
||||
],
|
||||
"location": "query"
|
||||
},
|
||||
"fields": {
|
||||
"type": "string",
|
||||
"description": "Selector specifying which fields to include in a partial response.",
|
||||
"location": "query"
|
||||
},
|
||||
"key": {
|
||||
"type": "string",
|
||||
"description": "API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token.",
|
||||
"location": "query"
|
||||
},
|
||||
"oauth_token": {
|
||||
"type": "string",
|
||||
"description": "OAuth 2.0 token for the current user.",
|
||||
"location": "query"
|
||||
},
|
||||
"prettyPrint": {
|
||||
"type": "boolean",
|
||||
"description": "Returns response with indentations and line breaks.",
|
||||
"default": "true",
|
||||
"location": "query"
|
||||
},
|
||||
"quotaUser": {
|
||||
"type": "string",
|
||||
"description": "Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Overrides userIp if both are provided.",
|
||||
"location": "query"
|
||||
},
|
||||
"userIp": {
|
||||
"type": "string",
|
||||
"description": "IP address of the site where the request originates. Use this if you want to enforce per-user limits.",
|
||||
"location": "query"
|
||||
}
|
||||
},
|
||||
"features": [
|
||||
"dataWrapper"
|
||||
],
|
||||
"schemas": {
|
||||
"Animal": {
|
||||
"id": "Animal",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"etag": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"default": "zoo#animal"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"photo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string"
|
||||
},
|
||||
"hash": {
|
||||
"type": "string"
|
||||
},
|
||||
"hashAlgorithm": {
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"type": "integer"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Animal2": {
|
||||
"id": "Animal2",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"default": "zoo#animal"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AnimalFeed": {
|
||||
"id": "AnimalFeed",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"etag": {
|
||||
"type": "string"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "Animal"
|
||||
}
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"default": "zoo#animalFeed"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AnimalMap": {
|
||||
"id": "AnimalMap",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"etag": {
|
||||
"type": "string"
|
||||
},
|
||||
"animals": {
|
||||
"type": "object",
|
||||
"description": "Map of animal id to animal data",
|
||||
"additionalProperties": {
|
||||
"$ref": "Animal"
|
||||
}
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"default": "zoo#animalMap"
|
||||
}
|
||||
}
|
||||
},
|
||||
"LoadFeed": {
|
||||
"id": "LoadFeed",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"doubleVal": {
|
||||
"type": "number"
|
||||
},
|
||||
"nullVal": {
|
||||
"type": "null"
|
||||
},
|
||||
"booleanVal": {
|
||||
"type": "boolean",
|
||||
"description": "True or False."
|
||||
},
|
||||
"anyVal": {
|
||||
"type": "any",
|
||||
"description": "Anything will do."
|
||||
},
|
||||
"enumVal": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"default": "zoo#loadValue"
|
||||
},
|
||||
"longVal": {
|
||||
"type": "integer"
|
||||
},
|
||||
"stringVal": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"default": "zoo#loadFeed"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"methods": {
|
||||
"query": {
|
||||
"path": "query",
|
||||
"id": "bigquery.query",
|
||||
"httpMethod": "GET",
|
||||
"parameters": {
|
||||
"q": {
|
||||
"type": "string",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": false
|
||||
},
|
||||
"i": {
|
||||
"type": "integer",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": false,
|
||||
"minimum": "0",
|
||||
"maximum": "4294967295",
|
||||
"default": "20"
|
||||
},
|
||||
"n": {
|
||||
"type": "number",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": false
|
||||
},
|
||||
"b": {
|
||||
"type": "boolean",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": false
|
||||
},
|
||||
"a": {
|
||||
"type": "any",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": false
|
||||
},
|
||||
"o": {
|
||||
"type": "object",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": false
|
||||
},
|
||||
"e": {
|
||||
"type": "string",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": false,
|
||||
"enum": [
|
||||
"foo",
|
||||
"bar"
|
||||
]
|
||||
},
|
||||
"er": {
|
||||
"type": "string",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": true,
|
||||
"enum": [
|
||||
"one",
|
||||
"two",
|
||||
"three"
|
||||
]
|
||||
},
|
||||
"rr": {
|
||||
"type": "string",
|
||||
"location": "query",
|
||||
"required": false,
|
||||
"repeated": true,
|
||||
"pattern": "[a-z]+"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
"my": {
|
||||
"resources": {
|
||||
"favorites": {
|
||||
"methods": {
|
||||
"list": {
|
||||
"path": "favorites/@me/mine",
|
||||
"id": "zoo.animals.mine",
|
||||
"httpMethod": "GET",
|
||||
"parameters": {
|
||||
"max-results": {
|
||||
"location": "query",
|
||||
"required": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"resources": {
|
||||
"print": {
|
||||
"methods": {
|
||||
"assert": {
|
||||
"path": "global/print/assert",
|
||||
"id": "zoo.animals.mine",
|
||||
"httpMethod": "GET",
|
||||
"parameters": {
|
||||
"max-results": {
|
||||
"location": "query",
|
||||
"required": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animals": {
|
||||
"methods": {
|
||||
"crossbreed": {
|
||||
"path": "animals/crossbreed",
|
||||
"id": "zoo.animals.crossbreed",
|
||||
"httpMethod": "POST",
|
||||
"description": "Cross-breed animals",
|
||||
"response": {
|
||||
"$ref": "Animal2"
|
||||
},
|
||||
"mediaUpload": {
|
||||
"accept": [
|
||||
"image/png"
|
||||
],
|
||||
"protocols": {
|
||||
"simple": {
|
||||
"multipart": true,
|
||||
"path": "upload/activities/{userId}/@self"
|
||||
},
|
||||
"resumable": {
|
||||
"multipart": true,
|
||||
"path": "upload/activities/{userId}/@self"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"path": "animals/{name}",
|
||||
"id": "zoo.animals.delete",
|
||||
"httpMethod": "DELETE",
|
||||
"description": "Delete animals",
|
||||
"parameters": {
|
||||
"name": {
|
||||
"location": "path",
|
||||
"required": true,
|
||||
"description": "Name of the animal to delete",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"parameterOrder": [
|
||||
"name"
|
||||
]
|
||||
},
|
||||
"get": {
|
||||
"path": "animals/{name}",
|
||||
"id": "zoo.animals.get",
|
||||
"httpMethod": "GET",
|
||||
"description": "Get animals",
|
||||
"supportsMediaDownload": true,
|
||||
"parameters": {
|
||||
"name": {
|
||||
"location": "path",
|
||||
"required": true,
|
||||
"description": "Name of the animal to load",
|
||||
"type": "string"
|
||||
},
|
||||
"projection": {
|
||||
"location": "query",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"full"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Include everything"
|
||||
]
|
||||
}
|
||||
},
|
||||
"parameterOrder": [
|
||||
"name"
|
||||
],
|
||||
"response": {
|
||||
"$ref": "Animal"
|
||||
}
|
||||
},
|
||||
"getmedia": {
|
||||
"path": "animals/{name}",
|
||||
"id": "zoo.animals.get",
|
||||
"httpMethod": "GET",
|
||||
"description": "Get animals",
|
||||
"parameters": {
|
||||
"name": {
|
||||
"location": "path",
|
||||
"required": true,
|
||||
"description": "Name of the animal to load",
|
||||
"type": "string"
|
||||
},
|
||||
"projection": {
|
||||
"location": "query",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"full"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Include everything"
|
||||
]
|
||||
}
|
||||
},
|
||||
"parameterOrder": [
|
||||
"name"
|
||||
]
|
||||
},
|
||||
"insert": {
|
||||
"path": "animals",
|
||||
"id": "zoo.animals.insert",
|
||||
"httpMethod": "POST",
|
||||
"description": "Insert animals",
|
||||
"request": {
|
||||
"$ref": "Animal"
|
||||
},
|
||||
"response": {
|
||||
"$ref": "Animal"
|
||||
},
|
||||
"mediaUpload": {
|
||||
"accept": [
|
||||
"image/png"
|
||||
],
|
||||
"maxSize": "1KB",
|
||||
"protocols": {
|
||||
"simple": {
|
||||
"multipart": true,
|
||||
"path": "upload/activities/{userId}/@self"
|
||||
},
|
||||
"resumable": {
|
||||
"multipart": true,
|
||||
"path": "upload/activities/{userId}/@self"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"list": {
|
||||
"path": "animals",
|
||||
"id": "zoo.animals.list",
|
||||
"httpMethod": "GET",
|
||||
"description": "List animals",
|
||||
"parameters": {
|
||||
"max-results": {
|
||||
"location": "query",
|
||||
"description": "Maximum number of results to return",
|
||||
"type": "integer",
|
||||
"minimum": "0"
|
||||
},
|
||||
"name": {
|
||||
"location": "query",
|
||||
"description": "Restrict result to animals with this name",
|
||||
"type": "string"
|
||||
},
|
||||
"projection": {
|
||||
"location": "query",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"full"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Include absolutely everything"
|
||||
]
|
||||
},
|
||||
"start-token": {
|
||||
"location": "query",
|
||||
"description": "Pagination token",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"response": {
|
||||
"$ref": "AnimalFeed"
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"path": "animals/{name}",
|
||||
"id": "zoo.animals.patch",
|
||||
"httpMethod": "PATCH",
|
||||
"description": "Update animals",
|
||||
"parameters": {
|
||||
"name": {
|
||||
"location": "path",
|
||||
"required": true,
|
||||
"description": "Name of the animal to update",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"parameterOrder": [
|
||||
"name"
|
||||
],
|
||||
"request": {
|
||||
"$ref": "Animal"
|
||||
},
|
||||
"response": {
|
||||
"$ref": "Animal"
|
||||
}
|
||||
},
|
||||
"update": {
|
||||
"path": "animals/{name}",
|
||||
"id": "zoo.animals.update",
|
||||
"httpMethod": "PUT",
|
||||
"description": "Update animals",
|
||||
"parameters": {
|
||||
"name": {
|
||||
"location": "path",
|
||||
"description": "Name of the animal to update",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"parameterOrder": [
|
||||
"name"
|
||||
],
|
||||
"request": {
|
||||
"$ref": "Animal"
|
||||
},
|
||||
"response": {
|
||||
"$ref": "Animal"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"load": {
|
||||
"methods": {
|
||||
"list": {
|
||||
"path": "load",
|
||||
"id": "zoo.load.list",
|
||||
"httpMethod": "GET",
|
||||
"response": {
|
||||
"$ref": "LoadFeed"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"loadNoTemplate": {
|
||||
"methods": {
|
||||
"list": {
|
||||
"path": "loadNoTemplate",
|
||||
"id": "zoo.loadNoTemplate.list",
|
||||
"httpMethod": "GET"
|
||||
}
|
||||
}
|
||||
},
|
||||
"scopedAnimals": {
|
||||
"methods": {
|
||||
"list": {
|
||||
"path": "scopedanimals",
|
||||
"id": "zoo.scopedAnimals.list",
|
||||
"httpMethod": "GET",
|
||||
"description": "List animals (scoped)",
|
||||
"parameters": {
|
||||
"max-results": {
|
||||
"location": "query",
|
||||
"description": "Maximum number of results to return",
|
||||
"type": "integer",
|
||||
"minimum": "0"
|
||||
},
|
||||
"name": {
|
||||
"location": "query",
|
||||
"description": "Restrict result to animals with this name",
|
||||
"type": "string"
|
||||
},
|
||||
"projection": {
|
||||
"location": "query",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"full"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Include absolutely everything"
|
||||
]
|
||||
},
|
||||
"start-token": {
|
||||
"location": "query",
|
||||
"description": "Pagination token",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"response": {
|
||||
"$ref": "AnimalFeed"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
require 'google/api_client'
|
||||
require 'google/api_client/version'
|
||||
require 'google/api_client/auth/storage'
|
||||
|
||||
describe Google::APIClient::Storage do
|
||||
let(:client) { Google::APIClient.new(:application_name => 'API Client Tests') }
|
||||
let(:root_path) { File.expand_path(File.join(__FILE__, '..', '..', '..')) }
|
||||
let(:json_file) { File.expand_path(File.join(root_path, 'fixtures', 'files', 'auth_stored_credentials.json')) }
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
require 'google/api_client'
|
||||
require 'google/api_client/version'
|
||||
require 'google/api_client/auth/storages/file_store'
|
||||
|
||||
describe Google::APIClient::FileStore do
|
||||
let(:root_path) { File.expand_path(File.join(__FILE__, '..','..','..', '..','..')) }
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
require 'google/api_client'
|
||||
require 'google/api_client/version'
|
||||
|
||||
require 'google/api_client/auth/storages/redis_store'
|
||||
|
||||
describe Google::APIClient::RedisStore do
|
||||
let(:root_path) { File.expand_path(File.join(__FILE__, '..', '..', '..', '..', '..')) }
|
||||
|
|
|
@ -1,248 +0,0 @@
|
|||
# Copyright 2012 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'spec_helper'
|
||||
require 'google/api_client'
|
||||
|
||||
RSpec.describe Google::APIClient::BatchRequest do
|
||||
CLIENT = Google::APIClient.new(:application_name => 'API Client Tests') unless defined?(CLIENT)
|
||||
|
||||
after do
|
||||
# Reset client to not-quite-pristine state
|
||||
CLIENT.key = nil
|
||||
CLIENT.user_ip = nil
|
||||
end
|
||||
|
||||
it 'should raise an error if making an empty batch request' do
|
||||
batch = Google::APIClient::BatchRequest.new
|
||||
|
||||
expect(lambda do
|
||||
CLIENT.execute(batch)
|
||||
end).to raise_error(Google::APIClient::BatchError)
|
||||
end
|
||||
|
||||
it 'should allow query parameters in batch requests' do
|
||||
batch = Google::APIClient::BatchRequest.new
|
||||
batch.add(:uri => 'https://example.com', :parameters => {
|
||||
'a' => '12345'
|
||||
})
|
||||
method, uri, headers, body = batch.to_http_request
|
||||
expect(body.read).to include("/?a=12345")
|
||||
end
|
||||
|
||||
describe 'with the discovery API' do
|
||||
before do
|
||||
CLIENT.authorization = nil
|
||||
@discovery = CLIENT.discovered_api('discovery', 'v1')
|
||||
end
|
||||
|
||||
describe 'with two valid requests' do
|
||||
before do
|
||||
@call1 = {
|
||||
:api_method => @discovery.apis.get_rest,
|
||||
:parameters => {
|
||||
'api' => 'plus',
|
||||
'version' => 'v1'
|
||||
}
|
||||
}
|
||||
|
||||
@call2 = {
|
||||
:api_method => @discovery.apis.get_rest,
|
||||
:parameters => {
|
||||
'api' => 'discovery',
|
||||
'version' => 'v1'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'should execute both when using a global callback' do
|
||||
block_called = 0
|
||||
ids = ['first_call', 'second_call']
|
||||
expected_ids = ids.clone
|
||||
batch = Google::APIClient::BatchRequest.new do |result|
|
||||
block_called += 1
|
||||
expect(result.status).to eq(200)
|
||||
expect(expected_ids).to include(result.response.call_id)
|
||||
expected_ids.delete(result.response.call_id)
|
||||
end
|
||||
|
||||
batch.add(@call1, ids[0])
|
||||
batch.add(@call2, ids[1])
|
||||
|
||||
CLIENT.execute(batch)
|
||||
expect(block_called).to eq(2)
|
||||
end
|
||||
|
||||
it 'should execute both when using individual callbacks' do
|
||||
batch = Google::APIClient::BatchRequest.new
|
||||
|
||||
call1_returned, call2_returned = false, false
|
||||
batch.add(@call1) do |result|
|
||||
call1_returned = true
|
||||
expect(result.status).to eq(200)
|
||||
end
|
||||
batch.add(@call2) do |result|
|
||||
call2_returned = true
|
||||
expect(result.status).to eq(200)
|
||||
end
|
||||
|
||||
CLIENT.execute(batch)
|
||||
expect(call1_returned).to be_truthy
|
||||
expect(call2_returned).to be_truthy
|
||||
end
|
||||
|
||||
it 'should raise an error if using the same call ID more than once' do
|
||||
batch = Google::APIClient::BatchRequest.new
|
||||
|
||||
expect(lambda do
|
||||
batch.add(@call1, 'my_id')
|
||||
batch.add(@call2, 'my_id')
|
||||
end).to raise_error(Google::APIClient::BatchError)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with a valid request and an invalid one' do
|
||||
before do
|
||||
@call1 = {
|
||||
:api_method => @discovery.apis.get_rest,
|
||||
:parameters => {
|
||||
'api' => 'plus',
|
||||
'version' => 'v1'
|
||||
}
|
||||
}
|
||||
|
||||
@call2 = {
|
||||
:api_method => @discovery.apis.get_rest,
|
||||
:parameters => {
|
||||
'api' => 0,
|
||||
'version' => 1
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'should execute both when using a global callback' do
|
||||
block_called = 0
|
||||
ids = ['first_call', 'second_call']
|
||||
expected_ids = ids.clone
|
||||
batch = Google::APIClient::BatchRequest.new do |result|
|
||||
block_called += 1
|
||||
expect(expected_ids).to include(result.response.call_id)
|
||||
expected_ids.delete(result.response.call_id)
|
||||
if result.response.call_id == ids[0]
|
||||
expect(result.status).to eq(200)
|
||||
else
|
||||
expect(result.status).to be >= 400
|
||||
expect(result.status).to be < 500
|
||||
end
|
||||
end
|
||||
|
||||
batch.add(@call1, ids[0])
|
||||
batch.add(@call2, ids[1])
|
||||
|
||||
CLIENT.execute(batch)
|
||||
expect(block_called).to eq(2)
|
||||
end
|
||||
|
||||
it 'should execute both when using individual callbacks' do
|
||||
batch = Google::APIClient::BatchRequest.new
|
||||
|
||||
call1_returned, call2_returned = false, false
|
||||
batch.add(@call1) do |result|
|
||||
call1_returned = true
|
||||
expect(result.status).to eq(200)
|
||||
end
|
||||
batch.add(@call2) do |result|
|
||||
call2_returned = true
|
||||
expect(result.status).to be >= 400
|
||||
expect(result.status).to be < 500
|
||||
end
|
||||
|
||||
CLIENT.execute(batch)
|
||||
expect(call1_returned).to be_truthy
|
||||
expect(call2_returned).to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with the calendar API' do
|
||||
before do
|
||||
CLIENT.authorization = nil
|
||||
@calendar = CLIENT.discovered_api('calendar', 'v3')
|
||||
end
|
||||
|
||||
describe 'with two valid requests' do
|
||||
before do
|
||||
event1 = {
|
||||
'summary' => 'Appointment 1',
|
||||
'location' => 'Somewhere',
|
||||
'start' => {
|
||||
'dateTime' => '2011-01-01T10:00:00.000-07:00'
|
||||
},
|
||||
'end' => {
|
||||
'dateTime' => '2011-01-01T10:25:00.000-07:00'
|
||||
},
|
||||
'attendees' => [
|
||||
{
|
||||
'email' => 'myemail@mydomain.tld'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
event2 = {
|
||||
'summary' => 'Appointment 2',
|
||||
'location' => 'Somewhere as well',
|
||||
'start' => {
|
||||
'dateTime' => '2011-01-02T10:00:00.000-07:00'
|
||||
},
|
||||
'end' => {
|
||||
'dateTime' => '2011-01-02T10:25:00.000-07:00'
|
||||
},
|
||||
'attendees' => [
|
||||
{
|
||||
'email' => 'myemail@mydomain.tld'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@call1 = {
|
||||
:api_method => @calendar.events.insert,
|
||||
:parameters => {'calendarId' => 'myemail@mydomain.tld'},
|
||||
:body => MultiJson.dump(event1),
|
||||
:headers => {'Content-Type' => 'application/json'}
|
||||
}
|
||||
|
||||
@call2 = {
|
||||
:api_method => @calendar.events.insert,
|
||||
:parameters => {'calendarId' => 'myemail@mydomain.tld'},
|
||||
:body => MultiJson.dump(event2),
|
||||
:headers => {'Content-Type' => 'application/json'}
|
||||
}
|
||||
end
|
||||
|
||||
it 'should convert to a correct HTTP request' do
|
||||
batch = Google::APIClient::BatchRequest.new { |result| }
|
||||
batch.add(@call1, '1').add(@call2, '2')
|
||||
request = batch.to_env(CLIENT.connection)
|
||||
boundary = Google::APIClient::BatchRequest::BATCH_BOUNDARY
|
||||
expect(request[:method].to_s.downcase).to eq('post')
|
||||
expect(request[:url].to_s).to eq('https://www.googleapis.com/batch')
|
||||
expect(request[:request_headers]['Content-Type']).to eq("multipart/mixed;boundary=#{boundary}")
|
||||
body = request[:body].read
|
||||
expect(body).to include(@call1[:body])
|
||||
expect(body).to include(@call2[:body])
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,708 +0,0 @@
|
|||
# encoding:utf-8
|
||||
|
||||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
require 'faraday'
|
||||
require 'multi_json'
|
||||
require 'compat/multi_json'
|
||||
require 'signet/oauth_1/client'
|
||||
require 'google/api_client'
|
||||
|
||||
fixtures_path = File.expand_path('../../../fixtures', __FILE__)
|
||||
|
||||
RSpec.describe Google::APIClient do
|
||||
include ConnectionHelpers
|
||||
CLIENT = Google::APIClient.new(:application_name => 'API Client Tests') unless defined?(CLIENT)
|
||||
|
||||
after do
|
||||
# Reset client to not-quite-pristine state
|
||||
CLIENT.key = nil
|
||||
CLIENT.user_ip = nil
|
||||
end
|
||||
|
||||
it 'should raise a type error for bogus authorization' do
|
||||
expect(lambda do
|
||||
Google::APIClient.new(:application_name => 'API Client Tests', :authorization => 42)
|
||||
end).to raise_error(TypeError)
|
||||
end
|
||||
|
||||
it 'should not be able to retrieve the discovery document for a bogus API' do
|
||||
expect(lambda do
|
||||
CLIENT.discovery_document('bogus')
|
||||
end).to raise_error(Google::APIClient::TransmissionError)
|
||||
expect(lambda do
|
||||
CLIENT.discovered_api('bogus')
|
||||
end).to raise_error(Google::APIClient::TransmissionError)
|
||||
end
|
||||
|
||||
it 'should raise an error for bogus services' do
|
||||
expect(lambda do
|
||||
CLIENT.discovered_api(42)
|
||||
end).to raise_error(TypeError)
|
||||
end
|
||||
|
||||
it 'should raise an error for bogus services' do
|
||||
expect(lambda do
|
||||
CLIENT.preferred_version(42)
|
||||
end).to raise_error(TypeError)
|
||||
end
|
||||
|
||||
it 'should raise an error for bogus methods' do
|
||||
expect(lambda do
|
||||
CLIENT.execute(42)
|
||||
end).to raise_error(TypeError)
|
||||
end
|
||||
|
||||
it 'should not return a preferred version for bogus service names' do
|
||||
expect(CLIENT.preferred_version('bogus')).to eq(nil)
|
||||
end
|
||||
|
||||
describe 'with zoo API' do
|
||||
it 'should return API instance registered from file' do
|
||||
zoo_json = File.join(fixtures_path, 'files', 'zoo.json')
|
||||
contents = File.open(zoo_json, 'rb') { |io| io.read }
|
||||
api = CLIENT.register_discovery_document('zoo', 'v1', contents)
|
||||
expect(api).to be_kind_of(Google::APIClient::API)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with the prediction API' do
|
||||
before do
|
||||
CLIENT.authorization = nil
|
||||
# The prediction API no longer exposes a v1, so we have to be
|
||||
# careful about looking up the wrong API version.
|
||||
@prediction = CLIENT.discovered_api('prediction', 'v1.2')
|
||||
end
|
||||
|
||||
it 'should correctly determine the discovery URI' do
|
||||
expect(CLIENT.discovery_uri('prediction')).to be ===
|
||||
'https://www.googleapis.com/discovery/v1/apis/prediction/v1/rest'
|
||||
end
|
||||
|
||||
it 'should correctly determine the discovery URI if :user_ip is set' do
|
||||
CLIENT.user_ip = '127.0.0.1'
|
||||
|
||||
conn = stub_connection do |stub|
|
||||
stub.get('/discovery/v1/apis/prediction/v1.2/rest?userIp=127.0.0.1') do |env|
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
CLIENT.execute(
|
||||
:http_method => 'GET',
|
||||
:uri => CLIENT.discovery_uri('prediction', 'v1.2'),
|
||||
:authenticated => false,
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should correctly determine the discovery URI if :key is set' do
|
||||
CLIENT.key = 'qwerty'
|
||||
conn = stub_connection do |stub|
|
||||
stub.get('/discovery/v1/apis/prediction/v1.2/rest?key=qwerty') do |env|
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
request = CLIENT.execute(
|
||||
:http_method => 'GET',
|
||||
:uri => CLIENT.discovery_uri('prediction', 'v1.2'),
|
||||
:authenticated => false,
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should correctly determine the discovery URI if both are set' do
|
||||
CLIENT.key = 'qwerty'
|
||||
CLIENT.user_ip = '127.0.0.1'
|
||||
conn = stub_connection do |stub|
|
||||
stub.get('/discovery/v1/apis/prediction/v1.2/rest?key=qwerty&userIp=127.0.0.1') do |env|
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
request = CLIENT.execute(
|
||||
:http_method => 'GET',
|
||||
:uri => CLIENT.discovery_uri('prediction', 'v1.2'),
|
||||
:authenticated => false,
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should correctly generate API objects' do
|
||||
expect(CLIENT.discovered_api('prediction', 'v1.2').name).to eq('prediction')
|
||||
expect(CLIENT.discovered_api('prediction', 'v1.2').version).to eq('v1.2')
|
||||
expect(CLIENT.discovered_api(:prediction, 'v1.2').name).to eq('prediction')
|
||||
expect(CLIENT.discovered_api(:prediction, 'v1.2').version).to eq('v1.2')
|
||||
end
|
||||
|
||||
it 'should discover methods' do
|
||||
expect(CLIENT.discovered_method(
|
||||
'prediction.training.insert', 'prediction', 'v1.2'
|
||||
).name).to eq('insert')
|
||||
expect(CLIENT.discovered_method(
|
||||
:'prediction.training.insert', :prediction, 'v1.2'
|
||||
).name).to eq('insert')
|
||||
expect(CLIENT.discovered_method(
|
||||
'prediction.training.delete', 'prediction', 'v1.2'
|
||||
).name).to eq('delete')
|
||||
end
|
||||
|
||||
it 'should define the origin API in discovered methods' do
|
||||
expect(CLIENT.discovered_method(
|
||||
'prediction.training.insert', 'prediction', 'v1.2'
|
||||
).api.name).to eq('prediction')
|
||||
end
|
||||
|
||||
it 'should not find methods that are not in the discovery document' do
|
||||
expect(CLIENT.discovered_method(
|
||||
'prediction.bogus', 'prediction', 'v1.2'
|
||||
)).to eq(nil)
|
||||
end
|
||||
|
||||
it 'should raise an error for bogus methods' do
|
||||
expect(lambda do
|
||||
CLIENT.discovered_method(42, 'prediction', 'v1.2')
|
||||
end).to raise_error(TypeError)
|
||||
end
|
||||
|
||||
it 'should raise an error for bogus methods' do
|
||||
expect(lambda do
|
||||
CLIENT.execute(:api_method => CLIENT.discovered_api('prediction', 'v1.2'))
|
||||
end).to raise_error(TypeError)
|
||||
end
|
||||
|
||||
it 'should correctly determine the preferred version' do
|
||||
expect(CLIENT.preferred_version('prediction').version).not_to eq('v1')
|
||||
expect(CLIENT.preferred_version(:prediction).version).not_to eq('v1')
|
||||
end
|
||||
|
||||
it 'should return a batch path' do
|
||||
expect(CLIENT.discovered_api('prediction', 'v1.2').batch_path).not_to be_nil
|
||||
end
|
||||
|
||||
it 'should generate valid requests' do
|
||||
conn = stub_connection do |stub|
|
||||
stub.post('/prediction/v1.2/training?data=12345') do |env|
|
||||
expect(env[:body]).to eq('')
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
request = CLIENT.execute(
|
||||
:api_method => @prediction.training.insert,
|
||||
:parameters => {'data' => '12345'},
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should generate valid requests when parameter value includes semicolon' do
|
||||
conn = stub_connection do |stub|
|
||||
# semicolon (;) in parameter value was being converted to
|
||||
# bare ampersand (&) in 0.4.7. ensure that it gets converted
|
||||
# to a CGI-escaped semicolon (%3B) instead.
|
||||
stub.post('/prediction/v1.2/training?data=12345%3B67890') do |env|
|
||||
expect(env[:body]).to eq('')
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
request = CLIENT.execute(
|
||||
:api_method => @prediction.training.insert,
|
||||
:parameters => {'data' => '12345;67890'},
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should generate valid requests when multivalued parameters are passed' do
|
||||
conn = stub_connection do |stub|
|
||||
stub.post('/prediction/v1.2/training?data=1&data=2') do |env|
|
||||
expect(env.params['data']).to include('1', '2')
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
request = CLIENT.execute(
|
||||
:api_method => @prediction.training.insert,
|
||||
:parameters => {'data' => ['1', '2']},
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should generate requests against the correct URIs' do
|
||||
conn = stub_connection do |stub|
|
||||
stub.post('/prediction/v1.2/training?data=12345') do |env|
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
request = CLIENT.execute(
|
||||
:api_method => @prediction.training.insert,
|
||||
:parameters => {'data' => '12345'},
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should generate requests against the correct URIs' do
|
||||
conn = stub_connection do |stub|
|
||||
stub.post('/prediction/v1.2/training?data=12345') do |env|
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
request = CLIENT.execute(
|
||||
:api_method => @prediction.training.insert,
|
||||
:parameters => {'data' => '12345'},
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should allow modification to the base URIs for testing purposes' do
|
||||
# Using a new client instance here to avoid caching rebased discovery doc
|
||||
prediction_rebase =
|
||||
Google::APIClient.new(:application_name => 'API Client Tests').discovered_api('prediction', 'v1.2')
|
||||
prediction_rebase.method_base =
|
||||
'https://testing-domain.example.com/prediction/v1.2/'
|
||||
|
||||
conn = stub_connection do |stub|
|
||||
stub.post('/prediction/v1.2/training') do |env|
|
||||
expect(env[:url].host).to eq('testing-domain.example.com')
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
|
||||
request = CLIENT.execute(
|
||||
:api_method => prediction_rebase.training.insert,
|
||||
:parameters => {'data' => '123'},
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should generate OAuth 1 requests' do
|
||||
CLIENT.authorization = :oauth_1
|
||||
CLIENT.authorization.token_credential_key = '12345'
|
||||
CLIENT.authorization.token_credential_secret = '12345'
|
||||
|
||||
conn = stub_connection do |stub|
|
||||
stub.post('/prediction/v1.2/training?data=12345') do |env|
|
||||
expect(env[:request_headers]).to have_key('Authorization')
|
||||
expect(env[:request_headers]['Authorization']).to match(/^OAuth/)
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
|
||||
request = CLIENT.execute(
|
||||
:api_method => @prediction.training.insert,
|
||||
:parameters => {'data' => '12345'},
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should generate OAuth 2 requests' do
|
||||
CLIENT.authorization = :oauth_2
|
||||
CLIENT.authorization.access_token = '12345'
|
||||
|
||||
conn = stub_connection do |stub|
|
||||
stub.post('/prediction/v1.2/training?data=12345') do |env|
|
||||
expect(env[:request_headers]).to have_key('Authorization')
|
||||
expect(env[:request_headers]['Authorization']).to match(/^Bearer/)
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
|
||||
request = CLIENT.execute(
|
||||
:api_method => @prediction.training.insert,
|
||||
:parameters => {'data' => '12345'},
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should not be able to execute improperly authorized requests' do
|
||||
CLIENT.authorization = :oauth_1
|
||||
CLIENT.authorization.token_credential_key = '12345'
|
||||
CLIENT.authorization.token_credential_secret = '12345'
|
||||
result = CLIENT.execute(
|
||||
@prediction.training.insert,
|
||||
{'data' => '12345'}
|
||||
)
|
||||
expect(result.response.status).to eq(401)
|
||||
end
|
||||
|
||||
it 'should not be able to execute improperly authorized requests' do
|
||||
CLIENT.authorization = :oauth_2
|
||||
CLIENT.authorization.access_token = '12345'
|
||||
result = CLIENT.execute(
|
||||
@prediction.training.insert,
|
||||
{'data' => '12345'}
|
||||
)
|
||||
expect(result.response.status).to eq(401)
|
||||
end
|
||||
|
||||
it 'should not be able to execute improperly authorized requests' do
|
||||
expect(lambda do
|
||||
CLIENT.authorization = :oauth_1
|
||||
CLIENT.authorization.token_credential_key = '12345'
|
||||
CLIENT.authorization.token_credential_secret = '12345'
|
||||
result = CLIENT.execute!(
|
||||
@prediction.training.insert,
|
||||
{'data' => '12345'}
|
||||
)
|
||||
end).to raise_error(Google::APIClient::ClientError)
|
||||
end
|
||||
|
||||
it 'should not be able to execute improperly authorized requests' do
|
||||
expect(lambda do
|
||||
CLIENT.authorization = :oauth_2
|
||||
CLIENT.authorization.access_token = '12345'
|
||||
result = CLIENT.execute!(
|
||||
@prediction.training.insert,
|
||||
{'data' => '12345'}
|
||||
)
|
||||
end).to raise_error(Google::APIClient::ClientError)
|
||||
end
|
||||
|
||||
it 'should correctly handle unnamed parameters' do
|
||||
conn = stub_connection do |stub|
|
||||
stub.post('/prediction/v1.2/training') do |env|
|
||||
expect(env[:request_headers]).to have_key('Content-Type')
|
||||
expect(env[:request_headers]['Content-Type']).to eq('application/json')
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
CLIENT.authorization = :oauth_2
|
||||
CLIENT.authorization.access_token = '12345'
|
||||
CLIENT.execute(
|
||||
:api_method => @prediction.training.insert,
|
||||
:body => MultiJson.dump({"id" => "bucket/object"}),
|
||||
:headers => {'Content-Type' => 'application/json'},
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with the plus API' do
|
||||
before do
|
||||
CLIENT.authorization = nil
|
||||
@plus = CLIENT.discovered_api('plus')
|
||||
end
|
||||
|
||||
it 'should correctly determine the discovery URI' do
|
||||
expect(CLIENT.discovery_uri('plus')).to be ===
|
||||
'https://www.googleapis.com/discovery/v1/apis/plus/v1/rest'
|
||||
end
|
||||
|
||||
it 'should find APIs that are in the discovery document' do
|
||||
expect(CLIENT.discovered_api('plus').name).to eq('plus')
|
||||
expect(CLIENT.discovered_api('plus').version).to eq('v1')
|
||||
expect(CLIENT.discovered_api(:plus).name).to eq('plus')
|
||||
expect(CLIENT.discovered_api(:plus).version).to eq('v1')
|
||||
end
|
||||
|
||||
it 'should find methods that are in the discovery document' do
|
||||
# TODO(bobaman) Fix this when the RPC names are correct
|
||||
expect(CLIENT.discovered_method(
|
||||
'plus.activities.list', 'plus'
|
||||
).name).to eq('list')
|
||||
end
|
||||
|
||||
it 'should define the origin API in discovered methods' do
|
||||
expect(CLIENT.discovered_method(
|
||||
'plus.activities.list', 'plus'
|
||||
).api.name).to eq('plus')
|
||||
end
|
||||
|
||||
it 'should not find methods that are not in the discovery document' do
|
||||
expect(CLIENT.discovered_method('plus.bogus', 'plus')).to eq(nil)
|
||||
end
|
||||
|
||||
it 'should generate requests against the correct URIs' do
|
||||
conn = stub_connection do |stub|
|
||||
stub.get('/plus/v1/people/107807692475771887386/activities/public') do |env|
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
|
||||
request = CLIENT.execute(
|
||||
:api_method => @plus.activities.list,
|
||||
:parameters => {
|
||||
'userId' => '107807692475771887386', 'collection' => 'public'
|
||||
},
|
||||
:authenticated => false,
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should correctly validate parameters' do
|
||||
expect(lambda do
|
||||
CLIENT.execute(
|
||||
:api_method => @plus.activities.list,
|
||||
:parameters => {'alt' => 'json'},
|
||||
:authenticated => false
|
||||
)
|
||||
end).to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it 'should correctly validate parameters' do
|
||||
expect(lambda do
|
||||
CLIENT.execute(
|
||||
:api_method => @plus.activities.list,
|
||||
:parameters => {
|
||||
'userId' => '107807692475771887386', 'collection' => 'bogus'
|
||||
},
|
||||
:authenticated => false
|
||||
).to_env(CLIENT.connection)
|
||||
end).to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it 'should correctly determine the service root_uri' do
|
||||
expect(@plus.root_uri.to_s).to eq('https://www.googleapis.com/')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with the adsense API' do
|
||||
before do
|
||||
CLIENT.authorization = nil
|
||||
@adsense = CLIENT.discovered_api('adsense', 'v1.3')
|
||||
end
|
||||
|
||||
it 'should correctly determine the discovery URI' do
|
||||
expect(CLIENT.discovery_uri('adsense', 'v1.3').to_s).to be ===
|
||||
'https://www.googleapis.com/discovery/v1/apis/adsense/v1.3/rest'
|
||||
end
|
||||
|
||||
it 'should find APIs that are in the discovery document' do
|
||||
expect(CLIENT.discovered_api('adsense', 'v1.3').name).to eq('adsense')
|
||||
expect(CLIENT.discovered_api('adsense', 'v1.3').version).to eq('v1.3')
|
||||
end
|
||||
|
||||
it 'should return a batch path' do
|
||||
expect(CLIENT.discovered_api('adsense', 'v1.3').batch_path).not_to be_nil
|
||||
end
|
||||
|
||||
it 'should find methods that are in the discovery document' do
|
||||
expect(CLIENT.discovered_method(
|
||||
'adsense.reports.generate', 'adsense', 'v1.3'
|
||||
).name).to eq('generate')
|
||||
end
|
||||
|
||||
it 'should not find methods that are not in the discovery document' do
|
||||
expect(CLIENT.discovered_method('adsense.bogus', 'adsense', 'v1.3')).to eq(nil)
|
||||
end
|
||||
|
||||
it 'should generate requests against the correct URIs' do
|
||||
conn = stub_connection do |stub|
|
||||
stub.get('/adsense/v1.3/adclients') do |env|
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
request = CLIENT.execute(
|
||||
:api_method => @adsense.adclients.list,
|
||||
:authenticated => false,
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should not be able to execute requests without authorization' do
|
||||
result = CLIENT.execute(
|
||||
:api_method => @adsense.adclients.list,
|
||||
:authenticated => false
|
||||
)
|
||||
expect(result.response.status).to eq(401)
|
||||
end
|
||||
|
||||
it 'should fail when validating missing required parameters' do
|
||||
expect(lambda do
|
||||
CLIENT.execute(
|
||||
:api_method => @adsense.reports.generate,
|
||||
:authenticated => false
|
||||
)
|
||||
end).to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it 'should succeed when validating parameters in a correct call' do
|
||||
conn = stub_connection do |stub|
|
||||
stub.get('/adsense/v1.3/reports?dimension=DATE&endDate=2010-01-01&metric=PAGE_VIEWS&startDate=2000-01-01') do |env|
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
expect(lambda do
|
||||
CLIENT.execute(
|
||||
:api_method => @adsense.reports.generate,
|
||||
:parameters => {
|
||||
'startDate' => '2000-01-01',
|
||||
'endDate' => '2010-01-01',
|
||||
'dimension' => 'DATE',
|
||||
'metric' => 'PAGE_VIEWS'
|
||||
},
|
||||
:authenticated => false,
|
||||
:connection => conn
|
||||
)
|
||||
end).not_to raise_error
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should fail when validating parameters with invalid values' do
|
||||
expect(lambda do
|
||||
CLIENT.execute(
|
||||
:api_method => @adsense.reports.generate,
|
||||
:parameters => {
|
||||
'startDate' => '2000-01-01',
|
||||
'endDate' => '2010-01-01',
|
||||
'dimension' => 'BAD_CHARACTERS=-&*(£&',
|
||||
'metric' => 'PAGE_VIEWS'
|
||||
},
|
||||
:authenticated => false
|
||||
)
|
||||
end).to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it 'should succeed when validating repeated parameters in a correct call' do
|
||||
conn = stub_connection do |stub|
|
||||
stub.get('/adsense/v1.3/reports?dimension=DATE&dimension=PRODUCT_CODE'+
|
||||
'&endDate=2010-01-01&metric=CLICKS&metric=PAGE_VIEWS&'+
|
||||
'startDate=2000-01-01') do |env|
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
expect(lambda do
|
||||
CLIENT.execute(
|
||||
:api_method => @adsense.reports.generate,
|
||||
:parameters => {
|
||||
'startDate' => '2000-01-01',
|
||||
'endDate' => '2010-01-01',
|
||||
'dimension' => ['DATE', 'PRODUCT_CODE'],
|
||||
'metric' => ['PAGE_VIEWS', 'CLICKS']
|
||||
},
|
||||
:authenticated => false,
|
||||
:connection => conn
|
||||
)
|
||||
end).not_to raise_error
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should fail when validating incorrect repeated parameters' do
|
||||
expect(lambda do
|
||||
CLIENT.execute(
|
||||
:api_method => @adsense.reports.generate,
|
||||
:parameters => {
|
||||
'startDate' => '2000-01-01',
|
||||
'endDate' => '2010-01-01',
|
||||
'dimension' => ['DATE', 'BAD_CHARACTERS=-&*(£&'],
|
||||
'metric' => ['PAGE_VIEWS', 'CLICKS']
|
||||
},
|
||||
:authenticated => false
|
||||
)
|
||||
end).to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it 'should generate valid requests when multivalued parameters are passed' do
|
||||
conn = stub_connection do |stub|
|
||||
stub.get('/adsense/v1.3/reports?dimension=DATE&dimension=PRODUCT_CODE'+
|
||||
'&endDate=2010-01-01&metric=CLICKS&metric=PAGE_VIEWS&'+
|
||||
'startDate=2000-01-01') do |env|
|
||||
expect(env.params['dimension']).to include('DATE', 'PRODUCT_CODE')
|
||||
expect(env.params['metric']).to include('CLICKS', 'PAGE_VIEWS')
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
request = CLIENT.execute(
|
||||
:api_method => @adsense.reports.generate,
|
||||
:parameters => {
|
||||
'startDate' => '2000-01-01',
|
||||
'endDate' => '2010-01-01',
|
||||
'dimension' => ['DATE', 'PRODUCT_CODE'],
|
||||
'metric' => ['PAGE_VIEWS', 'CLICKS']
|
||||
},
|
||||
:authenticated => false,
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with the Drive API' do
|
||||
before do
|
||||
CLIENT.authorization = nil
|
||||
@drive = CLIENT.discovered_api('drive', 'v1')
|
||||
end
|
||||
|
||||
it 'should include media upload info methods' do
|
||||
expect(@drive.files.insert.media_upload).not_to eq(nil)
|
||||
end
|
||||
|
||||
it 'should include accepted media types' do
|
||||
expect(@drive.files.insert.media_upload.accepted_types).not_to be_empty
|
||||
end
|
||||
|
||||
it 'should have an upload path' do
|
||||
expect(@drive.files.insert.media_upload.uri_template).not_to eq(nil)
|
||||
end
|
||||
|
||||
it 'should have a max file size' do
|
||||
expect(@drive.files.insert.media_upload.max_size).not_to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with the Pub/Sub API' do
|
||||
before do
|
||||
CLIENT.authorization = nil
|
||||
@pubsub = CLIENT.discovered_api('pubsub', 'v1beta2')
|
||||
end
|
||||
|
||||
it 'should generate requests against the correct URIs' do
|
||||
conn = stub_connection do |stub|
|
||||
stub.get('/v1beta2/projects/12345/topics') do |env|
|
||||
expect(env[:url].host).to eq('pubsub.googleapis.com')
|
||||
[200, {}, '{}']
|
||||
end
|
||||
end
|
||||
request = CLIENT.execute(
|
||||
:api_method => @pubsub.projects.topics.list,
|
||||
:parameters => {'project' => 'projects/12345'},
|
||||
:connection => conn
|
||||
)
|
||||
conn.verify
|
||||
end
|
||||
|
||||
it 'should correctly determine the service root_uri' do
|
||||
expect(@pubsub.root_uri.to_s).to eq('https://pubsub.googleapis.com/')
|
||||
end
|
||||
|
||||
it 'should discover correct method URIs' do
|
||||
list = CLIENT.discovered_method(
|
||||
"pubsub.projects.topics.list", "pubsub", "v1beta2"
|
||||
)
|
||||
expect(list.uri_template.pattern).to eq(
|
||||
"https://pubsub.googleapis.com/v1beta2/{+project}/topics"
|
||||
)
|
||||
|
||||
publish = CLIENT.discovered_method(
|
||||
"pubsub.projects.topics.publish", "pubsub", "v1beta2"
|
||||
)
|
||||
expect(publish.uri_template.pattern).to eq(
|
||||
"https://pubsub.googleapis.com/v1beta2/{+topic}:publish"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue