Created
April 4, 2014 03:57
Revisions
-
zenhob created this gist
Apr 4, 2014 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,98 @@ # # This module is a starter Ruby client for your REST API, based on Faraday: # https://github.com/lostisland/faraday/ # # It supports HTTP basic authentication, sending and recieving JSON, and simple error reporting. # I use this as a basis for building API clients in most of my Ruby projects. # # Use it like this: # # http = GenericApi.connect('http://localhost:3000/', 'myname', 'secret') # http.get('boxes.json').body.each do |box| # puts "found a box named #{box[:name]}! Let's put something inside." # http.post('boxes/#{box[:id]}.json', contents: 'something!') # end # # A few hints for getting started: # # This uses Patron as the HTTP client but you can change those constants to use # another adapter or set to nil to use the built-in default. # # The response body is a Hash with Symbol keys (not String!). # If you're using ActiveSupport, you should use a hash with indifferent access instead. # # The default MIME type is appropriate for most purposes, but some APIs use it for # versioning so bear that in mind and change MIME_TYPE if necessary. # # Warmest regards, # # Zack Hobson <[email protected]> # require 'faraday' module GenericApi FARADAY_ADAPTER = :patron REQUIRE_DEPENDENCIES = ['patron'] MIME_TYPE = 'application/json' # Connect and return a `Faraday::Connection` instance: # http://rdoc.info/github/lostisland/faraday/Faraday/Connection # # If login and password are provided, the connection will use basic auth. def self.connect url, login=nil, password=nil Faraday.new(url) do |f| f.use :generic_api, login, password f.adapter(FARADAY_ADAPTER || Faraday.default_adapter) end end class Middleware < Faraday::Request::BasicAuthentication Faraday::Middleware.register_middleware generic_api: ->{ self } dependency do require 'yajl' (REQUIRE_DEPENDENCIES||[]).each {|dep| require dep } end def call(env) # encode with and accept json env[:request_headers]['Accept'] = MIME_TYPE env[:request_headers]['Content-Type'] = MIME_TYPE env[:body] = Yajl::Encoder.encode(env[:body]) # response processing super(env).on_complete do |env| begin env[:body] = Yajl::Parser.parse(env[:body], symbolize_keys:true) # XXX or, if you're using ActiveSupport: # env[:body] = Yajl::Parser.parse(env[:body]).with_indifferent_access rescue Yajl::ParseError raise ApiError.new("Unable to parse the response:\n#{env[:body]}", env) end case env[:status] when 300..399 raise RedirectError.new(env[:body][:message], env) when 400..499 raise AuthError.new(env[:body][:message], env) when 500..599 raise ApiError.new(env[:body][:message], env) end end end end class ApiError < Faraday::ClientError def initialize(message, response) super("Upstream API failure: #{message||'Internal error.'}", response) end end class AuthError < Faraday::ClientError def initialize(message, response) super("Authentication failure: #{message||'No reason given.'}", response) end end class RedirectError < Faraday::ClientError def initialize(message, response) super("Redirected: #{message||'No reason given.'}", response) end end end