restool 0.1.4 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 584d88793980824115720aa0e0f037d0fae8c35439c4e24e16e33dc902b11e8b
4
- data.tar.gz: 7adca6d17ead07b51bbe097b273e655e5ff34d365bbc95ffb33620e70588cffa
3
+ metadata.gz: b50f0e2b71d71c4cc51b17cca04939e16bbae2aa1c8ad30332d9ec93bfe8d2a3
4
+ data.tar.gz: f854bbe253e0b519df1d4fbc8354bef2a1905bb8ef2410f16fcb3d783cc65079
5
5
  SHA512:
6
- metadata.gz: 0b93df06284266885ce45b9e83849a7125ed2d0f4bd82a236b5ea751aaa7860136aeaad9f248dd3ad5d6ab21d3948469a82973cbe0a19812a578d57cb43d4c55
7
- data.tar.gz: d1a7b15cfc046896fc3b57d9092c1ffe33f50d21a1d8645327b68b7a28259b3e47ee9349e74115d77028c5b02cbf26607c995a4f9c9db0e6b2f7e02796d30bbb
6
+ metadata.gz: ac1c66d272cb7bd3c76f9697f0d8f8b1d5095e29202275b625b0e811155e1d24f2f411ff2d419008fb894e3b005377a5d9e000b75d32618c55636887f5888bd4
7
+ data.tar.gz: 53cffe026ac8a0134b5e6e3d46c5d2f3a3ec99c50d1583d6af4b79bbcbc3701f1778d4a94a6a079cd61f0981704a21b26bf59d925c65096d08fe3ba54085b83f
@@ -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,47 @@
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
+ end
16
+
17
+ def logger
18
+ @opts[:logger]
19
+ end
20
+
21
+ def log?
22
+ if @opts[:log] != nil
23
+ @opts[:log]
24
+ else
25
+ @opts[:logger] != nil
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def log_request(request)
32
+ logger.info { "Restool Service #{@host}" }
33
+ logger.info { "#{request.method.upcase} #{request.path}" }
34
+ logger.info { format_hash(request.headers) }
35
+ logger.debug { format_hash(request.params) }
36
+ end
37
+
38
+ def log_response(response)
39
+ logger.info { "Restool response (status #{response.code})" }
40
+ logger.debug { response.body }
41
+ end
42
+
43
+ def format_hash(headers)
44
+ headers.map { |key, value| "#{key}: #{value}" }.join(", ")
45
+ end
46
+ end
47
+ 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,39 @@
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)
16
+ operation_request = RequestUtils.build_request(method, path, request_params, headers, basic_auth)
35
17
 
36
- @connection.request(request)
18
+ @request_logger.log(operation_request) do
19
+ @connection.request(operation_request.http_request)
20
+ end
37
21
  end
38
22
 
39
23
  private
40
24
 
41
- def ssl_implied?(uri)
42
- uri.port == 443 || uri.scheme == 'https'
25
+ def build_connection(host, verify_ssl, timeout, opts)
26
+ uri = URI.parse(host)
27
+
28
+ connection = Net::HTTP.new(uri.host, uri.port)
29
+
30
+ connection.use_ssl = uri.is_a?(URI::HTTPS)
31
+ connection.verify_mode = verify_ssl?(verify_ssl)
32
+ connection.read_timeout = timeout
33
+ connection.open_timeout = timeout
34
+ connection.set_debug_output($stdout) if opts[:debug]
35
+
36
+ connection
43
37
  end
44
38
 
45
39
  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.1'
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.1
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-09-13 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,10 @@ extensions: []
33
19
  extra_rdoc_files: []
34
20
  files:
35
21
  - lib/restool.rb
22
+ - lib/restool/logger/request_logger.rb
23
+ - lib/restool/mock/restool.rb
36
24
  - lib/restool/service/operation_definer.rb
25
+ - lib/restool/service/operation_request.rb
37
26
  - lib/restool/service/remote_client.rb
38
27
  - lib/restool/service/remote_connector.rb
39
28
  - lib/restool/service/request_utils.rb
@@ -48,7 +37,7 @@ homepage: https://github.com/jzeni/restool
48
37
  licenses:
49
38
  - MIT
50
39
  metadata: {}
51
- post_install_message:
40
+ post_install_message:
52
41
  rdoc_options: []
53
42
  require_paths:
54
43
  - lib
@@ -64,7 +53,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
64
53
  version: '0'
65
54
  requirements: []
66
55
  rubygems_version: 3.0.1
67
- signing_key:
56
+ signing_key:
68
57
  specification_version: 4
69
58
  summary: Turn your API and its responses into Ruby interfaces.
70
59
  test_files: []