lib/zuora/client.rb in zuora-ruby-0.2.0 vs lib/zuora/client.rb in zuora-ruby-0.3.0
- old
+ new
@@ -1,139 +1,129 @@
-# encoding: utf-8
require 'faraday'
require 'faraday_middleware'
-require 'json'
+require 'nokogiri'
module Zuora
# Unable to connect. Check username / password
- ConnectionError = Class.new StandardError
+ SoapConnectionError = Class.new StandardError
# Non-success response
- ErrorResponse = Class.new StandardError
+ SoapErrorResponse = Class.new StandardError
class Client
- attr_reader :connection
+ attr_accessor :session_token
+ SOAP_API_URI = '/apps/services/a/74.0'.freeze
+ SESSION_TOKEN_XPATH =
+ %w(//soapenv:Envelope soapenv:Body api:loginResponse
+ api:result api:Session).join('/').freeze
+
# Creates a connection instance.
- # Makes an initial HTTP request to fetch session token.
- # Subsequent requests made with .get, .post, and .put
- # contain the authenticated session id in their headers.
+ # Makes an initial SOAP request to fetch session token.
+ # Subsequent requests contain the authenticated session id
+ # in headers.
# @param [String] username
# @param [String] password
# @param [Boolean] sandbox
- # @return [Zuora::Client] with .connection, .put, .post
- def initialize(username, password, sandbox = false)
- base_url = api_url sandbox
- conn = connection base_url
+ # @return [Zuora::SoapClient]
+ def initialize(username, password, sandbox = true)
+ @username = username
+ @password = password
+ @sandbox = sandbox
+ end
- response = auth_request conn, username, password
+ # Makes auth request, handles response
+ # @return [Faraday::Response]
+ def authenticate!
+ auth_response = call! :login,
+ username: @username,
+ password: @password
- handle_response response, conn
+ handle_auth_response auth_response
+ rescue Object => e
+ raise SoapConnectionError, e
end
- # @param [String] url - URL of request
- # @return [Faraday::Response] A response, with .headers, .status & .body
- def get(url)
- @connection.get do |req|
- set_request_headers! req, url
- end
- end
+ # Fire a request
+ # @param [Xml] body - an object responding to .xml
+ # @return [Zuora::Response]
+ def request!(body)
+ fail 'body must support .to_xml' unless body.respond_to? :to_xml
- # @param [String] url - URL for HTTP POST request
- # @param [Params] params - Data to be sent in request body
- # @return [Faraday::Response] A response, with .headers, .status & .body
- def post(url, params)
- response = @connection.post do |req|
- set_request_headers! req, url
- req.body = JSON.generate params
+ raw_response = connection.post do |request|
+ request.url SOAP_API_URI
+ request.headers['Content-Type'] = 'text/xml'
+ request.body = body.to_xml
end
- response
- # if response.body['success']
- # return response
- # else
- # raise ErrorResponse.new(response)
- # end
+ Zuora::Response.new(raw_response)
end
- # @param [String] url - URL for HTTP PUT request
- # @param [Params] params - Data to be sent in request body
- # @return [Faraday::Response] A response, with .headers, .status & .body
- def put(url, params)
- response = @connection.put do |request|
- set_request_headers! request, url
- request.body = JSON.generate params
- end
-
- response
- # if response.body['success']
- # return response
- # else
- # raise ErrorResponse.new(response)
- # end
+ # The primary interface via which users should make SOAP requests.
+ # client.call :create, object_name: :BillRun, data: {...}
+ # client.call :subscribe, account: {...}, sold_to_contact: {...}
+ # @param [Symbol] call_name - one of :create, :subscribe, :amend, :update
+ # @return [Faraday:Response] - response
+ def call!(call_name, *args)
+ factory = Zuora::Dispatcher.send call_name
+ xml_builder = factory.new(*args).xml_builder
+ request_data = envelope_for call_name, xml_builder
+ request! request_data
end
private
- # Make connection attempt
- # @param [Faraday::Connection] conn
- # @param [String] username
- # @param [String] password
- def auth_request(conn, username, password)
- conn.post do |request|
- set_auth_request_headers! request, username, password
+ # Generate envelope for request
+ # @param [Symbol] call name - one of the supported calls (see #call)
+ # @param [Callable] builder_modifier - function taking a builder
+ # @return [Nokogiri::XML::Builder]
+ def envelope_for(call_name, xml_builder_modifier)
+ if call_name == :login
+ Zuora::Utils::Envelope.xml(nil, xml_builder_modifier)
+ else
+ Zuora::Utils::Envelope.authenticated_xml(@session_token) do |b|
+ xml_builder_modifier.call b
+ end
end
end
- # Sets instance variables or throws Connection error
- # @param [Faraday::Response] response
- # @param [Faraday::Connection] conn
- def handle_response(response, conn)
- if response.status == 200
- @auth_cookie = response.headers['set-cookie'].split(' ')[0]
- @connection = conn
+ # Handle auth response, setting session
+ # @params [Faraday::Response]
+ # @return [Faraday::Response]
+ # @throw [SoapErrorResponse]
+ def handle_auth_response(response)
+ if response.raw.status == 200
+ @session_token = extract_session_token response
else
- fail ConnectionError, response.body['reasons']
+ message = 'Unable to connect with provided credentials'
+ fail SoapErrorResponse, message
end
+ response
end
- # @param [Faraday::Request] request - Faraday::Request builder
- # @param [String] username - Zuora username
- # @param [String] password - Zuora password
- def set_auth_request_headers!(request, username, password)
- request.url '/rest/v1/connections'
- request.headers['apiAccessKeyId'] = username
- request.headers['apiSecretAccessKey'] = password
- request.headers['Content-Type'] = 'application/json'
+ # Extracts session token from response and sets instance variable
+ # for use in subsequent requests
+ # @param [Faraday::Response] response - response to auth request
+ def extract_session_token(response)
+ Nokogiri::XML(response.raw.body).xpath(
+ SESSION_TOKEN_XPATH, Zuora::NAMESPACES
+ ).text
end
- # @param [Faraday::Request] request - Faraday Request builder
- # @param [String] url - Relative URL for HTTP request
- # @return [Nil]
- def set_request_headers!(request, url)
- request.url url
- request.headers['Content-Type'] = 'application/json'
- request.headers['Cookie'] = @auth_cookie
- end
-
- # @param [String] url
- # @return [Faraday::Client]
- def connection(url)
- Faraday.new(url, ssl: { verify: false }) do |conn|
- conn.request :json
- conn.response :json, content_type: /\bjson$/
- conn.use :instrumentation
+ # Initializes a connection using api_url
+ # @return [Faraday::Connection]
+ def connection
+ Faraday.new(api_url, ssl: { verify: false }) do |conn|
conn.adapter Faraday.default_adapter
end
end
- # @param [Boolean] sandbox - Use the sandbox url?
- # @return [String] the API url
- def api_url(sandbox)
- if sandbox
- Zuora::SANDBOX_URL
+ # @return [String] - SOAP url based on @sandbox
+ def api_url
+ if @sandbox
+ 'https://apisandbox.zuora.com/apps/services/a/74.0'
else
- Zuora::API_URL
+ 'https://api.zuora.com/apps/services/a/74.0'
end
end
end
end