class ThreeScale::Client
Wrapper for 3scale Web Service Management API.
Example¶ ↑
client = ThreeScale::Client.new(service_tokens: true) 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? # all fine. 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.
Constants
- ALL_PARAMS
- DEFAULT_HOST
- DEPRECATION_MSG_OLD_REPORT
- DEPRECATION_MSG_PROVIDER_KEY
- EXTENSIONS_HEADER
- OAUTH_PARAMS
- REPORT_PARAMS
- VERSION
Attributes
Public Class Methods
# File lib/3scale/client.rb, line 60 def initialize(options) @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
Public Instance Methods
Authorize and report an application. TODO (in the mean time read authorize comments or head over to support.3scale.net/reference/activedocs#operation/66 for details
# File lib/3scale/client.rb, line 77 def authrep(options) path = "/transactions/authrep.xml?#{creds_params(options)}" options_usage = options.delete :usage options_log = options.delete :log extensions = options.delete :extensions options.each_pair do |param, value| path += "&#{param}=#{CGI.escape(value.to_s)}" end options_usage ||= {:hits => 1} path += "&#{usage_query_params(options_usage)}" if options_log log = [] options_log.each_pair do |key, value| escaped_key = CGI.escape "[log][#{key}]" log << "#{escaped_key}=#{CGI.escape(value)}" end path += "&#{log.join('&')}" end headers = extensions_to_header extensions if extensions http_response = @http.get(path, headers: headers) case http_response when Net::HTTPSuccess,Net::HTTPConflict build_authorize_response(http_response.body) when Net::HTTPClientError build_error_response(http_response.body, AuthorizeResponse) else raise ServerError.new(http_response) end end
Report transaction(s).
Parameters¶ ↑
Hash with up to three 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. timestamp: Timestamp of the transaction. This can be either a object of the ruby's Time class, or a string in the "YYYY-MM-DD HH:MM:SS" format (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_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.
In case of unexpected internal server error, this method raises a ThreeScale::ServerError
exception.
Examples¶ ↑
Report two transactions of two applications. Using the default service. client.report(transactions: [{:app_id => 'foo', :usage => {'hits' => 1}}, {:app_id => 'bar', :usage => {'hits' => 1}}]) Report one transaction with timestamp. Using the default service. client.report(transactions: [{:app_id => 'foo', :timestamp => Time.local(2010, 4, 27, 15, 14), :usage => {'hits' => 1}]) Report a transaction specifying the service. client.report(transactions: [{:app_id => 'foo', :usage => {'hits' => 1}}], service_id: 'a_service_id')
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)
# File lib/3scale/client.rb, line 164 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 if @warn_deprecated transactions.concat([rest]) end payload = encode_transactions(transactions) 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) case http_response when Net::HTTPSuccess build_report_response when Net::HTTPClientError build_error_response(http_response.body) else raise ServerError.new(http_response) end end
Private Instance Methods
# File lib/3scale/client.rb, line 355 def append_value(result, index, names, value) result["transactions[#{index}][#{names.join('][')}]"] = value if value end
# File lib/3scale/client.rb, line 403 def build_error_response(body, klass = Response) doc = Nokogiri::XML(body) node = doc.at_css('error') response = klass.new response.error!(node.content.to_s.strip, node['code'].to_s.strip) response end
# File lib/3scale/client.rb, line 359 def build_report_response response = Response.new response.success! response end
# File lib/3scale/client.rb, line 331 def encode_transactions(transactions) result = {} transactions.each_with_index do |transaction, index| REPORT_PARAMS.each do |param| append_value(result, index, [param], transaction[param]) end transaction[:usage].each do |name, value| append_value(result, index, [:usage, name], value) end transaction.fetch(:log, {}).each do |name, value| append_value(result, index, [:log, name], value) end end result end
Encode extensions header
# File lib/3scale/client.rb, line 413 def extensions_to_header(extensions) { EXTENSIONS_HEADER => RackQuery.encode(extensions) } end
helper to generate the creds_params method
# File lib/3scale/client.rb, line 418 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
# File lib/3scale/client.rb, line 310 def options_to_params(options, allowed_keys) params = {} (allowed_keys - [:usage]).each do |key| params[key] = options[key] if options.has_key?(key) end tuples = params.map do |key, value| "#{key}=#{CGI.escape(value.to_s)}" end res = '?' + tuples.join('&') # Usage is a hash. The format is a bit different if allowed_keys.include?(:usage) && options.has_key?(:usage) res << "&#{usage_query_params(options[:usage])}" end res end
# File lib/3scale/client.rb, line 351 def usage_query_params(usage) URI.encode_www_form(usage.map { |metric, value| ["[usage][#{metric}]", value ] }) end