lib/3scale/client.rb in 3scale_client-2.10.0 vs lib/3scale/client.rb in 3scale_client-2.11.0
- old
+ new
@@ -5,11 +5,11 @@
require '3scale/client/http_client'
require '3scale/client/version'
require '3scale/response'
require '3scale/authorize_response'
-require '3scale/rack_query'
+require '3scale/client/rack_query'
module ThreeScale
Error = Class.new(RuntimeError)
class ServerError < Error
@@ -23,13 +23,13 @@
# Wrapper for 3scale Web Service Management API.
#
# == Example
#
- # client = ThreeScale::Client.new(:provider_key => "your provider key")
+ # client = ThreeScale::Client.new(service_tokens: true)
#
- # response = client.authorize(:app_id => "an app id", :app_key => "a secret key")
+ # response = client.authorize(service_token: 'token', service_id: '123', app_id: 'an app id', app_key: 'a secret key')
#
# if response.success?
# response = client.report(:app_id => "some app id", :usage => {"hits" => 1})
#
# if response.success?
@@ -37,41 +37,47 @@
# else
# # something's wrong.
# end
# end
#
+ # Note: Provider Keys are deprecated in favor of Service Tokens with Service IDs
+ # The next major release of this client will default to use Service Tokens.
+ #
class Client
DEFAULT_HOST = 'su1.3scale.net'
+ DEPRECATION_MSG_PROVIDER_KEY = 'provider keys are deprecated - ' \
+ 'please switch at your earliest convenience to use service tokens'.freeze
+ private_constant :DEPRECATION_MSG_PROVIDER_KEY
DEPRECATION_MSG_OLD_REPORT = 'warning: def report(*transactions) is '\
'deprecated. In next versions, the signature of the report method is '\
'going to be: '\
'def report(transactions: [], service_id: nil).'.freeze
private_constant :DEPRECATION_MSG_OLD_REPORT
EXTENSIONS_HEADER = '3scale-options'.freeze
private_constant :EXTENSIONS_HEADER
def initialize(options)
- if options[:provider_key].nil? || options[:provider_key] =~ /^\s*$/
- raise ArgumentError, 'missing :provider_key'
- end
-
@provider_key = options[:provider_key]
+ @service_tokens = options[:service_tokens]
+ @warn_deprecated = options.fetch(:warn_deprecated, true)
+ generate_creds_params
+
@host = options[:host] ||= DEFAULT_HOST
@http = ThreeScale::Client::HTTPClient.new(options)
end
- attr_reader :provider_key, :host, :http
+ attr_reader :provider_key, :service_tokens, :host, :http
# Authorize and report an application.
# TODO (in the mean time read authorize comments or head over to https://support.3scale.net/reference/activedocs#operation/66 for details
#
def authrep(options)
- path = "/transactions/authrep.xml?provider_key=#{CGI.escape(provider_key)}"
+ path = "/transactions/authrep.xml?#{creds_params(options)}"
options_usage = options.delete :usage
options_log = options.delete :log
extensions = options.delete :extensions
@@ -106,13 +112,13 @@
# Report transaction(s).
#
# == Parameters
#
- # Hash with two fields:
+ # Hash with up to three fields:
#
- # transactions:: It is required. It is an enumerable. Each element is a hash with the fields:
+ # transactions:: Required. Enumerable. Each element is a hash with the fields:
# app_id: ID of the application to report the transaction for. This parameter is
# required.
# usage: Hash of usage values. The keys are metric names and values are
# corresponding numeric values. Example: {'hits' => 1, 'transfer' => 1024}.
# This parameter is required.
@@ -121,12 +127,13 @@
# (if the time is in the UTC), or a string in
# the "YYYY-MM-DD HH:MM:SS ZZZZZ" format, where the ZZZZZ is the time offset
# from the UTC. For example, "US Pacific Time" has offset -0800, "Tokyo"
# has offset +0900. This parameter is optional, and if not provided, equals
# to the current time.
- # service_id:: ID of the service. It is optional. When not specified, the transactions
- # are reported to the default service.
+ # service_id:: ID of the service. It is optional. When not specified, the transactions
+ # are reported to the default service.
+ # service_token:: Token granting access to the specified service ID.
#
# == Return
#
# A Response object with method +success?+ that returns true if the report was successful,
# or false if there was an error. See ThreeScale::Response class for more information.
@@ -152,24 +159,29 @@
# == Note
#
# The signature of this method is a bit complicated because we decided to
# keep backwards compatibility with a previous version of the method:
# def report(*transactions)
- def report(*reports, transactions: [], service_id: nil, extensions: nil, **rest)
+ def report(*reports, transactions: [], service_id: nil, extensions: nil, service_token: nil, **rest)
if (!transactions || transactions.empty?) && rest.empty?
raise ArgumentError, 'no transactions to report'
end
transactions = transactions.concat(reports)
unless rest.empty?
- warn(DEPRECATION_MSG_OLD_REPORT)
+ warn DEPRECATION_MSG_OLD_REPORT if @warn_deprecated
transactions.concat([rest])
end
payload = encode_transactions(transactions)
- payload['provider_key'] = CGI.escape(provider_key)
+ if @service_tokens
+ raise ArgumentError, "service_token or service_id not specified" unless service_token && service_id
+ payload['service_token'] = CGI.escape(service_token)
+ else
+ payload['provider_key'] = CGI.escape(@provider_key)
+ end
payload['service_id'] = CGI.escape(service_id.to_s) if service_id
headers = extensions_to_header extensions if extensions
http_response = @http.post('/transactions.xml', payload, headers: headers)
@@ -187,18 +199,19 @@
#
# == Parameters
#
# Hash with options:
#
- # app_id:: id of the application to authorize. This is required.
- # app_key:: secret key assigned to the application. Required only if application has
- # a key defined.
- # service_id:: id of the service (required if you have more than one service)
- # usage:: predicted usage. It is optional. It is a hash where the keys are metrics
- # and the values their predicted usage.
- # Example: {'hits' => 1, 'my_metric' => 100}
- # extensions:: Optional. Hash of extension keys and values.
+ # service_token:: token granting access to the specified service_id.
+ # app_id:: id of the application to authorize. This is required.
+ # app_key:: secret key assigned to the application. Required only if application has
+ # a key defined.
+ # service_id:: id of the service (required if you have more than one service)
+ # usage:: predicted usage. It is optional. It is a hash where the keys are metrics
+ # and the values their predicted usage.
+ # Example: {'hits' => 1, 'my_metric' => 100}
+ # extensions:: Optional. Hash of extension keys and values.
#
# == Return
#
# An ThreeScale::AuthorizeResponse object. It's +success?+ method returns true if
# the authorization is successful, false otherwise. It contains additional information
@@ -217,11 +230,12 @@
# # All good. Proceed...
# end
#
def authorize(options)
extensions = options.delete :extensions
- path = "/transactions/authorize.xml" + options_to_params(options, ALL_PARAMS)
+ creds = creds_params(options)
+ path = "/transactions/authorize.xml" + options_to_params(options, ALL_PARAMS) + '&' + creds
headers = extensions_to_header extensions if extensions
http_response = @http.get(path, headers: headers)
case http_response
@@ -238,15 +252,16 @@
#
# == Parameters
#
# Hash with options:
#
- # app_id:: id of the application to authorize. This is required.
- # service_id:: id of the service (required if you have more than one service)
- # usage:: predicted usage. It is optional. It is a hash where the keys are metrics
- # and the values their predicted usage.
- # Example: {'hits' => 1, 'my_metric' => 100}
+ # service_token:: token granting access to the specified service_id.
+ # app_id:: id of the application to authorize. This is required.
+ # service_id:: id of the service (required if you have more than one service)
+ # usage:: predicted usage. It is optional. It is a hash where the keys are metrics
+ # and the values their predicted usage.
+ # Example: {'hits' => 1, 'my_metric' => 100}
#
# == Return
#
# A ThreeScale::AuthorizeResponse object. It's +success?+ method returns true if
# the authorization is successful, false otherwise. It contains additional information
@@ -268,11 +283,12 @@
# # All good. Proceed...
# end
#
def oauth_authorize(options)
extensions = options.delete :extensions
- path = "/transactions/oauth_authorize.xml" + options_to_params(options, OAUTH_PARAMS)
+ creds = creds_params(options)
+ path = "/transactions/oauth_authorize.xml" + options_to_params(options, OAUTH_PARAMS) + '&' + creds
headers = extensions_to_header extensions if extensions
http_response = @http.get(path, headers: headers)
case http_response
@@ -290,11 +306,11 @@
OAUTH_PARAMS = [:app_id, :app_key, :service_id, :redirect_url, :usage]
ALL_PARAMS = [:user_key, :app_id, :app_key, :service_id, :redirect_url, :usage]
REPORT_PARAMS = [:user_key, :app_id, :service_id, :timestamp]
def options_to_params(options, allowed_keys)
- params = { :provider_key => provider_key }
+ params = {}
(allowed_keys - [:usage]).each do |key|
params[key] = options[key] if options.has_key?(key)
end
@@ -394,8 +410,28 @@
end
# Encode extensions header
def extensions_to_header(extensions)
{ EXTENSIONS_HEADER => RackQuery.encode(extensions) }
+ end
+
+ # helper to generate the creds_params method
+ def generate_creds_params
+ define_singleton_method :creds_params,
+ if @service_tokens
+ lambda do |options|
+ token = options.delete(:service_token)
+ service_id = options[:service_id]
+ raise ArgumentError, "need to specify a service_token and a service_id" unless token && service_id
+ 'service_token='.freeze + CGI.escape(token)
+ end
+ elsif @provider_key
+ warn DEPRECATION_MSG_PROVIDER_KEY if @warn_deprecated
+ lambda do |_|
+ "provider_key=#{CGI.escape @provider_key}".freeze
+ end
+ else
+ raise ArgumentError, 'missing credentials - either use "service_tokens: true" or specify a provider_key value'
+ end
end
end
end