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
'2.2.1'
Instance Method Summary collapse
-
#check_error(xml) ⇒ Object
Must extract and raise an error from
xml
, an REXML::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 REXML::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 REXML::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 { |v| << [k, v] } 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 REXML::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 |
# File 'lib/rc_rest.rb', line 117 def get(method, params = {}) url = make_url method, params url.open do |xml| res = REXML::Document.new xml.read check_error res return parse_response(res) end rescue IOError, SystemCallError, SocketError, Timeout::Error, REXML::ParseException => e raise CommunicationError.new(e) rescue OpenURI::HTTPError => e begin xml = REXML::Document.new e.io.read check_error xml rescue REXML::ParseException => e end new_e = CommunicationError.new e new_e. << "\n\nunhandled error:\n#{xml.to_s}" raise 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.
192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/rc_rest.rb', line 192 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
171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/rc_rest.rb', line 171 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 REXML::Document, into something sensible for the API.
209 210 211 |
# File 'lib/rc_rest.rb', line 209 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 REXML::Document instance and returns its result.
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/rc_rest.rb', line 218 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 = REXML::Document.new res.body check_error xml parse_response xml rescue SystemCallError, SocketError, Timeout::Error, IOError, REXML::ParseException => e raise CommunicationError.new(e) rescue Net::HTTPError => e xml = REXML::Document.new e.res.body 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 REXML::Document instance and returns its result.
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/rc_rest.rb', line 250 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 = REXML::Document.new res.body check_error xml parse_response xml rescue SystemCallError, SocketError, Timeout::Error, IOError, REXML::ParseException => e raise CommunicationError.new(e) rescue Net::HTTPError => e xml = REXML::Document.new e.res.body check_error xml raise CommunicationError.new(e) end |