Skip to content

Commit

Permalink
Drop dependency on Google API Client
Browse files Browse the repository at this point in the history
This commit makes several changes, first, it replaces Google API Client
with custom code using Faraday to call the JSON REST API.
The new code uses the new Translate endpoint, switched to HTTP POST,
and adds support for service accounts in addition to API keys.

[closes #1046, closes #1047, closes #1049]
  • Loading branch information
blowmage committed Nov 12, 2016
1 parent 3371dc8 commit 436116c
Show file tree
Hide file tree
Showing 16 changed files with 648 additions and 225 deletions.
51 changes: 47 additions & 4 deletions google-cloud-translate/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,63 @@ end

# Acceptance tests
desc "Runs the translate acceptance tests."
task :acceptance, :key do |t, args|
task :acceptance, :project, :keyfile, :key do |t, args|
project = args[:project]
project ||= ENV["GCLOUD_TEST_PROJECT"] || ENV["TRANSLATE_TEST_PROJECT"]
keyfile = args[:keyfile]
keyfile ||= ENV["GCLOUD_TEST_KEYFILE"] || ENV["TRANSLATE_TEST_KEYFILE"]
if keyfile
keyfile = File.read keyfile
else
keyfile ||= ENV["GCLOUD_TEST_KEYFILE_JSON"] || ENV["TRANSLATE_TEST_KEYFILE_JSON"]
end
if project.nil? || keyfile.nil?
fail "You must provide a project and keyfile. e.g. rake acceptance[test123, /path/to/keyfile.json] or TRANSLATE_TEST_PROJECT=test123 TRANSLATE_TEST_KEYFILE=/path/to/keyfile.json rake acceptance"
end
key = args[:key]
key ||= ENV["GCLOUD_TEST_KEY"] || ENV["TRANSLATE_TEST_KEY"]
if key.nil?
fail "You must provide a key. e.g. rake acceptance[api_key] or TRANSLATE_TEST_KEY=api_key rake acceptance"

# run tests with api key credentials when available
if key
puts "running acceptance tests with API key"
# Rake::Task["acceptance:key"].invoke key
puts `bundle exec rake acceptance:key[#{key}]`
end

# always run tests with service account credentials
puts "running acceptance tests with service account"

# always overwrite when running tests
ENV["TRANSLATE_KEY"] = key
ENV["TRANSLATE_PROJECT"] = project
ENV["TRANSLATE_KEYFILE"] = nil
ENV["TRANSLATE_KEYFILE_JSON"] = keyfile
ENV["TRANSLATE_KEY"] = nil

$LOAD_PATH.unshift "lib", "acceptance"
Dir.glob("acceptance/**/*_test.rb").each { |file| require_relative file }
end

namespace :acceptance do
task :key, :key do |t, args|
key = args[:key]
key ||= ENV["GCLOUD_TEST_KEY"] || ENV["TRANSLATE_TEST_KEY"]
if key.nil?
fail "unable to run acceptance tests with api key credentials"
end
# always overwrite when running tests
ENV["TRANSLATE_PROJECT"] = nil
ENV["TRANSLATE_KEYFILE"] = nil
ENV["GOOGLE_CLOUD_KEYFILE"] = nil
ENV["GCLOUD_KEYFILE"] = nil
ENV["TRANSLATE_KEYFILE_JSON"] = nil
ENV["GOOGLE_CLOUD_KEYFILE_JSON"] = nil
ENV["GCLOUD_KEYFILE_JSON"] = nil
ENV["TRANSLATE_KEY"] = key

$LOAD_PATH.unshift "lib", "acceptance"
Dir.glob("acceptance/**/*_test.rb").each { |file| require_relative file }
end

desc "Runs acceptance tests with coverage."
task :coverage, :project, :keyfile do |t, args|
require "simplecov"
Expand Down
1 change: 0 additions & 1 deletion google-cloud-translate/google-cloud-translate.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ Gem::Specification.new do |gem|
gem.required_ruby_version = ">= 2.0.0"

gem.add_dependency "google-cloud-core", "~> 0.21.0"
gem.add_dependency "google-api-client", "~> 0.9.11"

gem.add_development_dependency "minitest", "~> 5.9"
gem.add_development_dependency "minitest-autotest", "~> 1.0"
Expand Down
33 changes: 29 additions & 4 deletions google-cloud-translate/lib/google-cloud-translate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ module Cloud
# keys](https://cloud.google.com/translate/v2/using_rest#creating-server-api-keys).
#
# @param [String] key a public API access key (not an OAuth 2.0 token)
# @param [String, Array<String>] scope The OAuth 2.0 scopes controlling the
# set of resources and operations that the connection can access. See
# [Using OAuth 2.0 to Access Google
# APIs](https://developers.google.com/identity/protocols/OAuth2).
#
# The default scope is:
#
# * `https://www.googleapis.com/auth/cloud-platform`
# @param [Integer] retries Number of times to retry requests on server
# error. The default value is `3`. Optional.
# @param [Integer] timeout Default timeout to use in requests. Optional.
Expand All @@ -62,8 +70,10 @@ module Cloud
# translation = translate.translate "Hello world!", to: "la"
# translation.text #=> "Salve mundi!"
#
def translate key = nil, retries: nil, timeout: nil
Google::Cloud.translate key, retries: (retries || @retries),
def translate key = nil, scope: nil, retries: nil, timeout: nil
Google::Cloud.translate key, project: @project, keyfile: @keyfile,
scope: scope,
retries: (retries || @retries),
timeout: (timeout || @timeout)
end

Expand All @@ -80,6 +90,18 @@ def translate key = nil, retries: nil, timeout: nil
# keys](https://cloud.google.com/translate/v2/using_rest#creating-server-api-keys).
#
# @param [String] key a public API access key (not an OAuth 2.0 token)
# @param [String] project Project identifier for the Translate service you
# are connecting to.
# @param [String, Hash] keyfile Keyfile downloaded from Google Cloud. If
# file path the file must be readable.
# @param [String, Array<String>] scope The OAuth 2.0 scopes controlling the
# set of resources and operations that the connection can access. See
# [Using OAuth 2.0 to Access Google
# APIs](https://developers.google.com/identity/protocols/OAuth2).
#
# The default scope is:
#
# * `https://www.googleapis.com/auth/cloud-platform`
# @param [Integer] retries Number of times to retry requests on server
# error. The default value is `3`. Optional.
# @param [Integer] timeout Default timeout to use in requests. Optional.
Expand All @@ -104,9 +126,12 @@ def translate key = nil, retries: nil, timeout: nil
# translation = translate.translate "Hello world!", to: "la"
# translation.text #=> "Salve mundi!"
#
def self.translate key = nil, retries: nil, timeout: nil
def self.translate key = nil, project: nil, keyfile: nil, scope: nil,
retries: nil, timeout: nil
require "google/cloud/translate"
Google::Cloud::Translate.new key: key, retries: retries, timeout: timeout
Google::Cloud::Translate.new key: key, project: project, keyfile: keyfile,
scope: scope, retries: retries,
timeout: timeout
end
end
end
50 changes: 44 additions & 6 deletions google-cloud-translate/lib/google/cloud/translate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,18 @@ module Translate
# the specific instructions for [Server
# keys](https://cloud.google.com/translate/v2/using_rest#creating-server-api-keys).
#
# @param [String] project Project identifier for the Translate service you
# are connecting to.
# @param [String, Hash] keyfile Keyfile downloaded from Google Cloud. If
# file path the file must be readable.
# @param [String, Array<String>] scope The OAuth 2.0 scopes controlling
# the set of resources and operations that the connection can access.
# See [Using OAuth 2.0 to Access Google
# APIs](https://developers.google.com/identity/protocols/OAuth2).
#
# The default scope is:
#
# * `https://www.googleapis.com/auth/cloud-platform`
# @param [String] key a public API access key (not an OAuth 2.0 token)
# @param [Integer] retries Number of times to retry requests on server
# error. The default value is `3`. Optional.
Expand All @@ -229,7 +241,20 @@ module Translate
# @example
# require "google/cloud/translate"
#
# translate = Google::Cloud::Translate.new key: "api-key-abc123XYZ789"
# translate = Google::Cloud::Translate.new(
# project: "my-todo-project",
# keyfile: "/path/to/keyfile.json"
# )
#
# translation = translate.translate "Hello world!", to: "la"
# translation.text #=> "Salve mundi!"
#
# @example Using API Key.
# require "google/cloud/translate"
#
# translate = Google::Cloud::Translate.new(
# key: "api-key-abc123XYZ789"
# )
#
# translation = translate.translate "Hello world!", to: "la"
# translation.text #=> "Salve mundi!"
Expand All @@ -244,17 +269,30 @@ module Translate
# translation = translate.translate "Hello world!", to: "la"
# translation.text #=> "Salve mundi!"
#
def self.new key: nil, retries: nil, timeout: nil
def self.new project: nil, keyfile: nil, scope: nil, key: nil,
retries: nil, timeout: nil
project ||= Google::Cloud::Translate::Api.default_project
project = project.to_s # Always cast to a string

key ||= ENV["TRANSLATE_KEY"]
key ||= ENV["GOOGLE_CLOUD_KEY"]
if key.nil?
key_missing_msg = "An API key is required to use the Translate API."
fail ArgumentError, key_missing_msg
if key
return Google::Cloud::Translate::Api.new(
Google::Cloud::Translate::Service.new(
project, nil, retries: retries, timeout: timeout, key: key))
end

if keyfile.nil?
credentials = Google::Cloud::Translate::Credentials.default(
scope: scope)
else
credentials = Google::Cloud::Translate::Credentials.new(
keyfile, scope: scope)
end

Google::Cloud::Translate::Api.new(
Google::Cloud::Translate::Service.new(
key, retries: retries, timeout: timeout))
project, credentials, retries: retries, timeout: timeout))
end
end
end
Expand Down
29 changes: 28 additions & 1 deletion google-cloud-translate/lib/google/cloud/translate/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.


require "google/cloud/core/environment"
require "google/cloud/translate/service"
require "google/cloud/translate/translation"
require "google/cloud/translate/detection"
Expand Down Expand Up @@ -62,6 +63,32 @@ def initialize service
@service = service
end

##
# The Translate project connected to.
#
# @example
# require "google/cloud/translate"
#
# translate = Google::Cloud::Translate.new(
# project: "my-todo-project",
# keyfile: "/path/to/keyfile.json"
# )
#
# translate.project #=> "my-todo-project"
#
def project
service.project
end

##
# @private Default project.
def self.default_project
ENV["TRANSLATE_PROJECT"] ||
ENV["GOOGLE_CLOUD_PROJECT"] ||
ENV["GCLOUD_PROJECT"] ||
Google::Cloud::Core::Environment.project_id
end

##
# Returns text translations from one language to another.
#
Expand Down Expand Up @@ -227,7 +254,7 @@ def detect *text
def languages language = nil
language = language.to_s if language
gapi = service.languages language
Array(gapi.languages).map { |g| Language.from_gapi g }
Array(gapi["languages"]).map { |g| Language.from_gapi g }
end
end
end
Expand Down
42 changes: 42 additions & 0 deletions google-cloud-translate/lib/google/cloud/translate/credentials.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright 2016 Google Inc. All rights reserved.
#
# 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/cloud/credentials"

module Google
module Cloud
module Translate
##
# @private Represents the OAuth 2.0 signing logic for Translate.
class Credentials < Google::Cloud::Credentials
SCOPE = ["https://www.googleapis.com/auth/cloud-platform"]
PATH_ENV_VARS = %w(TRANSLATE_KEYFILE GOOGLE_CLOUD_KEYFILE
GCLOUD_KEYFILE)
JSON_ENV_VARS = %w(TRANSLATE_KEYFILE_JSON GOOGLE_CLOUD_KEYFILE_JSON
GCLOUD_KEYFILE_JSON)

##
# @private Sign Oauth2 API calls.
def sign_http_request request #:nodoc:
if @client
@client.fetch_access_token! if @client.expires_within? 30
@client.generate_authenticated_request request: request
end
request
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ def language
# @private New Detection from a ListDetectionsResponse object as
# defined by the Google API Client object.
def self.from_gapi gapi, text
res = text.zip(Array(gapi.detections)).map do |txt, detections_gapi|
results = detections_gapi.map { |g| Result.from_gapi g }
res = text.zip(Array(gapi["detections"])).map do |txt, detections|
results = detections.map { |g| Result.from_gapi g }
new txt, results
end
return res.first if res.size == 1
Expand Down Expand Up @@ -130,7 +130,7 @@ def initialize confidence, language
# @private New Detection::Result from a DetectionsResource object as
# defined by the Google API Client object.
def self.from_gapi gapi
new gapi.confidence, gapi.language
new gapi["confidence"], gapi["language"]
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def initialize code, name
# @private New Language from a LanguagesResource object as defined by
# the Google API Client object.
def self.from_gapi gapi
new gapi.language, gapi.name
new gapi["language"], gapi["name"]
end
end
end
Expand Down
Loading

0 comments on commit 436116c

Please sign in to comment.