This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
require 'faraday'
|
||||
require 'addressable/template'
|
||||
|
||||
module Sawyer
|
||||
class Agent
|
||||
NO_BODY = Set.new([:get, :head])
|
||||
|
||||
attr_accessor :links_parser
|
||||
attr_accessor :allow_undefined_methods
|
||||
|
||||
class << self
|
||||
attr_writer :serializer
|
||||
end
|
||||
|
||||
def self.serializer
|
||||
@serializer ||= Serializer.any_json
|
||||
end
|
||||
|
||||
def self.encode(data)
|
||||
serializer.encode(data)
|
||||
end
|
||||
|
||||
def self.decode(data)
|
||||
serializer.decode(data)
|
||||
end
|
||||
|
||||
# Agents handle making the requests, and passing responses to
|
||||
# Sawyer::Response.
|
||||
#
|
||||
# endpoint - String URI of the API entry point.
|
||||
# options - Hash of options.
|
||||
# :allow_undefined_methods - Allow relations to call all the HTTP verbs,
|
||||
# not just the ones defined.
|
||||
# :faraday - Optional Faraday::Connection to use.
|
||||
# :links_parser - Optional parser to parse link relations
|
||||
# Defaults: Sawyer::LinkParsers::Hal.new
|
||||
# :serializer - Optional serializer Class. Defaults to
|
||||
# self.serializer_class.
|
||||
#
|
||||
# Yields the Faraday::Connection if a block is given.
|
||||
def initialize(endpoint, options = nil)
|
||||
@endpoint = endpoint
|
||||
@conn = (options && options[:faraday]) || Faraday.new
|
||||
@serializer = (options && options[:serializer]) || self.class.serializer
|
||||
@links_parser = (options && options[:links_parser]) || Sawyer::LinkParsers::Hal.new
|
||||
@allow_undefined_methods = (options && options[:allow_undefined_methods])
|
||||
@conn.url_prefix = @endpoint
|
||||
yield @conn if block_given?
|
||||
end
|
||||
|
||||
# Public: Close the underlying connection.
|
||||
def close
|
||||
@conn.close if @conn.respond_to?(:close)
|
||||
end
|
||||
|
||||
# Public: Retains a reference to the root relations of the API.
|
||||
#
|
||||
# Returns a Sawyer::Relation::Map.
|
||||
def rels
|
||||
@rels ||= root.data._rels
|
||||
end
|
||||
|
||||
# Public: Retains a reference to the root response of the API.
|
||||
#
|
||||
# Returns a Sawyer::Response.
|
||||
def root
|
||||
@root ||= start
|
||||
end
|
||||
|
||||
# Public: Hits the root of the API to get the initial actions.
|
||||
#
|
||||
# Returns a Sawyer::Response.
|
||||
def start
|
||||
call :get, @endpoint
|
||||
end
|
||||
|
||||
# Makes a request through Faraday.
|
||||
#
|
||||
# method - The Symbol name of an HTTP method.
|
||||
# url - The String URL to access. This can be relative to the Agent's
|
||||
# endpoint.
|
||||
# data - The Optional Hash or Resource body to be sent. :get or :head
|
||||
# requests can have no body, so this can be the options Hash
|
||||
# instead.
|
||||
# options - Hash of option to configure the API request.
|
||||
# :headers - Hash of API headers to set.
|
||||
# :query - Hash of URL query params to set.
|
||||
#
|
||||
# Returns a Sawyer::Response.
|
||||
def call(method, url, data = nil, options = nil)
|
||||
if NO_BODY.include?(method)
|
||||
options ||= data
|
||||
data = nil
|
||||
end
|
||||
|
||||
options ||= {}
|
||||
url = expand_url(url, options[:uri])
|
||||
started = nil
|
||||
res = @conn.send method, url do |req|
|
||||
if data
|
||||
req.body = data.is_a?(String) ? data : encode_body(data)
|
||||
end
|
||||
if params = options[:query]
|
||||
req.params.update params
|
||||
end
|
||||
if headers = options[:headers]
|
||||
req.headers.update headers
|
||||
end
|
||||
started = Time.now
|
||||
end
|
||||
|
||||
Response.new self, res, :sawyer_started => started, :sawyer_ended => Time.now
|
||||
end
|
||||
|
||||
# Encodes an object to a string for the API request.
|
||||
#
|
||||
# data - The Hash or Resource that is being sent.
|
||||
#
|
||||
# Returns a String.
|
||||
def encode_body(data)
|
||||
@serializer.encode(data)
|
||||
end
|
||||
|
||||
# Decodes a String response body to a resource.
|
||||
#
|
||||
# str - The String body from the response.
|
||||
#
|
||||
# Returns an Object resource (Hash by default).
|
||||
def decode_body(str)
|
||||
@serializer.decode(str)
|
||||
end
|
||||
|
||||
def parse_links(data)
|
||||
@links_parser.parse(data)
|
||||
end
|
||||
|
||||
def expand_url(url, options = nil)
|
||||
tpl = url.respond_to?(:expand) ? url : Addressable::Template.new(url.to_s)
|
||||
tpl.expand(options || {}).to_s
|
||||
end
|
||||
|
||||
def allow_undefined_methods?
|
||||
!!@allow_undefined_methods
|
||||
end
|
||||
|
||||
def inspect
|
||||
%(<#{self.class} #{@endpoint}>)
|
||||
end
|
||||
|
||||
# private
|
||||
def to_yaml_properties
|
||||
[:@endpoint]
|
||||
end
|
||||
|
||||
def marshal_dump
|
||||
[@endpoint]
|
||||
end
|
||||
|
||||
def marshal_load(dumped)
|
||||
@endpoint = *dumped.shift(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user