restool 0.1.4 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 584d88793980824115720aa0e0f037d0fae8c35439c4e24e16e33dc902b11e8b
4
- data.tar.gz: 7adca6d17ead07b51bbe097b273e655e5ff34d365bbc95ffb33620e70588cffa
3
+ metadata.gz: a30917334428d8500580624813b39b56a4e56e8fae18f01399f23fd5f24aebca
4
+ data.tar.gz: aabdff9a61d0b7e9e976c1e88aec8af63ce511fa72b6b01ef97f2f961c0150ee
5
5
  SHA512:
6
- metadata.gz: 0b93df06284266885ce45b9e83849a7125ed2d0f4bd82a236b5ea751aaa7860136aeaad9f248dd3ad5d6ab21d3948469a82973cbe0a19812a578d57cb43d4c55
7
- data.tar.gz: d1a7b15cfc046896fc3b57d9092c1ffe33f50d21a1d8645327b68b7a28259b3e47ee9349e74115d77028c5b02cbf26607c995a4f9c9db0e6b2f7e02796d30bbb
6
+ metadata.gz: 8ce2c12b769a4605c6163d2102df036cc74c596b0477720c229e2abd7aa7f7851e3b09dc436590654373cb5758144cc1ee93ca6b7ddd8eed2fd4294ae0ab965f
7
+ data.tar.gz: 45e6f37d33a8bd228ceb15caec3234cfaa9642cced28eb5e85c3ebb64f435fa7cf2e3a504046ca5ddedf1921c2dc850d4cd0420872b106680eaa010554d8046a
@@ -1,11 +1,10 @@
1
1
  require_relative 'restool/settings/loader'
2
2
  require_relative 'restool/service/restool_service'
3
3
 
4
-
5
4
  module Restool
6
5
 
7
- def self.create(service_name, &response_handler)
8
- service_config = Restool::Settings::Loader.load(service_name)
6
+ def self.create(service_name, opts = {}, &response_handler)
7
+ service_config = Restool::Settings::Loader.load(service_name, opts)
9
8
 
10
9
  Restool::Service::RestoolService.new(service_config, response_handler)
11
10
  end
@@ -0,0 +1,7 @@
1
+ module Restool
2
+
3
+ class Error < StandardError
4
+ end
5
+
6
+
7
+ end
@@ -0,0 +1,55 @@
1
+ module Restool
2
+ class RequestLogger
3
+
4
+ def initialize(host, opts)
5
+ @host = host
6
+ @opts = opts
7
+ end
8
+
9
+ def log(request, &http_request)
10
+ log_request(request) if log?
11
+ response = http_request.call
12
+ log_response(response) if log?
13
+
14
+ response
15
+ rescue StandardError => e
16
+ log_error(e) if log?
17
+
18
+ raise
19
+ end
20
+
21
+ def logger
22
+ @opts[:logger]
23
+ end
24
+
25
+ def log?
26
+ if @opts[:log] != nil
27
+ @opts[:log]
28
+ else
29
+ @opts[:logger] != nil
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def log_request(request)
36
+ logger.info { "Restool Service #{@host}" }
37
+ logger.info { "#{request.method.upcase} #{request.path}" }
38
+ logger.info { "Headers: { #{format_hash(request.headers)} }" }
39
+ logger.debug { "Params: { #{format_hash(request.params)} }" }
40
+ end
41
+
42
+ def log_response(response)
43
+ logger.info { "Restool response (status #{response.code}):" }
44
+ logger.debug { response.body }
45
+ end
46
+
47
+ def log_error(error)
48
+ logger.error { "Restool error: #{error}" }
49
+ end
50
+
51
+ def format_hash(headers)
52
+ headers.map { |key, value| "#{key}: #{value}" }.join(", ")
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,32 @@
1
+ require_relative '../settings/loader'
2
+
3
+ module Restool
4
+ module Mock
5
+ def self.create(service_name, operation_responses)
6
+ @operation_responses = operation_responses
7
+ @service_config = Restool::Settings::Loader.load(service_name)
8
+
9
+ Service.new(@service_config, operation_responses)
10
+ end
11
+
12
+ private
13
+
14
+ class Service
15
+ def initialize(service_config, operation_responses)
16
+ @service_config = service_config
17
+ @operation_responses = operation_responses
18
+ end
19
+
20
+ def method_missing(method, *args, &block)
21
+ if @service_config.operations.map(&:name).include?(method)
22
+ operation_response = @operation_responses[method]
23
+ response_representation = @service_config.operation.response
24
+ representations = @service_config.representations
25
+
26
+ Restool::Traversal::Converter.convert(operation_response, response_representation, representations)
27
+ end
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ module Restool
2
+ class OperationRequest
3
+
4
+ attr_accessor :http_request, :method, :path, :params, :headers
5
+
6
+ def initialize(http_request, method, path, params, headers)
7
+ @http_request = http_request
8
+ @method = method
9
+ @path = path
10
+ @params = params
11
+ @headers = headers
12
+ end
13
+
14
+ end
15
+ end
@@ -1,45 +1,43 @@
1
- require 'persistent_http'
2
-
1
+ require "net/http"
2
+ require "net/https"
3
3
  require_relative 'request_utils'
4
+ require_relative '../logger/request_logger'
4
5
 
5
6
  module Restool
6
7
  module Service
7
8
  class RemoteClient
8
9
 
9
- def initialize(host, verify_ssl, persistent_connection, timeout)
10
- @connection = if persistent_connection
11
- PersistentHTTP.new(
12
- pool_size: persistent_connection.pool_size,
13
- pool_timeout: timeout,
14
- warn_timeout: persistent_connection.warn_timeout,
15
- force_retry: persistent_connection.force_retry,
16
- url: host,
17
- read_timeout: timeout,
18
- open_timeout: timeout,
19
- verify_mode: verify_ssl?(verify_ssl)
20
- )
21
- else
22
- uri = URI.parse(host)
23
- http = Net::HTTP.new(uri.host, uri.port)
24
- http.use_ssl = ssl_implied?(uri)
25
- http.verify_mode = verify_ssl?(verify_ssl)
26
- http.read_timeout = timeout
27
- http.open_timeout = timeout
28
- # http.set_debug_output($stdout)
29
- http
30
- end
10
+ def initialize(host, verify_ssl, timeout, opts)
11
+ @request_logger = Restool::RequestLogger.new(host, opts)
12
+ @connection = build_connection(host, verify_ssl, timeout, opts)
31
13
  end
32
14
 
33
15
  def make_request(path, method, request_params, headers, basic_auth)
34
- request = RequestUtils.build_request(method, path, request_params, headers, basic_auth)
35
-
36
- @connection.request(request)
16
+ operation_request = RequestUtils.build_request(method, path, request_params, headers, basic_auth)
17
+
18
+ @request_logger.log(operation_request) do
19
+ @connection.request(operation_request.http_request)
20
+ end
21
+ rescue Errno::ETIMEDOUT => e
22
+ raise Restool::TimeoutError, e
23
+ rescue Errno::EADDRNOTAVAIL, Errno::ECONNREFUSED, IOError, SocketError
24
+ raise Restool::ConnectionFailed, $ERROR_INFO
37
25
  end
38
26
 
39
27
  private
40
28
 
41
- def ssl_implied?(uri)
42
- uri.port == 443 || uri.scheme == 'https'
29
+ def build_connection(host, verify_ssl, timeout, opts)
30
+ uri = URI.parse(host)
31
+
32
+ connection = Net::HTTP.new(uri.host, uri.port)
33
+
34
+ connection.use_ssl = uri.is_a?(URI::HTTPS)
35
+ connection.verify_mode = verify_ssl?(verify_ssl)
36
+ connection.read_timeout = timeout
37
+ connection.open_timeout = timeout
38
+ connection.set_debug_output($stdout) if opts[:debug]
39
+
40
+ connection
43
41
  end
44
42
 
45
43
  def verify_ssl?(verify_ssl_setting)
@@ -1,3 +1,5 @@
1
+ require_relative 'operation_request'
2
+
1
3
  module Restool
2
4
  module Service
3
5
  module RequestUtils
@@ -23,7 +25,7 @@ module Restool
23
25
 
24
26
  headers.each { |k, v| request[k] = v } if headers
25
27
 
26
- request
28
+ OperationRequest.new(request, method, path, params, headers)
27
29
  end
28
30
 
29
31
  def self.build_base_request(method, path)
@@ -11,7 +11,7 @@ module Restool
11
11
  @service_config = service_config
12
12
  @response_handler = response_handler
13
13
  @remote_client = Restool::Service::RemoteClient.new(service_config.host, service_config.verify_ssl,
14
- service_config.persistent, service_config.timeout)
14
+ service_config.timeout, service_config.opts)
15
15
 
16
16
  define_operations(
17
17
  @service_config, method(:make_request), method(:make_request_with_uri_params)
@@ -11,37 +11,28 @@ module Restool
11
11
  DEFAULT_SSL_VERIFY = false
12
12
 
13
13
 
14
- def self.load(service_name)
14
+ def self.load(service_name, opts)
15
15
  service_config = config['services'].detect do |service|
16
- service['name'] == service_name
16
+ service['name'] == service_name.to_s
17
17
  end
18
18
 
19
19
  raise "Service #{service_name} not found in configuration" unless service_config
20
20
 
21
- build_service(service_config)
21
+ build_service(service_config, opts)
22
22
  end
23
23
 
24
24
  private
25
25
 
26
- def self.build_service(service_config)
26
+ def self.build_service(service_config, opts)
27
27
  representations = if service_config['representations']
28
28
  build_representations(service_config['representations'])
29
29
  else
30
30
  []
31
31
  end
32
32
 
33
- basic_auth = service_config['basic_auth'] || service_config['basic_authentication']
33
+ basic_auth = opts['basic_auth'] || opts['basic_authentication'] || service_config['basic_auth'] || service_config['basic_authentication']
34
34
  basic_auth = BasicAuthentication.new(basic_auth['user'], basic_auth['password']) if basic_auth
35
35
 
36
- persistent_connection = service_config['persistent']
37
- persistent_connection = if persistent_connection
38
- PersistentConnection.new(
39
- persistent_connection['pool_size'],
40
- persistent_connection['warn_timeout'],
41
- persistent_connection['force_retry'],
42
- )
43
- end
44
-
45
36
  # Support host + common path in url config, e.g. api.com/v2/
46
37
  paths_prefix_in_host = URI(service_config['url']).path
47
38
 
@@ -49,11 +40,11 @@ module Restool
49
40
  service_config['name'],
50
41
  service_config['url'],
51
42
  service_config['operations'].map { |operation| build_operation(operation, paths_prefix_in_host) },
52
- persistent_connection,
53
43
  service_config['timeout'] || DEFAULT_TIMEOUT,
54
44
  representations,
55
45
  basic_auth,
56
- service_config['ssl_verify'] || DEFAULT_SSL_VERIFY
46
+ service_config['ssl_verify'] || DEFAULT_SSL_VERIFY,
47
+ opts
57
48
  )
58
49
  end
59
50
 
@@ -105,7 +96,7 @@ module Restool
105
96
  def self.config
106
97
  return @config if @config
107
98
 
108
- files_to_load = Dir['config/restool/*'] + ['config/restool.yml', 'config/restool.json']
99
+ files_to_load = Dir['config/restool/*.yml'] + Dir['config/restool/*.yaml'] + ['config/restool.yml', 'config/restool.yaml', 'config/restool.json']
109
100
 
110
101
  @config = { 'services' => [] }
111
102
 
@@ -114,12 +105,12 @@ module Restool
114
105
 
115
106
  extension = File.extname(file_name)
116
107
 
117
- content = if extension == '.yml'
118
- YAML.load_file(file_name)
119
- elsif extension == '.json'
120
- json_file = File.read(file_name)
121
- JSON.parse(json_file)
122
- end
108
+ content = if extension == '.yml' || extension == '.yaml'
109
+ YAML.load_file(file_name)
110
+ elsif extension == '.json'
111
+ json_file = File.read(file_name)
112
+ JSON.parse(json_file)
113
+ end
123
114
 
124
115
  @config['services'] += content['services']
125
116
  end
@@ -127,10 +118,6 @@ module Restool
127
118
  @config
128
119
  end
129
120
 
130
- def self.validate
131
- # TODO: perform validations
132
- end
133
-
134
121
  end
135
122
  end
136
123
  end
@@ -4,11 +4,10 @@ module Restool
4
4
 
5
5
  Operation = Struct.new(:name, :path, :method, :uri_params, :response)
6
6
  OperationResponse = Struct.new(:fields)
7
- Service = Struct.new(:name, :host, :operations, :persistent, :timeout, :representations, :basic_auth, :verify_ssl)
7
+ Service = Struct.new(:name, :host, :operations, :timeout, :representations, :basic_auth, :verify_ssl, :opts)
8
8
  Representation = Struct.new(:name, :fields)
9
9
  RepresentationField = Struct.new(:key, :metonym, :type)
10
10
  BasicAuthentication = Struct.new(:user, :password)
11
- PersistentConnection = Struct.new(:respool_size, :want_timeout, :force_retry)
12
11
  OperationResponsField = RepresentationField
13
12
 
14
13
  end
@@ -19,6 +19,9 @@ module Restool
19
19
  def self.convert(request_response, response_representation, representations)
20
20
  object = Restool::Traversal::Object.new
21
21
 
22
+ object.class.__send__(:attr_accessor, :_raw)
23
+ object.__send__("_raw=", request_response)
24
+
22
25
  if request_response.is_a?(Array)
23
26
  request_response.map do |element|
24
27
  map_response_to_representation(response_representation, element, object, representations)
@@ -32,15 +35,15 @@ module Restool
32
35
 
33
36
  def self.map_response_to_representation(representation, request_response, object, representations)
34
37
  representation.fields.each do |field|
35
- value = request_response[field.key]
38
+ value = request_response[field.key.to_s] || request_response[field.key.to_sym]
39
+
40
+ object.class.__send__(:attr_accessor, var_name(field))
36
41
 
37
42
  if value.nil?
38
43
  set_var(object, field, nil)
39
44
  next
40
45
  end
41
46
 
42
- object.class.__send__(:attr_accessor, var_name(field))
43
-
44
47
  if Restool::Traversal::TRAVERSAL_TYPES.include?(field.type.to_sym)
45
48
  map_primitive_field(value, field, object)
46
49
  else
@@ -1,17 +1,5 @@
1
1
  module Restool
2
2
  module Traversal
3
- class Object
4
-
5
- def to_hash
6
- instance_variables
7
- .inject({}) do |acum, var|
8
- acum[var.to_s.delete('@')] = instance_variable_get(var)
9
- acum
10
- end
11
- end
12
-
13
- alias_method :to_h, :to_hash
14
-
15
- end
3
+ class Object; end
16
4
  end
17
5
  end
@@ -1,3 +1,3 @@
1
1
  module Restool
2
- VERSION = '0.1.4'
2
+ VERSION = '1.0.2'
3
3
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Andres Zeni
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-20 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: persistent_http
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '2'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '2'
11
+ date: 2020-11-28 00:00:00.000000000 Z
12
+ dependencies: []
27
13
  description: Make HTTP requests and handle its responses using simple method calls.
28
14
  Restool turns your HTTP API and its responses into Ruby interfaces.
29
15
  email:
@@ -33,7 +19,11 @@ extensions: []
33
19
  extra_rdoc_files: []
34
20
  files:
35
21
  - lib/restool.rb
22
+ - lib/restool/errors.rb
23
+ - lib/restool/logger/request_logger.rb
24
+ - lib/restool/mock/restool.rb
36
25
  - lib/restool/service/operation_definer.rb
26
+ - lib/restool/service/operation_request.rb
37
27
  - lib/restool/service/remote_client.rb
38
28
  - lib/restool/service/remote_connector.rb
39
29
  - lib/restool/service/request_utils.rb
@@ -48,7 +38,7 @@ homepage: https://github.com/jzeni/restool
48
38
  licenses:
49
39
  - MIT
50
40
  metadata: {}
51
- post_install_message:
41
+ post_install_message:
52
42
  rdoc_options: []
53
43
  require_paths:
54
44
  - lib
@@ -63,8 +53,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
53
  - !ruby/object:Gem::Version
64
54
  version: '0'
65
55
  requirements: []
66
- rubygems_version: 3.0.1
67
- signing_key:
56
+ rubygems_version: 3.2.0.rc.1
57
+ signing_key:
68
58
  specification_version: 4
69
59
  summary: Turn your API and its responses into Ruby interfaces.
70
60
  test_files: []