Class: Hatt::HTTP

Inherits:
Object
  • Object
show all
Includes:
JsonHelpers, Log
Defined in:
lib/hatt/http.rb

Constant Summary

Constants included from Log

Log::HattFormatter

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from JsonHelpers

#jsonify, #objectify

Methods included from Log

#add_logger, #level=, #log, #logger, #loggers

Constructor Details

#initialize(config) ⇒ HTTP

Returns a new instance of HTTP.



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
# File 'lib/hatt/http.rb', line 16

def initialize(config)
  @config = config
  @name = @config[:name]
  @base_uri = @config[:base_uri]
  @log_headers = @config.fetch(:log_headers, true)
  @log_bodies = @config.fetch(:log_bodies, true)

  logger.debug "Configuring service:\n#{@config.to_hash.to_yaml}\n"

  @faraday_connection = Faraday.new @config[:faraday_url] do |conn_builder|
    # do our own logging
    # conn_builder.response logger: logger
    # conn_builder.adapter  Faraday.default_adapter  # make requests with Net::HTTP
    conn_builder.adapter @config.fetch(:adapter, :typhoeus).intern
    conn_builder.ssl[:verify] = false if @config[:ignore_ssl_cert]

    # defaulting this to flat adapter avoids issues when duplicating parameters
    conn_builder.options[:params_encoder] = Faraday.const_get(@config.fetch(:params_encoder, 'FlatParamsEncoder'))

    # this nonsense dont work?!  https://github.com/lostisland/faraday_middleware/issues/76
    # conn_builder.use :instrumentation
  end

  @headers = {
    'accept' => 'application/json',
    'content-type' => 'application/json'
  }
  if @config[:default_headers]
    logger.debug 'Default headers configured: ' + @config[:default_headers].inspect
    @config[:default_headers].each_pair do |k, v|
      @headers[k.to_s] = v.to_s
    end
  end
  @default_timeout = @config.fetch(:timeout, 10)
  logger.info "Initialized hatt service '#{@name}'"
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



63
64
65
# File 'lib/hatt/http.rb', line 63

def config
  @config
end

#faraday_connectionObject (readonly)

Returns the value of attribute faraday_connection.



63
64
65
# File 'lib/hatt/http.rb', line 63

def faraday_connection
  @faraday_connection
end

#headersObject

allows for doing some fancy stuff in threading



64
65
66
# File 'lib/hatt/http.rb', line 64

def headers
  @headers
end

#httpObject (readonly)

allow stubbing http if we are testing



62
63
64
# File 'lib/hatt/http.rb', line 62

def http
  @http
end

#last_requestObject (readonly)

this is useful for testing apis, and other times you want to interrogate the http details of a response



68
69
70
# File 'lib/hatt/http.rb', line 68

def last_request
  @last_request
end

#last_responseObject (readonly)

this is useful for testing apis, and other times you want to interrogate the http details of a response



68
69
70
# File 'lib/hatt/http.rb', line 68

def last_response
  @last_response
end

#nameObject (readonly)

Returns the value of attribute name.



63
64
65
# File 'lib/hatt/http.rb', line 63

def name
  @name
end

Instance Method Details

#delete(path, options = {}) ⇒ Object



148
149
150
# File 'lib/hatt/http.rb', line 148

def delete(path, options = {})
  do_request :delete, path, nil, options
end

#do_request(method, path, obj = nil, options = {}) ⇒ Object

do_request performs the actual request, and does associated logging options can include:

  • :timeout, which specifies num secs the request should timeout in (this turns out to be kind of annoying to implement)

Raises:



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
# File 'lib/hatt/http.rb', line 79

def do_request(method, path, obj = nil, options = {})
  # hatt clients pass in path possibly including query params.
  # Faraday needs the query and path seperately.
  parsed_uri = URI.parse make_path(path)
  # faraday needs the request params as a hash.
  # this turns out to be non-trivial
  query_hash = if parsed_uri.query
                 cgi_hash = CGI.parse(parsed_uri.query)
                 # this next line accounts for one param having multiple values
                 cgi_hash.each_with_object({}) { |(k, v), h| h[k] = v[1] ? v : v.first; }
               end

  req_headers = make_headers(options)

  body = if options[:form]
           URI.encode_www_form obj
         else
           jsonify(obj)
  end


  log_request(method, parsed_uri, query_hash, headers, body)

  # doing it this way avoids problem with OPTIONS method: https://github.com/lostisland/faraday/issues/305
  response = nil
  metrics_obj = { method: method, service: @name, path: parsed_uri.path }
  ActiveSupport::Notifications.instrument('request.hatt', metrics_obj) do
    response = @faraday_connection.run_request(method, nil, nil, nil) do |req|
      req.path = parsed_uri.path
      req.params = metrics_obj[:params] = query_hash if query_hash

      req.headers = req_headers
      req.body = body
      req.options[:timeout] = options.fetch(:timeout, @default_timeout)
    end
    metrics_obj[:response] = response
  end

  logger.info "Request status: (#{response.status}) #{@name}: #{method.to_s.upcase} #{path}"
  @last_request = {
    method: method,
    path: parsed_uri.path,
    query: parsed_uri.query,
    headers: req_headers,
    body: body
  }
  @last_response = response

  response_obj = objectify response.body

  log_response(response, response_obj)

  raise RequestException.new(nil, response) unless response.status >= 200 && response.status < 300

  response_obj
end

#get(path, options = {}) ⇒ Object



136
137
138
# File 'lib/hatt/http.rb', line 136

def get(path, options = {})
  do_request :get, path, nil, options
end

#head(path, options = {}) ⇒ Object



140
141
142
# File 'lib/hatt/http.rb', line 140

def head(path, options = {})
  do_request :head, path, nil, options
end

#in_parallel(&blk) ⇒ Object



70
71
72
73
# File 'lib/hatt/http.rb', line 70

def in_parallel(&blk)
  @faraday_connection.headers = @headers
  @faraday_connection.in_parallel(&blk)
end

#last_response_statusObject

convenience method for accessing the last response status code



169
170
171
# File 'lib/hatt/http.rb', line 169

def last_response_status
  @last_response.status
end

#options(path, options = {}) ⇒ Object



144
145
146
# File 'lib/hatt/http.rb', line 144

def options(path, options = {})
  do_request :options, path, nil, options
end

#patch(path, obj, options = {}) ⇒ Object



160
161
162
# File 'lib/hatt/http.rb', line 160

def patch(path, obj, options = {})
  do_request :patch, path, obj, options
end

#post(path, obj, options = {}) ⇒ Object



152
153
154
# File 'lib/hatt/http.rb', line 152

def post(path, obj, options = {})
  do_request :post, path, obj, options
end

#post_form(path, params, options = {}) ⇒ Object



164
165
166
# File 'lib/hatt/http.rb', line 164

def post_form(path, params, options = {})
  do_request :post, path, params, options.merge(form: true)
end

#put(path, obj, options = {}) ⇒ Object



156
157
158
# File 'lib/hatt/http.rb', line 156

def put(path, obj, options = {})
  do_request :put, path, obj, options
end

#stubsObject



53
54
55
56
57
58
59
# File 'lib/hatt/http.rb', line 53

def stubs
  stubs = Faraday::Adapter::Test::Stubs.new
  @faraday_connection = Faraday.new @config[:faraday_url] do |conn_builder|
    conn_builder.adapter :test, stubs
  end
  stubs
end