Created
April 4, 2014 03:57
-
-
Save zenhob/9967821 to your computer and use it in GitHub Desktop.
Starter Ruby client for your REST API, based on Faraday
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 characters
# | |
# 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 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment