api_recipes 0.7.1 → 2.6.2

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.
@@ -1,8 +1,8 @@
1
1
  module ApiRecipes
2
2
 
3
- class EndpointNameClashError < Exception
3
+ class ApiNameClashError < Exception
4
4
  def initialize(object, endpoint_name)
5
- message = "#{object.class} already defines a method called '#{endpoint_name}'. Tip: change endpoint name"
5
+ message = "#{object.class} already defines a method called '#{endpoint_name}'. Tip: change api name"
6
6
  super(message)
7
7
  end
8
8
  end
@@ -15,34 +15,38 @@ module ApiRecipes
15
15
  end
16
16
 
17
17
  class MissingRouteAttribute < Exception
18
- attr_reader :resource, :route, :attribute
18
+ def initialize(endpoint = nil, route = nil, attribute = nil)
19
+ message = "route '#{endpoint}.#{route}' requires '#{attribute}' attribute but this was not provided"
20
+ super(message)
21
+ end
22
+ end
19
23
 
20
- def initialize(message = nil, resource = nil, route = nil, attribute = nil)
21
- @resource = resource; @route = route; @attribute = attribute
22
- if message
23
- # Nothing to do
24
- elsif @route && @attribute
25
- message = "route '#{@resource}.#{@route}' requires '#{@attribute}' attribute but this was not given"
24
+ class PathParamsMismatch < Exception
25
+ def initialize(path, expected_params, provided_params)
26
+ if expected_params.size == 0
27
+ message = "route '#{path}' requires NO PARAMS but #{provided_params} were provided"
28
+ else
29
+ message = "route '#{path}' requires params #{expected_params} but #{provided_params} were provided"
26
30
  end
27
31
  super(message)
28
32
  end
29
33
  end
30
34
 
31
- class ResponseCodeNotAsExpected < Exception
32
- attr_reader :resource, :route, :expected_code, :response_code, :response_body
35
+ class ProvidedObjectNotAsResponseData < Exception
36
+ def initialize(object_class, data_class)
37
+ message = "provided object #{object_class} is not compatible with response data that is of type #{data_class}"
38
+ super(message)
39
+ end
40
+ end
33
41
 
34
- def initialize(message = nil, resource = nil, route = nil, expected_code = nil, response_code = nil, response_body = nil)
35
- @resource = resource; @route = route; @expected_code = expected_code; @response_code = response_code; @response_body = response_body
36
- if message
37
- # Nothing to do
38
- else
39
- message = "response code for request on route '#{@resource}.#{@route}' has returned #{@response_code}, but #{@expected_code} was expected. Reason: #{@response_body}"
40
- end
42
+ class ResponseCodeNotAsExpected < Exception
43
+ def initialize(path, expected_code = nil, response_code = nil, response_body = nil)
44
+ message = "response code for request on route '#{path}' has returned #{response_code}, but #{expected_code} was expected\n\nResponse body:\n #{response_body}"
41
45
  super(message)
42
46
  end
43
47
  end
44
48
 
45
- class EndpointConfigIsNotAnHash < Exception
49
+ class ApiConfigIsNotAnHash < Exception
46
50
  def initialize(endpoint)
47
51
  message = "provided config for endpoint '#{endpoint}' must be an Hash"
48
52
  super(message)
@@ -64,11 +68,15 @@ module ApiRecipes
64
68
  end
65
69
 
66
70
  class RouteNameClashWithExistentMethod < Exception
67
- attr_reader :resource, :route
71
+ def initialize(endpoint_name, route_name)
72
+ message = "can't define route '#{route_name}' method in endpoint '#{endpoint_name}' because method '#{route_name}' has already been defined"
73
+ super(message)
74
+ end
75
+ end
68
76
 
69
- def initialize(resource, route)
70
- @resource = resource; @route = route
71
- message = "can't define route '#{@route}' method in resource '#{@resource}' because method '#{@route}' already exists"
77
+ class NoRouteExists < Exception
78
+ def initialize(endpoint_name)
79
+ message = "no route defined on #{endpoint_name}"
72
80
  super(message)
73
81
  end
74
82
  end
@@ -0,0 +1,22 @@
1
+ module ApiRecipes
2
+ class Response
3
+
4
+ attr_reader :original_response
5
+
6
+ def initialize(response, attributes = {})
7
+ @original_response = response
8
+ @attributes = attributes
9
+ end
10
+
11
+ def data
12
+ return @data unless @data.nil?
13
+
14
+ @data = @original_response.parse
15
+ end
16
+
17
+ # Forward method calls to 'original' Response class
18
+ def method_missing(symbol, *args, &block)
19
+ @original_response.send symbol,* args, &block
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,156 @@
1
+ module ApiRecipes
2
+ class Route
3
+
4
+ attr_reader :request, :response, :url
5
+ attr_accessor :request_params, :attributes, :path
6
+
7
+ def initialize(api: nil, endpoint: nil, path: nil, attributes: {}, req_pars: {})
8
+ @api = api
9
+ @endpoint = endpoint
10
+ @path = path.to_s
11
+ @attributes = attributes
12
+ self.request_params = req_pars
13
+ @url = nil
14
+
15
+ prepare_request
16
+ end
17
+
18
+ def fill(object)
19
+ data = @response.parse
20
+ if block_given?
21
+ tap do
22
+ try_to_fill object, data
23
+ yield object, data, @response.status
24
+ end
25
+ else
26
+ try_to_fill object, data
27
+ end
28
+ end
29
+
30
+ def start_request(&block)
31
+ original_response = @request.send http_verb, @url, request_params
32
+ @response = Response.new original_response, attributes
33
+ check_response_code
34
+
35
+ if block_given?
36
+ tap { block.call @response }
37
+ else
38
+ response
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def build_url_from_path
45
+ attrs = {
46
+ scheme: settings[:protocol],
47
+ host: settings[:host],
48
+ port: port,
49
+ path: path
50
+ }
51
+ URI::Generic.build2 attrs
52
+ end
53
+
54
+ def check_response_code
55
+ # If :ok_code property is present, check the response code
56
+ ok_code = false
57
+ code = @response.code
58
+ if expected_code = attributes[:ok_code]
59
+ # If the code does not match, apply the requested strategy
60
+ ok_code = true if code == expected_code
61
+ else
62
+ # Default: 200 <= OK < 300
63
+ ok_code = true if (code >= 200 && code < 300)
64
+ expected_code = '200 <= CODE < 300'
65
+ end
66
+ unless ok_code
67
+ case attributes[:on_bad_code].to_s
68
+ when 'ignore'
69
+ when 'raise'
70
+ raise ResponseCodeNotAsExpected.new(path, expected_code, code, @response.body)
71
+ end
72
+ end
73
+ end
74
+
75
+ def extract_headers
76
+ settings[:default_headers] || {}
77
+ end
78
+
79
+ def timeout
80
+ attributes.fetch(:timeout, ApiRecipes::Settings::GLOBAL_TIMEOUT)
81
+ end
82
+
83
+ def port
84
+ settings[:port] || case settings[:protocol]
85
+ when 'http'
86
+ 80
87
+ when 'https'
88
+ 443
89
+ end
90
+ end
91
+
92
+ def prepare_request
93
+ @url = build_url_from_path
94
+ puts @url if ApiRecipes.configuration.print_urls
95
+
96
+ @request = request_with_auth
97
+ end
98
+
99
+ def request_params=(params)
100
+ unless params.is_a? Hash
101
+ raise ArgumentError, 'provided params must be an Hash'
102
+ end
103
+ # Merge route attributes with defaults and deep clone route attributes
104
+ @request_params = params
105
+ end
106
+
107
+ def request_with_auth
108
+ req = HTTP
109
+ req = req.headers(extract_headers)
110
+ .timeout(timeout)
111
+
112
+ basic_auth = @api.basic_auth
113
+ if basic_auth
114
+ req = req.basic_auth basic_auth
115
+ end
116
+ authorization = @api.authorization
117
+ if authorization
118
+ req = req.auth authorization
119
+ end
120
+ req
121
+ end
122
+
123
+ def settings
124
+ @api.configs
125
+ end
126
+
127
+ def try_to_fill(object, data)
128
+ case data
129
+ when Hash
130
+ res = fill_object_with object, data
131
+ when Array
132
+ res = []
133
+ data.each do |element|
134
+ res << fill_object_with(object.new, element)
135
+ end
136
+ end
137
+
138
+ res
139
+ end
140
+
141
+ def fill_object_with(object, data)
142
+ data.each do |key, value|
143
+ begin
144
+ object.send "#{key}=", value
145
+ rescue
146
+ end
147
+ end
148
+
149
+ object
150
+ end
151
+
152
+ def http_verb
153
+ attributes[:verb]
154
+ end
155
+ end
156
+ end
@@ -1,21 +1,24 @@
1
1
  module ApiRecipes
2
2
  module Settings
3
3
  GLOBAL_TIMEOUT = 1
4
- FAIL_OPTIONS = [:return, :raise, :return_false]
5
4
 
6
5
  DEFAULT = {
7
6
  protocol: 'https',
8
7
  host: 'localhost',
9
8
  port: nil,
10
- base_path: '',
11
- api_version: '',
9
+ base_url: nil,
12
10
  timeout: 3,
13
- on_nok_code: :raise,
14
- routes: {}
11
+ on_bad_code: 'raise',
12
+ endpoints: {}
15
13
  }
16
14
 
17
15
  DEFAULT_ROUTE_ATTRIBUTES = {
18
- method: :get
16
+ verb: :get,
17
+ route: 'yes',
18
+ path: nil,
19
+ ok_code: nil,
20
+ timeout: DEFAULT[:timeout],
21
+ on_bad_code: DEFAULT[:on_bad_code]
19
22
  }
20
23
 
21
24
  AVAILABLE_PARAMS_ENCODINGS = %w(form params json body)
@@ -1,3 +1,3 @@
1
1
  module ApiRecipes
2
- VERSION = '0.7.1'
2
+ VERSION = '2.6.2'.freeze
3
3
  end
metadata CHANGED
@@ -1,77 +1,45 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api_recipes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 2.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Verlato
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-15 00:00:00.000000000 Z
11
+ date: 2020-11-25 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: oj
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: 3.7.0
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: 3.7.0
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: http
29
15
  requirement: !ruby/object:Gem::Requirement
30
16
  requirements:
31
17
  - - "~>"
32
18
  - !ruby/object:Gem::Version
33
- version: 4.1.1
19
+ version: 4.4.1
34
20
  type: :runtime
35
21
  prerelease: false
36
22
  version_requirements: !ruby/object:Gem::Requirement
37
23
  requirements:
38
24
  - - "~>"
39
25
  - !ruby/object:Gem::Version
40
- version: 4.1.1
41
- description:
26
+ version: 4.4.1
27
+ description:
42
28
  email:
43
29
  - averlato@gmail.com
44
30
  executables: []
45
31
  extensions: []
46
32
  extra_rdoc_files: []
47
33
  files:
48
- - ".gitignore"
49
- - ".rspec"
50
- - ".travis.yml"
51
- - CHANGELOG.md
52
- - CODE_OF_CONDUCT.md
53
- - Gemfile
54
- - Guardfile
55
- - LICENSE.txt
34
+ - MIT-LICENSE
56
35
  - README.md
57
- - Rakefile
58
- - api_recipes.gemspec
59
- - api_recipes.png
60
- - bin/console
61
- - bin/setup
62
- - examples/authorization.rb
63
- - examples/authorization_with_default_headers.rb
64
- - examples/basic_auth.rb
65
- - examples/config/apis.yml
66
- - examples/custom_configs.rb
67
- - examples/delete_me.rb
68
- - examples/multiple_endpoints.rb
69
- - examples/simple_usage.rb
70
36
  - lib/api_recipes.rb
37
+ - lib/api_recipes/api.rb
71
38
  - lib/api_recipes/configuration.rb
72
39
  - lib/api_recipes/endpoint.rb
73
40
  - lib/api_recipes/exceptions.rb
74
- - lib/api_recipes/resource.rb
41
+ - lib/api_recipes/response.rb
42
+ - lib/api_recipes/route.rb
75
43
  - lib/api_recipes/settings.rb
76
44
  - lib/api_recipes/utils.rb
77
45
  - lib/api_recipes/version.rb
@@ -79,24 +47,23 @@ homepage: https://github.com/madAle/api_recipes
79
47
  licenses:
80
48
  - MIT
81
49
  metadata: {}
82
- post_install_message:
50
+ post_install_message:
83
51
  rdoc_options: []
84
52
  require_paths:
85
53
  - lib
86
54
  required_ruby_version: !ruby/object:Gem::Requirement
87
55
  requirements:
88
- - - ">"
56
+ - - ">="
89
57
  - !ruby/object:Gem::Version
90
- version: 2.2.0
58
+ version: 2.5.0
91
59
  required_rubygems_version: !ruby/object:Gem::Requirement
92
60
  requirements:
93
61
  - - ">="
94
62
  - !ruby/object:Gem::Version
95
63
  version: '0'
96
64
  requirements: []
97
- rubyforge_project:
98
- rubygems_version: 2.7.9
99
- signing_key:
65
+ rubygems_version: 3.0.8
66
+ signing_key:
100
67
  specification_version: 4
101
68
  summary: Consume HTTP APIs with style
102
69
  test_files: []
data/.gitignore DELETED
@@ -1,16 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
- *.orig
11
- .idea
12
- .rvmrc
13
- .ruby-version
14
- .ruby-gemset
15
- .DS_Store
16
- *.gem
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --format documentation
2
- --color
@@ -1,10 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 1.9.3
4
- - 2.0.0
5
- - 2.1.0
6
- - 2.2.0
7
- - 2.2.3
8
- notifications:
9
- email: false
10
- bundler_args: --without development