require 'net/http' require 'dm-core/support/inflector' module DataMapperRest # Somewhat stolen from ActiveResource # TODO: Support https? class Connection attr_accessor :uri, :format def initialize(uri, format) @uri = uri @format = Format.new(format) end # this is used to run the http verbs like http_post, http_put, http_delete etc. # TODO: handle nested resources, see prefix in ActiveResource def method_missing(method, *args) if verb = method.to_s.match(/\Ahttp_(get|post|put|delete|head)\z/) orig_uri, @uri = @uri, @uri.dup begin path, query = args[0].split('?', 2) @uri.path = "#{path}.#{@format.extension}#{'?' << query if query}" # Should be the form of /resources run_verb(verb.to_s.split('_').last, args[1]) ensure @uri = orig_uri end end end protected def run_verb(verb, data = nil) request do |http| klass = DataMapper::Ext::Module.find_const(Net::HTTP, DataMapper::Inflector.camelize(verb)) request = klass.new(@uri.to_s, @format.header) request.basic_auth(@uri.user, @uri.password) if @uri.user && @uri.password result = http.request(request, data) handle_response(result) end end def request(&block) res = nil Net::HTTP.start(@uri.host, @uri.port) do |http| res = yield(http) end res end # Handles response and error codes from remote service. def handle_response(response) case response.code.to_i when 301,302 raise(Redirection.new(response)) when 200...400 response when 400 raise(BadRequest.new(response)) when 401 raise(UnauthorizedAccess.new(response)) when 403 raise(ForbiddenAccess.new(response)) when 404 raise(ResourceNotFound.new(response)) when 405 raise(MethodNotAllowed.new(response)) when 409 raise(ResourceConflict.new(response)) when 422 raise(ResourceInvalid.new(response)) when 401...500 raise(ClientError.new(response)) when 500...600 raise(ServerError.new(response)) else raise(ConnectionError.new(response, "Unknown response code: #{response.code}")) end end end end