Class: RCRest
- Inherits:
-
Object
- Object
- RCRest
- Defined in:
- lib/rc_rest.rb
Overview
Abstract class for implementing REST APIs.
Example
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
Defined Under Namespace
Classes: CommunicationError, Error
Constant Summary collapse
- VERSION =
You are using this version of RCRest
'4.0'
Instance Method Summary collapse
-
#check_error(xml) ⇒ Object
Must extract and raise an error from
xml
, an Nokogiri::XML::Document, if any. -
#expand_params(params) ⇒ Object
:nodoc:.
-
#get(method, params = {}) ⇒ Object
Performs a GET request for method
method
withparams
. -
#initialize ⇒ RCRest
constructor
Web services initializer.
-
#make_multipart(params) ⇒ Object
Creates a multipart form post for the Hash of parameters
params
. -
#make_url(method, params = nil) ⇒ Object
Creates a URI for method
method
and a Hash of parametersparams
. -
#parse_response(xml) ⇒ Object
Must parse results from
xml
, an Nokogiri::XML::Document, into something sensible for the API. -
#post(method, params = {}) ⇒ Object
Performs a POST request for method
method
withparams
. -
#post_multipart(method, params = {}) ⇒ Object
Performs a POST request for method
method
withparams
, submitting a multipart form.
Constructor Details
#initialize ⇒ RCRest
Web services initializer.
Concrete web services implementations must set the url
instance variable which must be a URI.
86 87 88 |
# File 'lib/rc_rest.rb', line 86 def initialize raise NotImplementedError, 'need to implement #intialize and set @url' end |
Instance Method Details
#check_error(xml) ⇒ Object
Must extract and raise an error from xml
, an Nokogiri::XML::Document, if any. Must return if no error could be found.
94 95 96 |
# File 'lib/rc_rest.rb', line 94 def check_error(xml) raise NotImplementedError end |
#expand_params(params) ⇒ Object
:nodoc:
98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/rc_rest.rb', line 98 def (params) # :nodoc: = [] params.each do |k,v| if v.respond_to? :each and not String === v then v.each { |s| << [k, s] } else << [k, v] end end .sort_by { |k,v| [k.to_s, v.to_s] } end |
#get(method, params = {}) ⇒ Object
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.
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# 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. << "\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 |
#make_multipart(params) ⇒ Object
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.
204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/rc_rest.rb', line 204 def make_multipart(params) boundary = (0...8).map { rand(255).to_s 16 }.join '_' data = (params).map do |key, value| [ "--#{boundary}", "Content-Disposition: form-data; name=\"#{key}\"", nil, value] end data << "--#{boundary}--" return [boundary, data.join("\r\n")] end |
#make_url(method, params = nil) ⇒ Object
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
183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/rc_rest.rb', line 183 def make_url(method, params = nil) escaped_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 |
#parse_response(xml) ⇒ Object
Must parse results from xml
, an Nokogiri::XML::Document, into something sensible for the API.
221 222 223 |
# File 'lib/rc_rest.rb', line 221 def parse_response(xml) raise NotImplementedError end |
#post(method, params = {}) ⇒ Object
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.
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# 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 |
#post_multipart(method, params = {}) ⇒ Object
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.
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
# 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 |