Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 144 lines (123 sloc) 3.921 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
require 'faraday'
require 'uri_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.
    # :faraday - Optional Faraday::Connection to use.
    # :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: 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|
        req.body = encode_body(data) if data
        if params = options[:query]
          req.params.update params
        end
        if headers = options[:headers]
          req.headers.update headers
        end
        started = Time.now
      end
      res.env[:sawyer_started] = started
      res.env[:sawyer_ended] = Time.now

      Response.new self, res
    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 : URITemplate.new(url.to_s)
      expand = tpl.method(:expand)
      options ? expand.call(options) : expand.call
    end

    def allow_undefined_methods?
      !!@allow_undefined_methods
    end

    def inspect
      %(<#{self.class} #{@endpoint}>)
    end
  end
end

Something went wrong with that request. Please try again.