class LUSI::API::Core::API
Public Class Methods
Initializes a new API
instance @param api_user [String] the service account username @param api_password [String] the service account password @param logger [Logger, nil] a Logger instance for optional logging @param timeout [Integer] the timeout in seconds for LUSI
API
calls
# File lib/lusi_api/core/api.rb, line 22 def initialize(api_user: nil, api_password: nil, api_root: nil, logger: nil, timeout: nil) @api_password = api_password @api_root = api_root || 'https://lusiservice.lancs.ac.uk' @api_user = api_user @logger = logger @timeout = timeout.to_i end
Public Instance Methods
Calls a LUSI
API
method and return the parsed XML
response Any undocumented keyword parameters are passed as parameters to the LUSI
API
call. The LUSI
'Username' and 'Password' parameters are automatically added. @param path [String] the path of the API
call (e.g. 'LUSIReference') @param endpoint [String] the endpoint of the API
call (e.g. 'General.asmx') @param method [String] the method name of the API
call (e.g. 'GetServiceAccountDetails') @param headers [Hash<String, String>] optional HTTP headers for the API
call @param options [Hash<String, Object>] options for the REST client @return [Nokogiri::XML::Node] the parsed XML
<body> content from the API
response @raise [LUSIAPI::Core::APITimeoutError] if the LUSI
API
call times out @raise [LUSIAPI::Core::APICallError] if the LUSI
API
call fails for any other reason (e.g. network unavailable) @raise [LUSIAPI::Core::APIContentError] if the LUSI
API
call returns an XML
document with an error response
# File lib/lusi_api/core/api.rb, line 42 def call(path, endpoint, method, headers: nil, options: nil, **params) # Add the username and password to the params params[:Username] ||= @api_user params[:Password] ||= @api_password # Set the REST client headers rest_headers = {}.merge(headers || {}) # Set the REST client options rest_options = { method: :post, headers: rest_headers, payload: params, url: url(path, endpoint, method), } rest_options[:timeout] = @timeout if @timeout > 0 rest_options.merge(options) if options RestClient.log = @log if @log # Make the API call begin response = RestClient::Request.execute(**rest_options) rescue RestClient::Exceptions::Timeout => e raise APITimeoutError.new(url: rest_options[:url]) rescue RestClient::Exception => e raise APICallError.new(url: rest_options[:url]) rescue => e raise APIError.new(url: rest_options[:url]) end # Extract and return the XML content xml(response) end
Return a ServiceAccount
instance representing the API's service user @return [LUSI::API::ServiceAccount] the ServiceAccount
instance representing the API's service user
# File lib/lusi_api/core/api.rb, line 81 def get_service_account_details # There should only be one instance but get_instance returns an array for consistnecy with other classes result = LUSI::API::ServiceAccount.get_instance(self) result.length == 0 ? nil : result[0] end
Update the service user's password via the LUSI
API
@param password [String, nil] the new password (a random 16-character password is generated if this is omitted) @return [String] the new password
# File lib/lusi_api/core/api.rb, line 94 def update_service_account_password(password = nil) @api_password = LUSI::API::ServiceAccount.update_service_account_password(self, password) end
Construct a full API
method URL from its constituents @param path [String] the path of the API
call (e.g. 'LUSIReference') @param endpoint [String] the endpoint of the API
call (e.g. 'General.asmx') @param method [String] the method name of the API
call (e.g. 'GetServiceAccountDetails') @return [String] the fully-qualified URL of the API
method
# File lib/lusi_api/core/api.rb, line 103 def url(path = nil, endpoint = nil, method = nil) "#{@api_root}/#{path}/#{endpoint}/#{method}" end
Protected Instance Methods
Validate the XML
response from an API
call @param xml [Nokogiri::XML::Node] the parsed XML
response @return [Nokogiri::XML::Node] the parsed <body> element of the XML
response @raise [LUSI::API::Core::APIContentError] if the XML
response indicates an error
# File lib/lusi_api/core/api.rb, line 113 def validate(xml) header = LUSI::API::Core::XML.xml_at(xml, '//xmlns:Header') status = LUSI::API::Core::XML.xml_content_at(header, 'xmlns:Status') if status == 'Success' # No errors, return the body content LUSI::API::Core::XML.xml_at(xml, '//xmlns:Body') else # Errors present, raise APIContentError with the details error = { error_code: LUSI::API::Core::XML.xml_content_at(header, 'xmlns:ErrorCode'), fault: LUSI::API::Core::XML.xml_content_at(header, 'xmlns:Fault'), status: status } error_message = LUSI::API::Core::XML.xml_content_at(header, 'xmlns:ErrorMessage') case error[:error_code] when 'CLIENT004' raise APIPermissionError.new(error_message, **error) else raise APIContentError.new(error_message, **error) end end end
Parse and validate the XML
content from a LUSI
API
call @param response [String] the string-serialized XML
response from the API
@return [Nokogiri::XML::Document] the parsed <body> element of the XML
response @raise [LUSIAPI::Core::APIContentError] if the XML
parsing fails or the response indicates an error
# File lib/lusi_api/core/api.rb, line 140 def xml(response) # Parse the HTTP response as XML begin xml = Nokogiri::XML(response.to_s) rescue Nokogiri::SyntaxError => e raise APIContentError('XML syntax error') end # Validate the XML and return the <body> element if successful validate(xml) end