class Bio::BaseSpace::APIClient
This class provides wrapper methods to the BaseSpace
API RESTful interface. It also handles serialization and deserialization of objects (Ruby to/from JSON). It is primarily used as a helper class for BaseSpaceAPI
.
Attributes
Public Class Methods
Create a new instance that will carry out REST calls.
access_token
-
Access token that is provided by App triggering.
api_server
-
URI of the
BaseSpace
API server. timeout
-
Timeout for REST calls.
# File lib/basespace/api/api_client.rb, line 37 def initialize(access_token = nil, api_server = nil, timeout = 10) if $DEBUG $stderr.puts " # ----- BaseAPI#initialize ----- " $stderr.puts " # caller: #{caller}" $stderr.puts " # access_token: #{access_token}" $stderr.puts " # api_server: #{api_server}" $stderr.puts " # timeout: #{timeout}" $stderr.puts " # " end raise UndefinedParameterError.new('AccessToken') unless access_token @api_key = access_token @api_server = api_server @timeout = timeout end
Public Instance Methods
Deserialize a boolean value to a Ruby object.
value
-
serialized representation of the boolean value.
# File lib/basespace/api/api_client.rb, line 98 def bool(value) case value when nil, false, 0, 'nil', 'false', '0', 'None' result = false else result = true end return result end
Carries out a RESTful operation on the BaseSpace
API.
TODO Need check. Logic in this method is rather complicated…
resource_path
-
URI that should be used for the API call.
method
-
HTTP method for the rest call (GET, POST, DELETE, etc.)
query_params
-
query parameters that should be sent along to the API.
post_data
-
Hash that contains data to be transferred.
header_params
-
Additional settings that should be transferred in the HTTP header.
force_post
-
Truth value that indicates whether a POST should be forced.
# File lib/basespace/api/api_client.rb, line 118 def call_api(resource_path, method, query_params, post_data, header_params = nil, force_post = false) url = @api_server + resource_path headers = header_params.dup headers['Content-Type'] = 'application/json' if not headers.has_key?('Content-Type') and not method == 'PUT' # include access token in header headers['Authorization'] = "Bearer #{@api_key}" uri = request = response = data = cgi_params = nil if query_params # Need to remove None (in Python, nil in Ruby) values, these should not be sent sent_query_params = {} query_params.each do |param, value| sent_query_params[param] = value if bool(value) end cgi_params = hash2urlencode(sent_query_params) end if $DEBUG $stderr.puts " # ----- APIClient#call_api ----- " $stderr.puts " # caller: #{caller}" $stderr.puts " # url: #{url}" $stderr.puts " # method: #{method}" $stderr.puts " # headers: #{headers}" $stderr.puts " # cgi_params: #{cgi_params}" $stderr.puts " # post_data: #{post_data}" $stderr.puts " # " end case method when 'GET' if cgi_params url += "?#{cgi_params}" end uri = URI.parse(url) # https://www.ruby-forum.com/topic/4411398 # In Ruby 1.9: Use Net::HTTP::Get.new(uri.path) or Net::HTTP::Get.new(uri.path + '?' + uri.query) # In Ruby 2.0: Use Net::HTTP::Get.new(uri) case RUBY_VERSION when /^1.9/ if uri.query and not uri.query.empty? request = Net::HTTP::Get.new(uri.path + '?' + uri.query, headers) else request = Net::HTTP::Get.new(uri.path, headers) end else request = Net::HTTP::Get.new(uri, headers) end when 'POST', 'PUT', 'DELETE' if cgi_params force_post_url = url url += "?#{cgi_params}" end if post_data # [TODO] Do we need to skip String, Integer, Float and bool also in Ruby? data = post_data # if not [str, int, float, bool].include?(type(post_data)) end if force_post response = force_post_call(force_post_url, sent_query_params, headers) else data = {} if not data or (data and data.empty?) # temp fix, in case is no data in the file, to prevent post request from failing uri = URI.parse(url) case RUBY_VERSION when /^1.9/ if uri.query and not uri.query.empty? request = Net::HTTP::Post.new(uri.path + '?' + uri.query, headers) else request = Net::HTTP::Post.new(uri.path, headers) end else request = Net::HTTP::Post.new(uri, headers) end if data.kind_of?(Hash) then request.set_form_data(data) else request.content_type = 'multipart/form-data' request.body = data end end if ['PUT', 'DELETE'].include?(method) # urllib doesnt do put and delete, default to pycurl here response = put_call(url, query_params, headers, data) response = response.split.last end else raise "Method #{method} is not recognized." end # Make the request, request may raise 403 forbidden, or 404 non-response if not force_post and not ['PUT', 'DELETE'].include?(method) # the normal case # puts url # puts request # puts "request with timeout=#{@timeout}" # [TODO] confirm this works or not #response = urllib2.urlopen(request, @timeout).read() http_opts = {} if uri.scheme == "https" http_opts[:use_ssl] = true end response = Net::HTTP.start(uri.host, uri.port, http_opts) { |http| http.request(request) } end begin data = JSON.parse(response.body) rescue => err $stderr.puts " # ----- APIClient#call_api ----- " $stderr.puts " # Error: #{err}" $stderr.puts " # " data = nil end return data end
Deserialize a JSON string into an object.
obj
-
String or object to be deserialized.
obj_class
-
Class literal for deserialzied object, or string of class name.
# File lib/basespace/api/api_client.rb, line 248 def deserialize(obj, obj_class) case obj_class.downcase when 'str' return obj.to_s when 'int' return obj.to_i when 'float' return obj.to_f when 'bool' return bool(obj) when 'file' # Bio::BaseSpace::File instance = File.new else # models in BaseSpace klass = ::Bio::BaseSpace.const_get(obj_class) instance = klass.new end if $DEBUG $stderr.puts " # ----- APIClient#deserialize ----- " $stderr.puts " # caller: #{caller}" $stderr.puts " # obj_class: #{obj_class}" $stderr.puts " # obj: #{obj}" # JSON.pretty_generate(obj) $stderr.puts " # " end instance.swagger_types.each do |attr, attr_type| if obj.has_key?(attr) or obj.has_key?(attr.to_s) if $DEBUG $stderr.puts " # # ----- APIClient#deserialize/swagger_types ----- " $stderr.puts " # # attr: #{attr}" $stderr.puts " # # attr_type: #{attr_type}" $stderr.puts " # # value: #{obj[attr]}" $stderr.puts " # # " end value = obj[attr] case attr_type.downcase when 'str' instance.set_attr(attr, value.to_s) when 'int' instance.set_attr(attr, value.to_i) when 'float' instance.set_attr(attr, value.to_f) when 'datetime' instance.set_attr(attr, DateTime.parse(value)) when 'bool' instance.set_attr(attr, bool(value)) when /list</ sub_class = attr_type[/list<(.*)>/, 1] sub_values = [] value.each do |sub_value| sub_values << deserialize(sub_value, sub_class) end instance.set_attr(attr, sub_values) when 'dict' # support for parsing dictionary if $DEBUG $stderr.puts " # # # ----- APIClient#deserialize/swagger_types/dict ----- " $stderr.puts " # # # dict: #{value}" $stderr.puts " # # # " end # [TODO] May need to convert value -> Hash (check in what format the value is passed) instance.set_attr(attr, value) else if $DEBUG # print "recursive call w/ " + attrType $stderr.puts " # # # ----- APIClient#deserialize/swagger_types/recursive call ----- " $stderr.puts " # # # attr: #{attr}" $stderr.puts " # # # attr_type: #{attr_type}" $stderr.puts " # # # value: #{value}" $stderr.puts " # # # " end instance.set_attr(attr, deserialize(value, attr_type)) end end end if $DEBUG $stderr.puts " # # ----- APIClient#deserialize/instance ----- " $stderr.puts " # # instance: #{instance.attributes.inspect}" $stderr.puts " # # " end return instance end
POST data to a provided URI.
resource_path
-
URI to which the data should be POSTed.
post_data
-
Hash that contains the data.
headers
-
Header of the POST call.
data
-
(unused; TODO)
# File lib/basespace/api/api_client.rb, line 58 def force_post_call(resource_path, post_data, headers, data = nil) # [TODO] Confirm whether we can expect those two parameters are Hash objects: # headers = { "key" => "value" } # post_data = { "key" => "value" } uri = URI.parse(resource_path) # If headers are not needed, the following line should be enough: # return Net::HTTP.post_form(uri, post_data).body http_opts = {} if uri.scheme == "https" http_opts[:use_ssl] = true end res = Net::HTTP.start(uri.host, uri.port, http_opts) { |http| encoded_data = hash2urlencode(post_data) http.post(uri.path, encoded_data, headers) } return res.body end
URL encode a Hash of data values.
hash
-
data encoded in a Hash.
# File lib/basespace/api/api_client.rb, line 79 def hash2urlencode(hash) # URI.escape (alias URI.encode) is obsolete since Ruby 1.9.2. #return hash.map{|k,v| URI.encode(k.to_s) + "=" + URI.encode(v.to_s)}.join("&") return hash.map{|k,v| URI.encode_www_form_component(k.to_s) + "=" + URI.encode_www_form_component(v.to_s)}.join("&") end
Makes a PUT call to a given URI for depositing file contents.
resource_path
-
URI to which the data should be transferred.
post_data
-
(unused; TODO)
headers
-
Header of the PUT call.
trans_file
-
Path to the file that should be transferred.
# File lib/basespace/api/api_client.rb, line 91 def put_call(resource_path, post_data, headers, trans_file) return %x(curl -H "x-access-token:#{@api_key}" -H "Content-MD5:#{headers['Content-MD5'].strip}" -T "#{trans_file}" -X PUT #{resource_path}) end
Serialize a list to a CSV string, if necessary.
obj
-
Data object to be serialized.
# File lib/basespace/api/api_client.rb, line 236 def to_path_value(obj) if obj.kind_of?(Array) return obj.join(',') else return obj end end