Git Product home page Git Product logo

google-api-ruby-client's Introduction

Simple REST Clients for Google APIs

This repository contains a set of simple client libraries for various Google APIs. These libraries are generated automatically from Discovery Documents, and the code generator is also hosted here in this repository.

Each client provides:

  • A client object that connects to the HTTP/JSON REST endpoint for the service.
  • Ruby objects for data structures related to the service.
  • Integration with the googleauth gem for authentication using OAuth, API keys, and service accounts.
  • Control of retry, pagination, and timeouts.

These client libraries are officially supported by Google, and are updated regularly to track changes to the service. However, many Google services, especially Google Cloud Platform services such as Cloud Storage, Pub/Sub, and BigQuery, may provide a more modern client that is easier to use and more performant. See the section below titled "Which client should I use?" for more information.

Using the clients

The client gems are named according to the pattern google-apis-<servicename>_<serviceversion>. For example, the client for the Google Drive V3 API is google-apis-drive_v3.

Install the client using gem install or by adding it to your Gemfile. Then, to use it, require the file and instantiate the service. For example to use the Drive API:

require 'google/apis/drive_v3'

drive = Google::Apis::DriveV3::DriveService.new
drive.authorization = ... # See Googleauth or Signet libraries

# 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

# Upload a file
metadata = Google::Apis::DriveV3::File.new(name: 'test.txt')
metadata = drive.create_file(metadata, upload_source: '/tmp/test.txt', content_type: 'text/plain')

# Download a file
drive.get_file(metadata.id, download_dest: '/tmp/downloaded-test.txt')

Following is another example using the Content API (Google Merchant Center), provided by the google-apis-content_v2_1 gem:

require 'google/apis/content_v2_1'
require 'googleauth' # https://github.com/googleapis/google-auth-library-ruby

content = Google::Apis::ContentV2_1::ShoppingContentService.new

scope = 'https://www.googleapis.com/auth/content'
merchant_id = # Merchant ID found on dashboard

content.authorization = Google::Auth::ServiceAccountCredentials.make_creds(
  json_key_io: File.open('./content-api-key.json'),
  scope: scope)

content.authorization.fetch_access_token!
# Service methods: https://rubydoc.info/gems/google-apis-content_v2_1/Google/Apis/ContentV2_1/ShoppingContentService
content.list_datafeeds(merchant_id) # Returns Google::Apis::ContentV2_1::ListDatafeedsResponse

For more detailed information, see the Usage Guide.

Which client should I use?

Google provides two types of Ruby API client libraries: simple REST clients and modern clients.

The libraries in this repo are simple REST clients. These clients connect to HTTP/JSON REST endpoints and are automatically generated from service discovery documents. They support most API functionality, but their class interfaces are sometimes awkward.

Modern clients are produced by a modern code generator, combined with hand-crafted functionality for some services. Most modern clients connect to high-performance gRPC endpoints, although a few are backed by REST services. Modern clients are available for many Google services, especially Cloud Platform services, but do not yet support all the services covered by the simple clients. Most modern clients live in the https://github.com/googleapis/google-cloud-ruby repository.

For most users, we recommend the modern client, if one is available. Compared with simple clients, modern clients are generally much easier to use and more Ruby-like, support more advanced features such as streaming and long-running operations, and often provide much better performance. You may consider using a simple client instead, if a modern client is not yet available for the service you want to use, or if you are not able to use gRPC on your infrastructure.

The documentation for the particular Google service you are working with, may provide guidance regarding the preferred client library to use.

Tracing

OpenCensus support with gems is now deprecated. Please migrate to using OpenTelemetry instead. Currently instrumented span data from core gem can be got by enabling Http and HttpClient auto-instrumentation of OpenTelemetry. To enable instrumentation for HTTP and HttpClient, and export it to Cloud Trace configure OpenTelemetry like below,

 gem "opentelemetry-sdk"
 gem "opentelemetry-exporter-google_cloud_trace"
 gem "opentelemetry-instrumentation-http"
 gem "opentelemetry-instrumentation-http_client"
 
 require "opentelemetry-sdk"
 require "opentelemetry/instrumentation/http_client"
 require "opentelemetry/instrumentation/http"
 require "opentelemetry/exporter/google_cloud_trace"
 OpenTelemetry::SDK.configure do |c|
   c.service_name = "ServiceName"
   c.add_span_processor(
     OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
       OpenTelemetry::Exporter::GoogleCloudTrace::SpanExporter.new
     )
   )
   c.use "OpenTelemetry::Instrumentation::Http"
   c.use "OpenTelemetry::Instrumentation::HttpClient"
 end

Samples

See the samples for examples on how to use the client library for various services.

Supported Ruby versions

This library is supported on Ruby 2.7+.

Google provides official support for Ruby versions that are actively supported by Ruby Core -- that is, Ruby versions that are either in normal maintenance or in security maintenance, and not end of life. Currently, this means Ruby 2.7 and later. Older versions of Ruby may still work, but are unsupported and not recommended. See https://www.ruby-lang.org/en/downloads/branches/ for details about the Ruby support schedule.

License

This library is licensed under Apache 2.0. Full license text is available in the LICENSE.

Contributing

See CONTRIBUTING.

Support

Please report bugs at the project on Github. Don't hesitate to ask questions about the client or APIs on StackOverflow.

google-api-ruby-client's People

Contributors

bajajneha27 avatar bantini avatar blowmage avatar dazuma avatar diptanshumittal avatar googleapis-publisher avatar grant avatar joker1007 avatar mattwhisenhunt avatar reklov avatar release-please[bot] avatar renovate-bot avatar saicheems avatar sanemat avatar seuros avatar sgomes avatar shivgautam avatar sporkmonger avatar sqrrrl avatar sunboshan avatar tbetbetbe avatar tcoffee-google avatar theroyaltnetennba avatar thomasdarde avatar tknzk avatar weppos avatar yaauie avatar yoshi-automation avatar yoshi-code-bot avatar ysksn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

google-api-ruby-client's Issues

Batch proccess for YouTube PlaylistItems delete failed!

I provided "id", but it always return the error that "Required parameter: id"

Here is my code

require 'google/api_client'

client = Google::APIClient.new(:application_name => 'YouBoard', :application_version => '1.0')
yt = client.discovered_api('youtube', 'v3')
client.authorization.access_token = 'Some Access Token'

response = client.execute!(
  :api_method => yt.playlist_items.list,
  :parameters => {
    :playlistId => pid,
    :part => 'id'
  }
)

# Get playlist_item's id
ids = response.data.items.collect {|x| x.id}

batch = Google::APIClient::BatchRequest.new() do |result|
  p result.data
end


batch.add(
 :api_method => yt.playlist_items.delete,
 :parameters => {:id => ids[0]}
)

client.execute!(batch)

Here is error

"error"=>{"errors"=>[{
"domain"=>"global", 
"reason"=>"required", 
"message"=>"Required parameter: id", 
"locationType"=>"parameter", 
"location"=>"id"}], "code"=>400, "message"=>"Required parameter: id"}}

insert a Group is giving an error

Hey, First thanks for the gem. Looks like it should work for many of my needs.

I'm having trouble inserting a google group in a background job on my server. This would strictly be a server to server interaction.

Here is what I am doing with a service user account:

require 'google/api_client'
client = Google::APIClient.new
directory = client.discovered_api('admin', 'directory_v1')

key = Google::APIClient::KeyUtils.load_from_pkcs12('test1-privatekey.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/plus.me',
 #  :scope => 'https://www.googleapis.com/auth/admin.directory.group',
  :issuer => '[email protected]',
  :signing_key => key)

client.authorization.fetch_access_token!

result = client.execute(
  :api_method => directory.groups.insert,
  :parameters => {email: '[email protected]'})
result.data

Then I get the following error

@extension_parameters={}, @grant_type=nil, @refresh_token=nil, @issued_at=2013-07-10 17:15:55 -0700, @access_token="ya29.AHES6ZRB24E2mNY4FIQydQx4FbfuCh6DBMjcMuZACLfJrMY", @expires_in=3600>, @body="">, @response=#<Faraday::Response:0x007ff433cd1e58 @env={:method=>:post, :body=>"{\n \"error\": {\n  \"errors\": [\n   {\n    \"domain\": \"global\",\n    \"reason\": \"required\",\n    \"message\": \"Missing required field: group\"\n   }\n  ],\n  \"code\": 400,\n  \"message\": \"Missing required field: group\"\n }\n}\n", :url=>#<URI::HTTPS:0x007ff433d0f9d8 URL:https://www.googleapis.com/admin/directory/v1/groups?email=aaaaadeleteme%40backops.co&group=aaaaadeleteme%40backops.co>, :request_headers=>{"User-Agent"=>"google-api-ruby-client/0.6.4 Mac OS X/10.8.4", "Authorization"=>"Bearer ya29.AHES6ZRB24E2mNY4FIQydQx4FbfuCh6DBMjcMuZACLfJrMY", "Cache-Control"=>"no-store", "Content-Type"=>"application/x-www-form-urlencoded"}, :parallel_manager=>nil, :request=>{:proxy=>nil}, :ssl=>{}, :status=>400, :response_headers=>{"content-type"=>"application/json; charset=UTF-8", "date"=>"Thu, 11 Jul 2013 00:24:56 GMT", "expires"=>"Thu, 11 Jul 2013 00:24:56 GMT", "cache-control"=>"private, max-age=0", "x-content-type-options"=>"nosniff", "x-frame-options"=>"SAMEORIGIN", "x-xss-protection"=>"1; mode=block", "server"=>"GSE", "connection"=>"close"}, :response=>#<Faraday::Response:0x007ff433cd1e58 ...>}, @on_complete_callbacks=[]>>

FYI @necroua

Client Error on discoverd_api call

/Library/Ruby/Gems/1.8/gems/google-api-client-0.6.4/lib/google/api_client.rb:597:in `execute!': Not Found (Google::APIClient::ClientError)

When trying to do:
1. @client = Google::APIClient.new
2. @bigquery = @client.discovered_api('bigquery', 'v3')

Occurs when attempting to execute line 1

Show warning when :params_encoder is set incorrectly.

Once technoweenie/faraday#182 is resolved, we're going to need to handle connections differently.

First, this probably means we need to use Google::APIClient.default_connection instead of Faraday.default_connection since the default value Faraday uses will likely be wrong for our use-case. But we also allow users to supply their own connection objects. Since the majority of time having the wrong setting won't cause problems, I'm inclined to make the condition where :params_encoder is set to Faraday::NestedParamsEncoder just a warning, but it's definitely something we need to check for.

adsense.reports.generate is not allowing multiple values for metric attributes

(Moved from https://code.google.com/p/google-api-ruby-client/issues/detail?id=69)

To reproduce

  1. authenticate via oauth 2
  2. use v1.2 (adsense.reports.generate)
  3. put multiple elements in array for metric attribute

What is the expected output? What do you see instead?
i expect all the metric attributes to appear with data,

instead i see no data at all, here's an example
when i put

'metric' => %w(CLICKS EARNINGS),

i get the following

"{\"kind\":\"adsense#report\",\"totalMatchedRows\":\"0\",\"headers\":[{\"name\":\"CUSTOM_CHANNEL_ID\",\"type\":\"DIMENSION\"}],\"totals\":[\"\"],\"averages\":[\"\"]}"

if i use only 1 element in metric, it works, for instance,

'metric' => %w(CLICKS),

i get the following

"{\"kind\":\"adsense#report\",\"totalMatchedRows\":\"2\",\"headers\":[{\"name\":\"CUSTOM_CHANNEL_ID\",\"type\":\"DIMENSION\"},{\"name\":\"CLICKS\",\"type\":\"METRIC_TALLY\"}],\"rows\":[[\"partner-pub-2227041865223506:1000000001\",\"112\"],[\"partner-pub-2227041865223506:1000000002\",\"89\"]],\"totals\":[\"\",\"201\"],\"averages\":[\"\",\"100\"]}"

im running on Centos 6, using gem 'google-api-client'

Support Gzip Compression

I routinely work with large datasets, especially with GoogleAnalytics, that would benefit from Gzip compression. AFAIK, this is all that needs to be done in order to support it:

  • User-Agent header needs to include the string gzip
  • Accept-Encoding header needs to have value gzip
  • Faraday Middleware needs to be present to decode gzipped responses

My question (and the reason I'm not just submitting a PR) is how this should be exposed; should it be yet-another-option on Google::APIClient#initialize() and be global to the client, or would it make more sense as a flag when making the request itself? I don't know the body of Google APIs well enough to guarantee that all the endpoints would work with Gzip enabled and don't want to add it globally unless that guarantee can be made.

problem with service account auth

hi there I just made a ruby script for try to access to calendar but I'm getting error

the code is

require 'rubygems'
require 'google/api_client'
require 'json'


client = Google::APIClient.new(:application_name => "app name")
key = Google::APIClient::PKCS12.load_key('client.p12', 'notasecret')
service_account = Google::APIClient::JWTAsserter.new(
    '[email protected]',
    'https://www.googleapis.com/auth/calendar',
    key)
client.authorization = service_account.authorize

service = client.discovered_api('calendar', 'v3')


result = client.execute(:api_method => service.calendar_list.get, :parameters => {'calendarId' => '[email protected]'})

and I'm getting

 @extension_parameters={}, @grant_type=nil, @refresh_token=nil, @issued_at=2013-05-13 16:37:11 -0300, @access_token="ya29.AHES6ZQSs7KFtnPVG_KtqVVXSXGo_cViYTuMIlMW36o7-ZrKvA", @expires_in=3600>, @body="">, @response=#<Faraday::Response:0x007ff2c24b1d80 @env={:method=>:get, :body=>"{\n \"error\": {\n  \"errors\": [\n   {\n    \"domain\": \"usageLimits\",\n    \"reason\": \"accessNotConfigured\",\n    \"message\": \"Access Not Configured\"\n   }\n  ],\n  \"code\": 403,\n  \"message\": \"Access Not Configured\"\n }\n}\n", :url=>#<URI::HTTPS:0x007ff2c449ba38 URL:https://www.googleapis.com/calendar/v3/users/me/calendarList/[email protected]>, :request_headers=>{"User-Agent"=>"StartupDigest/0.0.0 google-api-ruby-client/0.6.3 Mac OS X/10.8.3", "Authorization"=>"Bearer ya29.AHES6ZQSs7KFtnPVG_KtqVVXSXGo_cViYTuMIlMW36o7-ZrKvA", "Cache-Control"=>"no-store", "Content-Type"=>"application/x-www-form-urlencoded"}, :parallel_manager=>nil, :request=>{:proxy=>nil}, :ssl=>{}, :status=>403, :response_headers=>{"content-type"=>"application/json; charset=UTF-8", "date"=>"Mon, 13 May 2013 19:54:21 GMT", "expires"=>"Mon, 13 May 2013 19:54:21 GMT", "cache-control"=>"private, max-age=0", "x-content-type-options"=>"nosniff", "x-frame-options"=>"SAMEORIGIN", "x-xss-protection"=>"1; mode=block", "server"=>"GSE", "connection"=>"close"}, :response=>#<Faraday::Response:0x007ff2c24b1d80 ...>}, @on_complete_callbacks=[]>>

any idea?

Consider dropping sudo from "sudo gem install" in example

sudo gem install is harmful in a lot of setups.

  • You end up writing root-owned files to userland dirs for any sort of managed Ruby environment (chruby, rvm, rbenv, etc).
  • Related to above, it's a real pain to blow away the gem, or a ruby vm when you've got mixed ownership over the gems directory.
  • Gems can run arbitrary code on the user's machine during install; not great practice to promote that as the default behavior.
  • Depending on the user's setup, sudo may be dropping env vars such as GEM_HOME, placing gems into undesired locations.

etc.

Resumable Upload results in broken pipe

Hi,

I'm trying to use the resumable upload type to upload videos or thumbnails to youtube.


body = {
    :snippet => {
        :title => 'Testvideo Youtube Publisher TEST',
        :description => 'This is a Testvideo
                          Maybe it helps to solve some Problems.
                          DO NOT PUBLISH!',
        :categoryId => '22'
    },
    :status => {
        :privacyStatus => 'private'
    }
}

upload_file = Google::APIClient::UploadIO.new('/home/volker/Videos/youtube_testvideo.mp4', 'video/*')

response = client.execute({:api_method => youtube_service.videos.insert,
                           :body_object => body,
                           :media =>  upload_file,
                           :parameters => {
                               :uploadType => 'resumable',
                               :part => body.keys.join(','),
                               :alt => 'json',
                               :onBehalfOfContentOwner => '<<ContentOwnere>>',
                               :onBehalfOfContentOwnerChannel => '<<ChannelID>>'
                           },
                           :authorization => authorization
                          } )

response.data.id

But I receive an 'broken pipe'.

Trying the same with the upload type 'multipart' works fine.

volker@vz-ubuntu:~/Sites/pro7/yt-publisher$ bundle exec ruby script/yt-explorer/video_create.rb
D, [2013-07-26T13:37:29.209180 #3139] DEBUG -- : Google::APIClient - Initializing client with options {:application_name=>"yt-publisher", :application_version=>"v1"}
D, [2013-07-26T13:37:29.621135 #3139] DEBUG -- : Google::APIClient::Request Sending API request post https://www.googleapis.com/upload/youtube/v3/videos?alt=json&onBehalfOfContentOwner=<<ContentOwner>>&onBehalfOfContentOwnerChannel=UClj4mQAsWEr3PBJPjl14jrg&part=snippet%2Cstatus&uploadType=resumable {"User-Agent"=>"yt-publisher/v1 google-api-ruby-client/0.7.0 Linux/3.8.0-26-generic", "X-Upload-Content-Type"=>"video/*", "X-Upload-Content-Length"=>"292062370", "Content-Type"=>"application/json", "Authorization"=>"Bearer <<Bearer Code >>", "Cache-Control"=>"no-store"}
D, [2013-07-26T13:37:30.230329 #3139] DEBUG -- : Google::APIClient::Request Result: 200 {"location"=>"https://www.googleapis.com/upload/youtube/v3/videos?alt=json&onBehalfOfContentOwner=<<ContentOwner>>&onBehalfOfContentOwnerChannel=UClj4mQAsWEr3PBJPjl14jrg&part=snippet%2Cstatus&uploadType=resumable&upload_id=AEnB2UoO3NPbUzEud1SIgFIcAZ4X40r5d28y0zPGwRk0YEQdQanXu8C5JB7Z4tHJh5zt1uAqzf9SMxxhqubaxPo8KN5yi1cx_g", "date"=>"Fri, 26 Jul 2013 11:37:30 GMT", "server"=>"HTTP Upload Server Built on Jul 21 2013 19:20:38 (1374459638)", "content-length"=>"0", "content-type"=>"text/html; charset=UTF-8", "connection"=>"close"}
D, [2013-07-26T13:37:30.231483 #3139] DEBUG -- : Google::APIClient::Request Sending upload body
D, [2013-07-26T13:37:30.233920 #3139] DEBUG -- : Google::APIClient::ResumableUpload Sending API request post https://www.googleapis.com/upload/youtube/v3/videos?alt=json&onBehalfOfContentOwner=<<ContentOwner>>&onBehalfOfContentOwnerChannel=UClj4mQAsWEr3PBJPjl14jrg&part=snippet%2Cstatus&uploadType=resumable&upload_id=AEnB2UoO3NPbUzEud1SIgFIcAZ4X40r5d28y0zPGwRk0YEQdQanXu8C5JB7Z4tHJh5zt1uAqzf9SMxxhqubaxPo8KN5yi1cx_g {"User-Agent"=>"yt-publisher/v1 google-api-ruby-client/0.7.0 Linux/3.8.0-26-generic", "X-Upload-Content-Type"=>"video/*", "X-Upload-Content-Length"=>"292062370", "Content-Type"=>"video/*", "Content-Length"=>"292062370", "Content-Range"=>"bytes 0-292062369/292062370", "Authorization"=>"Bearer <<Bearer Code >>", "Cache-Control"=>"no-store"}
/home/volker/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/openssl/buffering.rb:318:in `syswrite': Broken pipe (Errno::EPIPE)
    from /home/volker/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/openssl/buffering.rb:318:in `do_write'
    from /home/volker/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/openssl/buffering.rb:336:in `write'
    from /home/volker/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http/generic_request.rb:202:in `copy_stream'
    from /home/volker/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http/generic_request.rb:202:in `send_request_with_body_stream'
    from /home/volker/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http/generic_request.rb:132:in `exec'
    from /home/volker/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http.rb:1404:in `block in transport_request'
    from /home/volker/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http.rb:1403:in `catch'
    from /home/volker/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http.rb:1403:in `transport_request'
    from /home/volker/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http.rb:1376:in `request'
    from /home/volker/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http.rb:1369:in `block in request'
    from /home/volker/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http.rb:852:in `start'
    from /home/volker/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http.rb:1367:in `request'
    from /home/volker/.rvm/gems/ruby-2.0.0-p247/gems/faraday-0.9.0.rc5/lib/faraday/adapter/net_http.rb:75:in `perform_request'
    from /home/volker/.rvm/gems/ruby-2.0.0-p247/gems/faraday-0.9.0.rc5/lib/faraday/adapter/net_http.rb:38:in `call'
    from /home/volker/Sites/sources/google-api-ruby-client/lib/google/api_client/request.rb:165:in `send'
    from /home/volker/Sites/sources/google-api-ruby-client/lib/google/api_client/request.rb:176:in `send'
    from /home/volker/Sites/sources/google-api-ruby-client/lib/google/api_client.rb:578:in `execute'
    from script/yt-explorer/video_create.rb:32:in `<main>'

Faraday Timout while uploading file

I've been trying using the library in v.0.6.1 through v.0.6.4 to upload a file to our enabled youtube account. Accessing the video lists does work, however when uploading I encounter a `rescue in rbuf_fill': Net::ReadTimeout (Faraday::Error::TimeoutError) (see below code). Any help on this would be highly appreciated.

As you can see below, I am using v.0.6.4 of your gem with ruby-2.0.0-p195, however it's been tested with ruby-1.9.3-p392 and v.0.6.1 through v.0.6.4 as well.

I am using the example from the youtube api v3 example pages:

    #!/usr/bin/ruby

    require 'rubygems'
    require 'google/api_client'


    # A limited OAuth 2 access scope that allows for uploading files, but not other
    # types of account access.
    YOUTUBE_API_SERVICE_NAME = 'youtube'
    YOUTUBE_API_VERSION = 'v3'


    service_account_email = '[email protected]' # Email of service account
    key_file_path = 'config/keys/privatekey.p12' # File containing private key
    key_secret = 'notasecret' # Password to unlock private key

    client = Google::APIClient.new(:application_name => $0, :application_version => '1.0')
    youtube = client.discovered_api(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION)

    key = Google::APIClient::KeyUtils.load_from_pkcs12(key_file_path, key_secret)
    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/youtube',
      :issuer => service_account_email,
      :signing_key => key)


    client.authorization.fetch_access_token!
    puts "authorization ok"

    body = {
      :snippet => {
        :title => 'movie',
        :description => 'description',
        :tags => 'movie, test, video',
        :categoryId => 22,
      },
      :status => {
        :privacyStatus => 'private'
      }
    }

    puts 'proceeding to upload'

    file = Google::APIClient::UploadIO.new('/Users/mcb/movie.mp4', 'video/*')
    puts "Loaded file: #{file.inspect}"

    videos_insert_response = client.execute!(
      :api_method => youtube.videos.insert,
      :body_object => body,
      :media => file,
      :parameters => {
        'uploadType' => 'multipart',
        :part => body.keys.join(',')
      }
    )

    puts "'#{videos_insert_response.data.snippet.title}' (video id: #{videos_insert_response.data.id}) was successfully uploaded."

Running this script results in following:

authorization ok
proceeding to upload
Loaded file: #<Google::APIClient::UploadIO:0x007f8e8a3aa2d0 @content_type="video/*", @original_filename="movie.mp4", @local_path="/Users/mcb/movie.mp4", @io=#<File:/Users/mcb/movie.mp4>, @opts={}>
/usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/net/protocol.rb:158:in `rescue in rbuf_fill': Net::ReadTimeout (Faraday::Error::TimeoutError)
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/net/protocol.rb:152:in `rbuf_fill'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/net/protocol.rb:134:in `readuntil'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/net/protocol.rb:144:in `readline'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/net/http/response.rb:39:in `read_status_line'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/net/http/response.rb:28:in `read_new'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/net/http.rb:1406:in `block in transport_request'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/net/http.rb:1403:in `catch'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/net/http.rb:1403:in `transport_request'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/net/http.rb:1376:in `request'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/net/http.rb:1369:in `block in request'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/net/http.rb:852:in `start'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/net/http.rb:1367:in `request'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/gems/2.0.0/gems/faraday-0.8.7/lib/faraday/adapter/net_http.rb:75:in `perform_request'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/gems/2.0.0/gems/faraday-0.8.7/lib/faraday/adapter/net_http.rb:38:in `call'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/gems/2.0.0/gems/faraday-0.8.7/lib/faraday/request/url_encoded.rb:14:in `call'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/gems/2.0.0/gems/google-api-client-0.6.4/lib/google/api_client/request.rb:159:in `send'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/gems/2.0.0/gems/google-api-client-0.6.4/lib/google/api_client.rb:568:in `execute'
  from /usr/local/var/rbenv/versions/2.0.0-p195/lib/ruby/gems/2.0.0/gems/google-api-client-0.6.4/lib/google/api_client.rb:583:in `execute!'
  from script/upload_test.rb:49:in `<main>'

The issue might be related to #57, however if you feel this would be a duplicate, please free to delete one of these. Thanks!

Google Analytics API: filter with AND is impossible

(From https://code.google.com/p/google-api-ruby-client/issues/detail?id=57)

What steps will reproduce the problem?

  1. @client = Google::APIClient.new (then -> authorize)
  2. parameters={"ids"=>"ga:XXXXX", "start-date"=>"2011-07-30", "end-date"=>"2012-08-30", "metrics"=>"ga:visits", "filters"=>"ga:medium=~cpa|cpc|cpm|cpp|cpv|ppc;ga:source==google"}
  3. reference = Google::APIClient::Reference.new(:api_method => analytics.data.ga.get(), :parameters => parameters)
  4. request = @client.generate_request(reference)
  5. you will see that in request object, the 'filters' parameter is split in 2:
    "filters"=>"ga:medium=~cpa|cpc|cpm|cpp|cpv|ppc", "ga:source"=>"=google"

What is the expected output?

"filters"=>"ga:medium=~cpa|cpc|cpm|cpp|cpv|ppc;ga:source==google"

What do you see instead?

"filters"=>"ga:medium=~cpa|cpc|cpm|cpp|cpv|ppc", "ga:source"=>"=google"

What version of the product are you using? On what operating system?

  • Google Analytics Core reporting API V3
  • ruby 1.9.3
  • google-api-ruby-client : hedge (git)

The problem comes from Faraday (or Google Analytics Core reporting API V3 syntax for filters) ๐Ÿ‘

  1. in Faraday::Utils, DEFAULT_SEP = /[&;] */n
  2. so the method ''parse_nested_query" splits the part
    "&filters=ga:medium=~cpa|cpc|cpm|cpp|cpv|ppc;ga:source==google" in {"filters" => "ga:medium=~cpa|cpc|cpm|cpp|cpv|ppc", "ga:source" => "=google"}

One solution would be to open Faraday and edit DEFAULT_SEP (remove the ';'): DEFAULT_SEP = /[&] */n
How can we deal with this ?

Aug 31, 2012
I really need to have a chat with the rest of the Ruby community on how to process URIs.

Mar 18, 2013
I'd like to do what I can to make the appropriate change happen in Faraday. A few questions:

  1. Is there an issue open in Faraday to reflect that this problem is happening?
  2. Is it a typo in the URL that the URL includes "ga:source==google"? Should that just be a single equals? That is, is "=google" the value of the "ga:source" parameter, or is it "google"?

authorization failed - "invalid_grant" error

this was not happening a day ago until perhaps ruby version was upgraded..

DEPRECATION WARNING: The InstanceMethods module inside ActiveSupport::Concern will be no longer included automatically. Please define instance methods directly in Rails::Railtie::Configurable instead. (called from require at /home/ubuntu/weddingwire_bi_salesforce/lib/tasks/google_analytics.rake:4)
** Invoke get_last7days (first_time)
** Invoke environment (first_time)
** Execute get_last7days
rake aborted!
Authorization failed. Server message:
{
"error" : "invalid_grant"
}
/usr/local/ruby/lib/ruby/gems/1.9.1/gems/signet-0.4.5/lib/signet/oauth_2/client.rb:875:in fetch_access_token' /usr/local/ruby/lib/ruby/gems/1.9.1/gems/signet-0.4.5/lib/signet/oauth_2/client.rb:888:infetch_access_token!'
/home/ubuntu/weddingwire_bi_salesforce/lib/tasks/google_analytics.rake:42:in get_abandoned_carts' /home/ubuntu/weddingwire_bi_salesforce/lib/tasks/google_analytics.rake:17:inblock in <top (required)>'
/usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:228:in call' /usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:228:inblock in execute'
/usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:223:in each' /usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:223:inexecute'
/usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:166:in block in invoke_with_call_chain' /usr/local/ruby/lib/ruby/1.9.1/monitor.rb:211:inmon_synchronize'
/usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:159:in invoke_with_call_chain' /usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:152:ininvoke'
/usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:143:in invoke_task' /usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:101:inblock (2 levels) in top_level'
/usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:101:in each' /usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:101:inblock in top_level'
/usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:110:in run_with_threads' /usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:95:intop_level'
/usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:73:in block in run' /usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:160:instandard_exception_handling'
/usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:70:in run' /usr/local/ruby/lib/ruby/gems/1.9.1/gems/rake-10.0.3/bin/rake:33:in<top (required)>'
/usr/local/ruby/bin/rake:23:in load' /usr/local/ruby/bin/rake:23:in

'
Tasks: TOP => get_last7days


not sure why this error came to be - credentials are good.

wrong handling of byte format for string field

It appears that string field with byte format are not handled propertly, when getting back the following field from the response a datastore API call (beginTransaction)

"transaction": {
 "type": "string",
 "description": "The transaction identifier (always present).",
 "format": "byte"
}

And trying to set it in a request field of another datastore API call (lookup/readOptions):

"transaction": {
 "type": "string",
 "description": "The transaction to use. Optional.",
 "format": "byte"
}

I get the following error:

/usr/local/google/home/proppy/.rvm/gems/ruby-2.0.0-p195/gems/google-api-client-0.6.4/lib/google/api_client/request.rb:337:in `encode': "\xA1" from ASCII-8BIT to UTF-8 (Encoding::UndefinedConversionError)
        from /usr/local/google/home/proppy/.rvm/gems/ruby-2.0.0-p195/gems/google-api-client-0.6.4/lib/google/api_client/request.rb:337:in `to_json'
        from /usr/local/google/home/proppy/.rvm/gems/ruby-2.0.0-p195/gems/google-api-client-0.6.4/lib/google/api_client/request.rb:337:in `serialize_body'
        from /usr/local/google/home/proppy/.rvm/gems/ruby-2.0.0-p195/gems/google-api-client-0.6.4/lib/google/api_client/request.rb:92:in `initialize'
        from /usr/local/google/home/proppy/.rvm/gems/ruby-2.0.0-p195/gems/google-api-client-0.6.4/lib/google/api_client.rb:491:in `new'
        from /usr/local/google/home/proppy/.rvm/gems/ruby-2.0.0-p195/gems/google-api-client-0.6.4/lib/google/api_client.rb:491:in `generate_request'
        from /usr/local/google/home/proppy/.rvm/gems/ruby-2.0.0-p195/gems/google-api-client-0.6.4/lib/google/api_client.rb:553:in `execute'
        from adams.rb:62:in `<main>'

The following hack workaround the issue:

transaction = JSON.parse(resp.data.to_json)[:transaction]

Here is a test case that reproduce it:

require 'rubygems'
require 'json'
require 'google/api_client'
if ARGV.empty?
  abort "usage: test.rb <dataset-id>"
end
client = Google::APIClient.new
datastore = client.discovered_api('datastore', 'v1beta1')
dataset_id = ARGV[0]
service_account = ENV['DATASTORE_SERVICE_ACCOUNT']
private_key_file = ENV['DATASTORE_PRIVATE_KEY_FILE']
private_key = Google::APIClient::KeyUtils.load_from_pkcs12(private_key_file,
                                                           '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/datastore',
             'https://www.googleapis.com/auth/userinfo.email'],
  :issuer => service_account,
  :signing_key => private_key)
client.authorization.fetch_access_token!
resp = client.execute(:api_method => datastore.datasets.begin_transaction,
                      :parameters => {:datasetId => dataset_id},
                      :headers => {'content-type' => 'application/json'})
transaction = resp.data.transaction
# workaround                                                                                                                                                                                                                                                                             
#transaction = JSON.parse(resp.data.to_json)[:transaction]                                                                                                                                                                                                                               
resp = client.execute(:api_method => datastore.datasets.lookup,
                      :parameters => {:datasetId => dataset_id},
                      :body_object => {
                        :readOptions => {:transaction => transaction}
                      })
puts resp.data.inspect

Suggest to refactor gemspec management to latest, more conventional bundler-based approach

gemspec is currently managed in a very unconventional manner, and I haven't found any particular reason (yet) why it should stay this way.

i.e. Rakefile defines gem-related constants |> custom rake gem task generates gemspec |> gemspec used to build gem

While in the past, not to bad compared to hoe, jeweler, etc variations, but I think nowdays everyone is just preferring to keep it simpler it all just built into the gemspec (as per the gemspec templates bundler can produce)

Provide a refresh_token command line option

I am looking to see if I can use google-api-ruby-client to provide oauth2 support for a CLI application (that talks to gmail via IMAP) instead of needing the python oauth2.py script to generate keys and refresh tokens.

I figured out how to do this using the API, however I find the google-api command-line mode quite deficient an unsuited to this usage.

One usage that is required when stringing together command-line utilities is the ability to request a new access token given an existing client-id+client-secret+refresh-token. Although you can do this in the API, it seems not from the command line.

Is there any reason why this shouldn't be a command-line facility? If not, I'm quite prepared to submit a pull request with it added.

The check for authorization expired does not seem to work

In the google docs, https://developers.google.com/google-apps/calendar/instantiate , there is this part:

if client.authorization.refresh_token && client.authorization.expired?
  client.authorization.fetch_access_token!
end

For a no longer valid access token, expired? returns false, and subsequent calls to the API, return code 401. Currently, my workaround is the following:

  • do a list on one of my calendars
  • if the status_code is 200, token is still good, we don't need to call client.authorization.fetch_access_token!
  • if the status_code is different, we call fetch_access_token!

undefined method `query_values' for nil:NilClass

Sometimes I get following error for resumable upload:

undefined method query_values' for nil:NilClass /bundle/ruby/1.9.1/gems/google-api-client-0.6.2/lib/google/api_client/request.rb:143:inuri='
/bundle/ruby/1.9.1/gems/google-api-client-0.6.2/lib/google/api_client/media.rb:49:in initialize' /bundle/ruby/1.9.1/gems/google-api-client-0.6.2/lib/google/api_client/result.rb:61:innew'
/bundle/ruby/1.9.1/gems/google-api-client-0.6.2/lib/google/api_client/result.rb:61:in resumable_upload' /bundle/ruby/1.9.1/gems/google-api-client-0.6.2/lib/google/api_client/request.rb:167:insend'
/bundle/ruby/1.9.1/gems/google-api-client-0.6.2/lib/google/api_client.rb:563:in execute' /bundle/ruby/1.9.1/gems/google-api-client-0.6.2/lib/google/api_client.rb:583:inexecute!'

It seems problem comes from resumable session initializing. By some reasons, server didn't send url for upload in response(headers['location'] is nil).
It would be good to add a special check for resumable session Initializing. And if something went wrong client could retry this step.

trainedmodels.insert gets "Model name is empty." error

I tried in the API Explorer on trainedmodels.insert passing id, storageDataLocation and modelType and it works. However, on the ruby client, I got error 400 saying "Model name is empty." I setup pretty much the same as in the README, I can execute trainedmodels.list successfully. Here's my code

prediction = client.discovered_api(:prediction, 'v1.5')
result = client.execute(
  api_method: prediction.trainedmodels.insert,
  id: 'SiteArticleCategorization',
  parameters: {'storageDataLocation' => storage_path, 'modelType' => 'classification'}
)

result.error_message
# => "Model name is empty."

This is my first time using the library, please let me know what other information I should provide to check this issue. Thank you.

Invalid Gemspec: Gemfile.lock in both .gitignore and specification.files

Warning output when bundle-installing a project that relies on this:

Using google-api-client (0.5.0) from [email protected]:google/google-api-ruby-client.git (at master 0b31876250ed4064425d5713097522815abe54d2) 
google-api-client at /Users/yaauie/.rvm/gems/ruby-1.9.3-p194@redacted-projectname/bundler/gems/google-api-ruby-client-0b31876250ed40 did not have a valid gemspec.
This prevents bundler from installing bins or native extensions, but that may not affect its functionality.
The validation message from Rubygems was:
  ["Gemfile.lock"] are not files

Can't Access Directory API using 2lo

After following all the instructions for accessing the Directory API from Googles documentation, Google::APIClient is unable to fetch from this API. The following code causes the API to return the error "Invalid Credentials" even though it should work:

def self.get_user2(email)
@client = Google::APIClient.new(:authorization => :two_legged_oauth_1)
@client.authorization.client_credential_key = GOOGLE_APP_KEY
@client.authorization.client_credential_secret = GOOGLE_APP_SECRET
@Directory = @client.discovered_api('admin', 'directory_v1')
result = @client.execute(
@directory.users.get,
'userKey' => email,
:key => GOOGLE_API_KEY
)
JSON.parse(result.body)
end

Debugging the connection I get the output:

get https://www.googleapis.com/admin/directory/v1/users/[email protected]?key=AIzaSyAHYBWlC_qiihRtTKTZleZlAw2ts8Q1WO8
User-Agent: "google-api-ruby-client/0.6.4 Mac OS X/10.8.4"
Authorization: "OAuth oauth_consumer_key="76548528623.apps.googleusercontent.com", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1375899810", oauth_nonce="de4d976eed6883a06b3f6084e3dd0db4", oauth_version="1.0", oauth_signature="3D7aqhBeaCYOYyaF8bWpaM9MA8U%3D""
Cache-Control: "no-store"
Content-Type: "application/x-www-form-urlencoded"
401
www-authenticate: "AuthSub realm="https://www.google.com/accounts/AuthSubRequest\""
content-type: "application/json; charset=UTF-8"
date: "Wed, 07 Aug 2013 18:23:30 GMT"
expires: "Wed, 07 Aug 2013 18:23:30 GMT"
cache-control: "private, max-age=0"
x-content-type-options: "nosniff"
x-frame-options: "SAMEORIGIN"
x-xss-protection: "1; mode=block"
server: "GSE"
connection: "close"

Not sure what is going wrong here but this should work according to the Google documentation for this API.

example of how to paginate would be nice

Finally figured it out but wasn't obvious at first, and a bit surprised it wasn't in the docs.

For others curious, if your first request looks like this:

result = make_request( api_method: api_method, parameters: {'role' => 'publishers', 'roleId' => 'ROLE_ID_HERE', 'maxResults' => 100} )

the second will be:

result = make_request result.next_page.to_hash

When providing parameters to execute(), + is replaced by space

(From https://code.google.com/p/google-api-ruby-client/issues/detail?id=56)

Call execute() using google-api-ruby-client version 0.4.5:

result = @client.execute(
   api_method: @calendar.events.list,
   parameters: {
      calendarId: calendar_id,
      timeMax: "2012-08-29T00:00:00+02:00",
      timeMin: "2012-08-28T00:00:00+02:00"
   })

timeMax & timeMin parameters are replaced internally by:
2012-08-29T00:00:00 02:00

which then is encoded to 2012-07-29T00%3A00%3A00+02%3A00

The end result is a bad request because Google Calendar API wants 2012-07-29T00%3A00%3A00%2B02%3A00

After some debugging, it appears that Faraday 0.8.4 does this :

# File faraday/utils.rb 

# Adapted from Rack
def parse_query(qs)
  params = {}

  (qs || '').split(DEFAULT_SEP).each do |p|
    k, v = p.split('=', 2).map { |x| unescape(x) }        <---------

    if cur = params[k]
      if cur.class == Array then params[k] << v
      else params[k] = [cur, v]
      end
    else
      params[k] = v
    end
  end
  params
end

unescape() method is from file cgi/util.rb from Ruby stdlib:

# File cgi/util.rb

# URL-decode a string with encoding(optional).
#   string = CGI::unescape("%27Stop%21%27+said+Fred")
#      # => "'Stop!' said Fred"
def CGI::unescape(string,encoding=@@accept_charset)
  str=string.tr('+', ' ').force_encoding(Encoding::ASCII_8BIT).gsub(/((?:%[0-9a-fA-F]{2})+)/) do
    [$1.delete('%')].pack('H*')
  end.force_encoding(encoding)
  str.valid_encoding? ? str : str.force_encoding(string.encoding)
end

As you see unescape replaces '+' by ' ' (space) and this causes the issue.

parse_query() from Faraday is being called by api_client/discovery/method.rb generate_request()

  # File api_client/discovery/method.rb
  def generate_request(parameters={}, body='', headers=[], options={})
    options[:connection] ||= Faraday.default_connection
    if body.respond_to?(:string)
      body = body.string
    elsif body.respond_to?(:to_str)
      body = body.to_str
    else
      raise TypeError, "Expected String or StringIO, got #{body.class}."
    end
    if !headers.kind_of?(Array) && !headers.kind_of?(Hash)
      raise TypeError, "Expected Hash or Array, got #{headers.class}."
    end
    method = self.http_method
    uri = self.generate_uri(parameters)
    headers = headers.to_a if headers.kind_of?(Hash)
    return options[:connection].build_request(
      method.to_s.downcase.to_sym
    ) do |req|
      req.url(Addressable::URI.parse(uri).normalize.to_s)
      req.url(uri.to_s)        <---------
      req.headers = Faraday::Utils::Headers.new(headers)
      req.body = body
    end
  end

Aug 30, 2012
Oupsss

Inside generate_request(), you should ignore req.url(uri.to_s), it's me trying to understand what was going on :)
The line that calls Faraday and then unescape() is
req.url(Addressable::URI.parse(uri).normalize.to_s)

Aug 30, 2012
I don't think it is a bug. + sign should probably not be inside an url.
The solution here is not to pass the local time (+02:00) but the UTC time instead:

  result = @client.execute(
    api_method: @calendar.events.list,
    parameters: {
      calendarId: calendar_id,
      timeMin: time_min.utc.iso8601,
      timeMax: time_max.utc.iso8601
    })

timeMin and timeMax are now:
"2012-07-28T22:00:00Z"
so no more + sign.

Aug 31, 2012
I'm in complete agreement that avoiding the '+' character is a best practice. However, I still consider this a bug. Unfortunately, it's not one that's likely to be fixed soon. Way too many dependencies involved in this issue. That said, Faraday may end up exposing a mechanism by which handling parameters could be delegated to something else.

https://github.com/technoweenie/faraday/issues/182

Dec 11, 2012
I'm having a similar issue, but haven't been able to resolve it by using .utc.iso6801.

I'm calling:

@result = client.execute({
            api_method: service.freebusy.query,
            parameters: { 
              timeMin: Time.now.utc.iso8601,
              timeMax: 3.days.from_now.utc.iso8601,
              items: [{id: "#{@calendar.calendar_id}"}]
            },
            headers: {'Content-Type' => 'application/json'}
})

I'm getting back a 400, "Missing timeMin parameter" error. Am I missing something else with how I need to submit these params?

Dec 12, 2012
Finally got this working and the fix was non-intuitive for me:

@result = client.execute({
    api_method: service.freebusy.query,
    body: JSON.dump({
        timeMin: Time.now.utc.iso8601,
        timeMax: 3.days.from_now.utc.iso8601,
        items: [{id: "#{@calendar.calendar_id}"}]
    },
    headers: {'Content-Type' => 'application/json'}
})

Basically, when timeMin was sent in the parameters field, it wasn't interpreted correctly, but when sent in the body, it was.

Better support for media downloads

Add better support for simplifying download of media/blobs for APIs that support it. Specifically for cloud storage, eventually Drive & other APIs with blob content.

Follow redirects correctly

(From https://code.google.com/p/google-api-ruby-client/issues/detail?id=66)

What steps will reproduce the problem?

  1. Make a call to a Google API which requires a redirect.

What is the expected output? What do you see instead?
Expected output: redirect followed
What did I see: redirect not followed

What version of the product are you using? On what operating system?
Latest version of google-api-ruby-client on a gubuntu box (Ubuntu 12.04.1), ruby 1.9.3

Client hangs (and then timeouts) when request has multipart upload and access token is expired

Seen this with drive.files.insert, but may not be specific.
I had code like:

drive = @client.discovered_api('drive', 'v2')
media = Google::APIClient::UploadIO.new(@asset.attachment.path, 'video/mp4')
metadata = { :title => File.basename(@asset.attachment.path) }
response = @client.execute(:api_method => drive.files.insert,
                           :parameters => { 'uploadType' => 'multipart' },
                           :body_object => metadata,
                           :media => media)

(very similar to the examples!) which worked for an hour after obtaining access and refresh tokens; that is until the access token was valid, and then stopped (by hanging and then timing out after about one minute). Doing some low level socket sniffing revealed that the client was issuing first request with payload, then being issued 401 in response, doing the new request and then hanging doing nothing just after ssl handshake.

Having read a few days ago about some other user having issues with a Faraday::UploadIO not being in a correct state after being read, my guess is that first time around the Google::APIClient::UploadIO stream gets read, but with automatic request retry (with new tokens) is not properly rewinded.

I managed to avoid the problem by issuing a fictitius read operation before writing (this way the tokens get refreshed correctly)

Sorry, I would like to be able to put that rewind in there myself, but don't have the time because I see your code does resume as well so don't have time to dig around.

Thanks!

How to dump / load discovery documents?

I'm trying to dump a discovery document to a file and load it again.

I found an undocumented _dump method, but loading the file with register_discovery_document fails because the dump also includes the document base.

Bundle SSL root certificates

Bundle & preconfigure trusted root CAs for talking to the google API. Ensure that HTTP requests are properly configure rather than relying on underlying system.

Per-request authentication is ignored

When initializing new request (especially for batch request) with Request#new, we can specify :authorization and :authenticated options.

However in APIClient#execute the authorization object is being overwritten as the APIClient's authorization because the options object is set to an empty Hash.

Usually we can walkaround this problem by specifying API call request to APIClient#execute instead of creating a Request, but for Batch it is not possible.

Batch requests broken for Google Analytics API

What steps will reproduce the problem?

  1. Create Google::APIClient.new (and perform auth...)
  2. Create Google::APIClient::BatchRequest.new
  3. Add a new valid Google Analytics API call to batch request object (i've verified that mine work by using client.execute as usual)
  4. Perform the batch request client.execute(batch)
  5. client.execeute(batch) returns !! #<Errno::EPIPE: Broken pipe>

What is the expected output? What do you see instead?

Expected; Google::APIClient::Result
Result: !! #<Errno::EPIPE: Broken pipe>

What version of the product are you using? On what operating system?

google-api-client v 0.6.2 (ruby gem) (Macintosh; Intel Mac OS X 10_8_3)

Please provide any additional information below.

I've verified that the call im trying to perform is valid and functional using client.execute without batch requests.

STACKTRACE:

Errno::EPIPE - Broken pipe:
  /Users/buren/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/openssl/buffering.rb:318:in `do_write'
  /Users/buren/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/openssl/buffering.rb:336:in `write'
  /Users/buren/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/net/http/generic_request.rb:202:in `send_request_with_body_stream'
  /Users/buren/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/net/http/generic_request.rb:132:in `exec'
  /Users/buren/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/net/http.rb:1403:in `block in transport_request'
  /Users/buren/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/net/http.rb:1402:in `transport_request'
  /Users/buren/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/net/http.rb:1375:in `request'
  /Users/buren/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/net/http.rb:1368:in `block in request'
  /Users/buren/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/net/http.rb:851:in `start'
  /Users/buren/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/net/http.rb:1366:in `request'
  (gem) faraday-0.8.5/lib/faraday/adapter/net_http.rb:75:in `perform_request'
  (gem) faraday-0.8.5/lib/faraday/adapter/net_http.rb:38:in `call'
  (gem) faraday-0.8.5/lib/faraday/request/url_encoded.rb:14:in `call'
  (gem) google-api-client-0.6.2/lib/google/api_client/request.rb:159:in `send'
  (gem) google-api-client-0.6.2/lib/google/api_client.rb:563:in `execute'
  lib/google/tb_analytics.rb:81:in `execute_request'
  app/controllers/participants_controller.rb:360:in `google_analytics_data'
  (gem) actionpack-3.2.13/lib/action_controller/metal/implicit_render.rb:4:in `send_action'
  (gem) actionpack-3.2.13/lib/abstract_controller/base.rb:167:in `process_action'
  (gem) actionpack-3.2.13/lib/action_controller/metal/rendering.rb:10:in `process_action'
  (gem) actionpack-3.2.13/lib/abstract_controller/callbacks.rb:18:in `block in process_action'
  (gem) activesupport-3.2.13/lib/active_support/callbacks.rb:469:in `_run__4205675944270840246__process_action__3704399789718745000__callbacks'
  (gem) activesupport-3.2.13/lib/active_support/callbacks.rb:405:in `__run_callback'
  (gem) activesupport-3.2.13/lib/active_support/callbacks.rb:385:in `_run_process_action_callbacks'
  (gem) activesupport-3.2.13/lib/active_support/callbacks.rb:81:in `run_callbacks'
  (gem) actionpack-3.2.13/lib/abstract_controller/callbacks.rb:17:in `process_action'
  (gem) actionpack-3.2.13/lib/action_controller/metal/rescue.rb:29:in `process_action'
  (gem) actionpack-3.2.13/lib/action_controller/metal/instrumentation.rb:30:in `block in process_action'
  (gem) activesupport-3.2.13/lib/active_support/notifications.rb:123:in `block in instrument'
  (gem) activesupport-3.2.13/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
  (gem) activesupport-3.2.13/lib/active_support/notifications.rb:123:in `instrument'
  (gem) actionpack-3.2.13/lib/action_controller/metal/instrumentation.rb:29:in `process_action'
  (gem) actionpack-3.2.13/lib/action_controller/metal/params_wrapper.rb:207:in `process_action'
  (gem) activerecord-3.2.13/lib/active_record/railties/controller_runtime.rb:18:in `process_action'
  (gem) actionpack-3.2.13/lib/abstract_controller/base.rb:121:in `process'
  (gem) actionpack-3.2.13/lib/abstract_controller/rendering.rb:45:in `process'
  (gem) actionpack-3.2.13/lib/action_controller/metal.rb:203:in `dispatch'
  (gem) actionpack-3.2.13/lib/action_controller/metal/rack_delegation.rb:14:in `dispatch'
  (gem) actionpack-3.2.13/lib/action_controller/metal.rb:246:in `block in action'
  (gem) actionpack-3.2.13/lib/action_dispatch/routing/route_set.rb:73:in `dispatch'
  (gem) actionpack-3.2.13/lib/action_dispatch/routing/route_set.rb:36:in `call'
  (gem) journey-1.0.4/lib/journey/router.rb:68:in `block in call'
  (gem) journey-1.0.4/lib/journey/router.rb:56:in `call'
  (gem) actionpack-3.2.13/lib/action_dispatch/routing/route_set.rb:612:in `call'
  (gem) bullet-4.3.0/lib/bullet/rack.rb:11:in `call'
  (gem) actionpack-3.2.13/lib/action_dispatch/middleware/best_standards_support.rb:17:in `call'
  (gem) rack-1.4.5/lib/rack/etag.rb:23:in `call'
  (gem) rack-1.4.5/lib/rack/conditionalget.rb:25:in `call'
  (gem) actionpack-3.2.13/lib/action_dispatch/middleware/head.rb:14:in `call'
  (gem) actionpack-3.2.13/lib/action_dispatch/middleware/params_parser.rb:21:in `call'
  (gem) actionpack-3.2.13/lib/action_dispatch/middleware/flash.rb:242:in `call'
  (gem) rack-1.4.5/lib/rack/session/abstract/id.rb:210:in `context'
  (gem) rack-1.4.5/lib/rack/session/abstract/id.rb:205:in `call'
  (gem) actionpack-3.2.13/lib/action_dispatch/middleware/cookies.rb:341:in `call'
  (gem) activerecord-3.2.13/lib/active_record/query_cache.rb:64:in `call'
  (gem) activerecord-3.2.13/lib/active_record/connection_adapters/abstract/connection_pool.rb:479:in `call'
  (gem) actionpack-3.2.13/lib/action_dispatch/middleware/callbacks.rb:28:in `block in call'
  (gem) activesupport-3.2.13/lib/active_support/callbacks.rb:405:in `_run__1148351990235291595__call__1004835448436417272__callbacks'
  (gem) activesupport-3.2.13/lib/active_support/callbacks.rb:405:in `__run_callback'
  (gem) activesupport-3.2.13/lib/active_support/callbacks.rb:385:in `_run_call_callbacks'
  (gem) activesupport-3.2.13/lib/active_support/callbacks.rb:81:in `run_callbacks'
  (gem) actionpack-3.2.13/lib/action_dispatch/middleware/callbacks.rb:27:in `call'
  (gem) actionpack-3.2.13/lib/action_dispatch/middleware/remote_ip.rb:31:in `call'
  (gem) better_errors-0.8.0/lib/better_errors/middleware.rb:84:in `protected_app_call'
  (gem) better_errors-0.8.0/lib/better_errors/middleware.rb:79:in `better_errors_call'
  (gem) better_errors-0.8.0/lib/better_errors/middleware.rb:56:in `call'
  (gem) actionpack-3.2.13/lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call'
  (gem) actionpack-3.2.13/lib/action_dispatch/middleware/show_exceptions.rb:56:in `call'
  (gem) railties-3.2.13/lib/rails/rack/logger.rb:32:in `call_app'
  (gem) railties-3.2.13/lib/rails/rack/logger.rb:16:in `block in call'
  (gem) activesupport-3.2.13/lib/active_support/tagged_logging.rb:22:in `tagged'
  (gem) railties-3.2.13/lib/rails/rack/logger.rb:16:in `call'
  (gem) actionpack-3.2.13/lib/action_dispatch/middleware/request_id.rb:22:in `call'
  (gem) rack-1.4.5/lib/rack/methodoverride.rb:21:in `call'
  (gem) rack-1.4.5/lib/rack/runtime.rb:17:in `call'
  (gem) activesupport-3.2.13/lib/active_support/cache/strategy/local_cache.rb:72:in `call'
  (gem) actionpack-3.2.13/lib/action_dispatch/middleware/static.rb:63:in `call'
  (gem) railties-3.2.13/lib/rails/engine.rb:479:in `call'
  (gem) railties-3.2.13/lib/rails/application.rb:223:in `call'
  (gem) rack-1.4.5/lib/rack/content_length.rb:14:in `call'
  (gem) railties-3.2.13/lib/rails/rack/log_tailer.rb:17:in `call'
  (gem) thin-1.5.0/lib/thin/connection.rb:81:in `block in pre_process'
  (gem) thin-1.5.0/lib/thin/connection.rb:79:in `pre_process'
  (gem) thin-1.5.0/lib/thin/connection.rb:54:in `process'
  (gem) thin-1.5.0/lib/thin/connection.rb:39:in `receive_data'
  (gem) eventmachine-1.0.0/lib/eventmachine.rb:187:in `run'
  (gem) thin-1.5.0/lib/thin/backends/base.rb:63:in `start'
  (gem) thin-1.5.0/lib/thin/server.rb:159:in `start'
  (gem) rack-1.4.5/lib/rack/handler/thin.rb:13:in `run'
  (gem) rack-1.4.5/lib/rack/server.rb:268:in `start'
  (gem) railties-3.2.13/lib/rails/commands/server.rb:70:in `start'
  (gem) railties-3.2.13/lib/rails/commands.rb:55:in `block in <top (required)>'
  (gem) railties-3.2.13/lib/rails/commands.rb:50:in `<top (required)>'
  script/rails:6:in `<main>'

Issues with inserting media to Google Drive

I have been trying to follow the Readme's example of uploading new content to Google Drive. However, when following the example code, I am returned a blank document with the name "Untitled" and the mimetype of application/x-www-form-urlencoded. Inspecting the HTTP call, I'm seeing a POST made to http://www.googleapis.com:443/upload/drive/v2/files?convert=true&uploadType=multipart but there is no data being sent with the request. The fact that no post data is being sent would explain why I get a blank document. But why is this happening?

This code is being run inside a Rails 3.2 app, in case that makes any difference.

Here's the relevant snippets of my code:

puts options, file_path

file = @drive.files.insert.request_schema.new(options[:resource])
media = Google::APIClient::UploadIO.new(file_path, options[:resource][:mimeType])

puts file, media

result = @client.execute!({
    :api_method => @drive.files.insert,
    :body_object => file,
    :media => media,
    :parameters => options[:post]
})

Here's the relevant puts statements' output:

puts options

{:post=>
    {:convert=>true, 
     :uploadType=>"multipart"}, 
 :resource=>
    {:description=>"Flashcard template file for the VMS Flash application.",      
     :mimeType=>"application/vnd.openxmlformats-officedocument.presentationml.presentation", 
     :title=>"QBANK TEMPLATE"}
}

puts file_path

"lib/flashcard_template.pptx"

puts file

#<Google::APIClient::Schema::Drive::V2::File:0x3fd69aa68528 DATA:{:description=>"Flashcard template file for the VMS Flash application.", :mimeType=>"application/vnd.openxmlformats-officedocument.presentationml.presentation", :title=>"QBANK TEMPLATE"}>

puts media

#<Google::APIClient::UploadIO:0x007fad354d08e8 @content_type="application/vnd.openxmlformats-officedocument.presentationml.presentation", @original_filename="flashcard_template.pptx", @local_path="lib/flashcard_template.pptx", @io=#<File:lib/flashcard_template.pptx>, @opts={}>

examples for OAuth1 usage?

I understand OAuth1 (specifically 2LO) has been deprecated, but it is still in use by apps on the Google Marketplace. Since the current client still happens to work for OAuth1 even though it is unsupported, why not add some examples for it? It took me quite a while to figure out what was missing for the 2LO to work, until I compared the requests with those from the java client which had more documentation available.

httpi 0.9.6 gem causes downloading issues

Problem was originally reported in AdWords API forum
https://groups.google.com/d/msg/adwords-api/u_PQYo12T1k/NQCm_Hul86YJ

I am adding bonus stack trace here...

msg:#<AdwordsApi::Errors::ReportError: AdwordsApi::Errors::ReportError>
/home/alex/.rvm/gems/jruby-1.6.2@google/gems/google-adwords-api-0.5.0/lib/adwords_api/report_utils.rb:177:in check_for_errors' /home/alex/.rvm/gems/jruby-1.6.2@google/gems/google-adwords-api-0.5.0/lib/adwords_api/report_utils.rb:102:inget_report_response'
/home/alex/.rvm/gems/jruby-1.6.2@google/gems/google-adwords-api-0.5.0/lib/adwords_api/report_utils.rb:54:in download_report' /home/alex/.rvm/gems/jruby-1.6.2@google/gems/google-adwords-api-0.5.0/lib/adwords_api/report_utils.rb:73:indownload_report_as_file'

How to get `google-api oauth-2-login` to echo keys instead of writing to file

I am looking to see if I can use google-api-ruby-client to provide oauth2 support for a CLI application (that talks to gmail via IMAP) instead of needing the python oauth2.py script to generate keys and refresh tokens.

I figured out how to do this using the API, however I find the google-api command-line mode quite deficient an unsuited to this usage.

Firstly, and the subject of this issue, is that the google-api oauth-2-login command does the correct authorisation, however to a user it can appear as if 'nothing happened'.

e.g.

$ google-api oauth-2-login --client-id="my_client_id" --client-secret="my_secret" --scope=https://mail.google.com/

This launches the authorisation page correctly, but simply returns the command prompt with no further information. Unless I had read the docs (and probably the source also), I wouldn't know to look and find that my new credentials have just been saved in "~/.google-api.yaml"

I think this really needs to change on a number of points:

  • it shouldn't persist a new token to ~/.google-api.yaml unless I ask for it
  • when it does save to ~/.google-api.yaml, it should be providing feedback to the user that it just did that
  • if I prefer, I should have a switch/option that simply echoes the new token to the console instead of saving to a file

Are these valid points to try and fix, or have I missed something along the way? If you think these are valid behaviours, I'm quite prepared to submit a pull request for some improvements.

Stack level too deep

Sometimes I getting SystemStackError: 'Stack level too deep' error for resumable_upload
I using following code for resumable_upload:

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)
end

It seems resumable upload went to infinity loop, because of wrong response from server.
Also it is hard to reproduce this error.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.