Abstract class for implementing REST APIs.
The following methods must be implemented in sublcasses:
initialize
Sets @url to the service enpoint.
check_error
Checks for errors in the server response.
parse_response
Extracts information from the server response.
If you have extra URL paramaters (application id, output type) or need to
perform URL customization, override make_url and
make_multipart.
class FakeService < RCRest class Error < RCRest::Error; end def initialize(appid) @appid = appid @url = URI.parse 'http://example.com/api/' end def check_error(xml) raise Error, xml.elements['error'].text if xml.elements['error'] end def make_url(method, params) params[:appid] = @appid super method, params end def parse_response(xml) return xml end def test(query) get :test, :q => query end end
You are using this version of RCRest
Must extract and raise an error from xml, an
Nokogiri::XML::Document, if any. Must return if no error could be found.
# File lib/rc_rest.rb, line 94 def check_error(xml) raise NotImplementedError end
Performs a GET request for method method with
params. Calls parse_response on the
concrete class with an Nokogiri::XML::Document instance and returns its
result.
# File lib/rc_rest.rb, line 117 def get(method, params = {}) @http ||= Net::HTTP::Persistent.new url = make_url method, params http_response = @http.request url case http_response when Net::HTTPSuccess res = Nokogiri::XML http_response.body, nil, nil, 0 check_error res parse_response res when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther, Net::HTTPTemporaryRedirect then # TODO else begin xml = Nokogiri::XML http_response.body, nil, nil, 0 check_error xml rescue Nokogiri::XML::SyntaxError => e end e = CommunicationError.new http_response e.message << "\n\nunhandled error:\n#{xml.to_s}" raise e end rescue Net::HTTP::Persistent::Error, SocketError, Timeout::Error, Nokogiri::XML::SyntaxError => e raise CommunicationError.new(e) end
Creates a multipart form post for the Hash of parameters
params. Override this then call super if you need to add extra
params like an application id, output type, etc.
make_multipart handles arguments similarly to make_url.
# File lib/rc_rest.rb, line 204 def make_multipart(params) boundary = (0...8).map { rand(255).to_s 16 }.join '_' data = expand_params(params).map do |key, value| [ "--#{boundary}", "Content-Disposition: form-data; name=\"#{key}\"", nil, value] end data << "--#{boundary}--" return [boundary, data.join("\r\n")] end
Creates a URI for method method and a Hash of parameters
params. Override this then call super if you need to add extra
params like an application id, output type, etc.
If the value of a parameter responds to each, #make_url creates a key-value pair per value in the param.
Examples:
If the URL base is:
http://example.com/api/
then:
make_url nil, :a => '1 2', :b => [4, 3]
creates the URL:
http://example.com/api/?a=1%202&b=3&b=4
and
make_url :method, :a => '1'
creates the URL:
http://example.com/api/method?a=1
# File lib/rc_rest.rb, line 183 def make_url(method, params = nil) escaped_params = expand_params(params).map do |k,v| k = URI.escape(k.to_s).gsub(';', '%3B').gsub('+', '%2B').gsub('&', '%26') v = URI.escape(v.to_s).gsub(';', '%3B').gsub('+', '%2B').gsub('&', '%26') "#{k}=#{v}" end query = escaped_params.join '&' url = @url + "./#{method}" url.query = query return url end
Must parse results from xml, an Nokogiri::XML::Document, into
something sensible for the API.
# File lib/rc_rest.rb, line 221 def parse_response(xml) raise NotImplementedError end
Performs a POST request for method method with
params. Calls parse_response on the
concrete class with an Nokogiri::XML::Document instance and returns its
result.
# File lib/rc_rest.rb, line 230 def post(method, params = {}) url = make_url method, params query = url.query url.query = nil req = Net::HTTP::Post.new url.path req.body = query req.content_type = 'application/x-www-form-urlencoded' res = Net::HTTP.start url.host, url.port do |http| http.request req end xml = Nokogiri::XML(res.body, nil, nil, 0) check_error xml parse_response xml rescue SystemCallError, SocketError, Timeout::Error, IOError, Nokogiri::XML::SyntaxError => e raise CommunicationError.new(e) rescue Net::HTTPError => e xml = Nokogiri::XML(e.res.body) { |cfg| cfg.strict } check_error xml raise CommunicationError.new(e) end
Performs a POST request for method method with
params, submitting a multipart form. Calls parse_response on the
concrete class with an Nokogiri::XML::Document instance and returns its
result.
# File lib/rc_rest.rb, line 262 def post_multipart(method, params = {}) url = make_url method, {} url.query = nil boundary, data = make_multipart params req = Net::HTTP::Post.new url.path req.content_type = "multipart/form-data; boundary=#{boundary}" req.body = data res = Net::HTTP.start url.host, url.port do |http| http.request req end xml = Nokogiri::XML(res.body, nil, nil, 0) check_error xml parse_response xml rescue SystemCallError, SocketError, Timeout::Error, IOError, Nokogiri::XML::SyntaxError => e raise CommunicationError.new(e) rescue Net::HTTPError => e xml = Nokogiri::XML(e.res.body, nil, nil, 0) check_error xml raise CommunicationError.new(e) end
Web services initializer.
Concrete web services implementations must set the url
instance variable which must be a URI.
# File lib/rc_rest.rb, line 86 def initialize raise NotImplementedError, 'need to implement #intialize and set @url' end