File: agent.rb

package info (click to toggle)
ruby-sawyer 0.9.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 280 kB
  • sloc: ruby: 1,224; sh: 17; makefile: 4
file content (163 lines) | stat: -rw-r--r-- 4,592 bytes parent folder | download | duplicates (2)
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
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