Class: FoucaultHttp::HttpPort

Inherits:
Object
  • Object
show all
Extended by:
Dry::Monads::Try::Mixin, Logging
Defined in:
lib/foucault_http/http_port.rb

Defined Under Namespace

Classes: NoContentTypeError

Constant Summary collapse

FAIL =
:fail
OK =
:ok
BAD_REQUEST =
:bad_request
UNAUTHORISED =
:unauthorised
NOT_FOUND =
:not_found
SYSTEM_FAILURE =
:system_failure
UNPROCESSABLE_ENTITY =
:unprocessable_entity

Class Method Summary collapse

Methods included from Logging

debug, error, fatal, info, logger

Class Method Details

.addressObject



79
80
81
82
83
# File 'lib/foucault_http/http_port.rb', line 79

def address
  -> service, resource {
    (service || "") + (resource || "")
  }.curry
end

.addressedObject



69
70
71
72
73
# File 'lib/foucault_http/http_port.rb', line 69

def addressed
  -> service, resource, connection {
    connection.(address.(service, resource))
  }.curry
end

.catastrophic_failure(response) ⇒ Object



159
160
161
162
163
164
165
# File 'lib/foucault_http/http_port.rb', line 159

def catastrophic_failure(response)
  OpenStruct.new(
    status: SYSTEM_FAILURE,
    exception: parse_error_response(response),
    code: 418
  )
end

.connectionObject



75
76
77
# File 'lib/foucault_http/http_port.rb', line 75

def connection
  -> opts, encoding, address { HttpConnection.new.connection(address, opts, encoding) }.curry
end

.context_for_log(service, resource, response) ⇒ Object



209
210
211
212
213
214
215
# File 'lib/foucault_http/http_port.rb', line 209

def context_for_log(service, resource, response)
  {
    http_code: response.code,
    resource: address.(service, resource),
    fail_response: log_of_failure(response)
  }
end

.deleteObject



40
41
42
43
44
45
46
47
48
# File 'lib/foucault_http/http_port.rb', line 40

def delete
  -> correlation, service, resource, opts, hdrs {
    ( Fn.either.(net_ok).(Monad.success).(Monad.failure) <<
      log_response.([], service, resource, __method__) <<
      response_value <<
      run_delete.(hdrs) <<
      addressed.(service, resource)).(connection.(opts, nil))
  }
end

.evalulate_statusObject



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/foucault_http/http_port.rb', line 103

def evalulate_status
  -> status {
    case status
    when 200..300
      OK
    when 400
      BAD_REQUEST
    when 401, 403
      UNAUTHORISED
    when 404
      NOT_FOUND
    when 422
      UNPROCESSABLE_ENTITY
    when 500..530
      SYSTEM_FAILURE
    else
      FAIL
    end
  }
end

.getObject



30
31
32
33
34
35
36
37
38
# File 'lib/foucault_http/http_port.rb', line 30

def get
  -> correlation, service, resource, opts, hdrs, enc, query {
    ( Fn.either.(net_ok).(Monad.success).(Monad.failure) <<
      log_response.(correlation, service, resource, __method__) <<
      response_value <<
      run_get.(hdrs, query) <<
      addressed.(service, resource)).(connection.(opts, enc))
  }
end

.json_parserObject



176
177
178
# File 'lib/foucault_http/http_port.rb', line 176

def json_parser
  -> response { JSON.parse(response.body) }
end

.log_of_failure(response) ⇒ Object



217
218
219
220
# File 'lib/foucault_http/http_port.rb', line 217

def log_of_failure(response)
  return nil if net_ok.(response)
  response.body.inspect
end

.log_responseObject



91
92
93
94
95
96
# File 'lib/foucault_http/http_port.rb', line 91

def log_response
  -> correlation, service, resource, api, response {
    info(structured_log(service, resource, api, response, correlation))
    response
  }.curry
end

.net_okObject



196
197
198
# File 'lib/foucault_http/http_port.rb', line 196

def net_ok
  -> value { value.status == OK }
end

.nil_parserObject



192
193
194
# File 'lib/foucault_http/http_port.rb', line 192

def nil_parser
  -> response { response.body }
end

.parse_error_response(response) ⇒ Object



167
168
169
170
171
172
173
174
# File 'lib/foucault_http/http_port.rb', line 167

def parse_error_response(response)
  result = response.to_result
  if result.failure.respond_to?(:exception)
    {exception_class: result.failure.exception.class.name, exception: result.failure.message}
  else
    {execepton: "not-determined"}
  end
end

.parser_fnObject



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/foucault_http/http_port.rb', line 131

def parser_fn
  -> type {
    case type
    when "text/html"
      xml_parser
    when "text/plain"
      text_parser
    when "text/csv"
      text_parser
    when "application/json"
      json_parser
    when "application/xml", "application/soap+xml", "text/xml"
      xml_parser
    else
      nil_parser
    end
  }
end

.postObject



20
21
22
23
24
25
26
27
28
# File 'lib/foucault_http/http_port.rb', line 20

def post
  -> correlation, service, resource, opts, hdrs, body_fn, enc, body {
    ( Fn.either.(net_ok).(Monad.success).(Monad.failure) <<
      log_response.(correlation, service, resource, __method__) <<
      response_value <<
      run_post.(hdrs, body_fn, body) <<
      addressed.(service, resource)).(connection.(opts, enc))
  }
end

.response_body_parserObject

takes a content type and returns a parser; e.g. “application/json; charset=utf-8” returns the json_parser



125
126
127
128
129
# File 'lib/foucault_http/http_port.rb', line 125

def response_body_parser
  parser_fn <<
  Fn.at.(0) <<
  Fn.split.(";")
end

.response_valueObject



85
86
87
88
89
# File 'lib/foucault_http/http_port.rb', line 85

def response_value
  -> response {
    response.success? ? try_handle_response(response) : catastrophic_failure(response)
  }
end

.returned_response(response) ⇒ Object

Raises:



150
151
152
153
154
155
156
157
# File 'lib/foucault_http/http_port.rb', line 150

def returned_response(response)
  raise(NoContentTypeError.new("Content Type in response is nil; body: #{response.value_or.body}")) unless response.value_or.headers["content-type"]
  OpenStruct.new(
    status: evalulate_status.(response.value_or.status),
    code: response.value_or.status,
    body: response_body_parser.(response.value_or.headers["content-type"]).(response.value_or)
  )
end

.run_deleteObject



63
64
65
66
67
# File 'lib/foucault_http/http_port.rb', line 63

def run_delete
  -> hdrs, connection {
    connection.delete(hdrs)
  }.curry
end

.run_getObject



57
58
59
60
61
# File 'lib/foucault_http/http_port.rb', line 57

def run_get
  -> hdrs, query, connection {
    connection.get(hdrs, query)
  }.curry
end

.run_postObject



51
52
53
54
55
# File 'lib/foucault_http/http_port.rb', line 51

def run_post
  -> hdrs, body_fn, body, connection {
    connection.post(hdrs, Try { body_fn.(body) })
  }.curry
end

.structured_log(service, resource, api, response, correlation = {}) ⇒ Object



200
201
202
203
204
205
206
207
# File 'lib/foucault_http/http_port.rb', line 200

def structured_log(service, resource, api, response, correlation={})
  {
    msg: "Common::Network::Net",
    context: context_for_log(service, resource, response),
    step: api,
    status: response.status
  }.merge(correlation || {})
end

.text_csvObject



188
189
190
# File 'lib/foucault_http/http_port.rb', line 188

def text_csv
  -> response { response.body }
end

.text_parserObject



184
185
186
# File 'lib/foucault_http/http_port.rb', line 184

def text_parser
  -> response { response.body }
end

.try_handle_response(response) ⇒ Object



98
99
100
101
# File 'lib/foucault_http/http_port.rb', line 98

def try_handle_response(response)
  result = Try { returned_response(response) }
  result.success? ? result.value_or : catastrophic_failure(result)
end

.xml_parserObject



180
181
182
# File 'lib/foucault_http/http_port.rb', line 180

def xml_parser
  -> response { Nokogiri::XML(response.body) }
end