api_recipes 0.6.1 → 2.5.0

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,58 +1,54 @@
1
1
  module ApiRecipes
2
- class RouteNameClashError < Exception
3
- attr_reader :route, :resource
4
2
 
5
- def initialize(message = nil, route = nil, resource = nil)
6
- @route = route; @resource = resource
7
- if message
8
- # Nothing to do
9
- elsif route
10
- message = "route name (#{@route}) can't be equal to resource name (#{@resource}). Please change route or resource name."
11
- else
12
- message = "route name can't be equal to resource name. Please change route or resource names."
13
- end
3
+ class ApiNameClashError < Exception
4
+ def initialize(object, endpoint_name)
5
+ message = "#{object.class} already defines a method called '#{endpoint_name}'. Tip: change api name"
14
6
  super(message)
15
7
  end
16
8
  end
17
9
 
18
- class MissingRouteAttribute < Exception
19
- attr_reader :resource, :route, :attribute
20
-
21
- def initialize(message = nil, resource = nil, route = nil, attribute = nil)
22
- @resource = resource; @route = route; @attribute = attribute
23
- if message
24
- # Nothing to do
25
- elsif @route && @attribute
26
- message = "route '#{@resource}.#{@route}' requires '#{@attribute}' attribute but this was not given"
27
- end
10
+ class RouteAndResourceNamesClashError < Exception
11
+ def initialize(route_name, resource_name)
12
+ message = "route name (#{route_name}) can't be equal to resource name (#{resource_name}). Please change route or resource name."
28
13
  super(message)
29
14
  end
30
15
  end
31
16
 
32
- class ResponseCodeNotAsExpected < Exception
33
- attr_reader :resource, :route, :expected_code, :response_code, :response_body
17
+ class MissingRouteAttribute < Exception
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
34
23
 
35
- def initialize(message = nil, resource = nil, route = nil, expected_code = nil, response_code = nil, response_body = nil)
36
- @resource = resource; @route = route; @expected_code = expected_code; @response_code = response_code; @response_body = response_body
37
- if message
38
- # Nothing to do
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"
39
28
  else
40
- message = "response code for request on route '#{@resource}.#{@route}' has returned #{@response_code}, but #{@expected_code} was expected. Reason: #{@response_body}"
29
+ message = "route '#{path}' requires params #{expected_params} but #{provided_params} were provided"
41
30
  end
42
31
  super(message)
43
32
  end
44
33
  end
45
34
 
46
- class EndpointConfigIsNotAnHash < Exception
47
- attr_reader :endpoint
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
48
41
 
49
- def initialize(message = nil, endpoint = nil)
50
- @endpoint = endpoint
51
- if message
52
- # Nothing to do
53
- else
54
- message = "provided config for endpoint '#{@endpoint}' must be an Hash"
55
- 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}"
45
+ super(message)
46
+ end
47
+ end
48
+
49
+ class ApiConfigIsNotAnHash < Exception
50
+ def initialize(endpoint)
51
+ message = "provided config for endpoint '#{endpoint}' must be an Hash"
56
52
  super(message)
57
53
  end
58
54
  end
@@ -72,11 +68,15 @@ module ApiRecipes
72
68
  end
73
69
 
74
70
  class RouteNameClashWithExistentMethod < Exception
75
- 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
76
76
 
77
- def initialize(resource, route)
78
- @resource = resource; @route = route
79
- 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}"
80
80
  super(message)
81
81
  end
82
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,158 @@
1
+ module ApiRecipes
2
+ class Route
3
+
4
+ attr_reader :request, :response
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
+ @uri = 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, @uri, 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_uri_from_path
45
+ attrs = {
46
+ scheme: settings[:protocol],
47
+ host: settings[:host],
48
+ port: port,
49
+ path: path
50
+ }
51
+ URI::Generic.build 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
+ when 'return_false'
72
+ return false
73
+ end
74
+ end
75
+ end
76
+
77
+ def extract_headers
78
+ settings[:default_headers] || {}
79
+ end
80
+
81
+ def timeout
82
+ attributes.fetch(:timeout, ApiRecipes::Settings::GLOBAL_TIMEOUT)
83
+ end
84
+
85
+ def port
86
+ settings[:port] || case settings[:protocol]
87
+ when 'http'
88
+ 80
89
+ when 'https'
90
+ 443
91
+ end
92
+ end
93
+
94
+ def prepare_request
95
+ @uri = build_uri_from_path
96
+ puts @uri if ApiRecipes.print_urls
97
+
98
+ @request = request_with_auth
99
+ end
100
+
101
+ def request_params=(params)
102
+ unless params.is_a? Hash
103
+ raise ArgumentError, 'provided params must be an Hash'
104
+ end
105
+ # Merge route attributes with defaults and deep clone route attributes
106
+ @request_params = params
107
+ end
108
+
109
+ def request_with_auth
110
+ req = HTTP
111
+ req = req.headers(extract_headers)
112
+ .timeout(timeout)
113
+
114
+ basic_auth = @api.basic_auth
115
+ if basic_auth
116
+ req = req.basic_auth basic_auth
117
+ end
118
+ authorization = @api.authorization
119
+ if authorization
120
+ req = req.auth authorization
121
+ end
122
+ req
123
+ end
124
+
125
+ def settings
126
+ @api.configs
127
+ end
128
+
129
+ def try_to_fill(object, data)
130
+ case data
131
+ when Hash
132
+ res = fill_object_with object, data
133
+ when Array
134
+ res = []
135
+ data.each do |element|
136
+ res << fill_object_with(object.new, element)
137
+ end
138
+ end
139
+
140
+ res
141
+ end
142
+
143
+ def fill_object_with(object, data)
144
+ data.each do |key, value|
145
+ begin
146
+ object.send "#{key}=", value
147
+ rescue
148
+ end
149
+ end
150
+
151
+ object
152
+ end
153
+
154
+ def http_verb
155
+ attributes[:verb]
156
+ end
157
+ end
158
+ 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.6.1'
2
+ VERSION = '2.5.0'.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.6.1
4
+ version: 2.5.0
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-06-27 00:00:00.000000000 Z
11
+ date: 2020-09-30 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.5.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.5.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: 2.0.3
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: 2.0.3
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,7 +47,7 @@ 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
@@ -87,16 +55,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
87
55
  requirements:
88
56
  - - ">="
89
57
  - !ruby/object:Gem::Version
90
- version: 2.1.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
+ rubyforge_project:
66
+ rubygems_version: 2.7.7
67
+ signing_key:
100
68
  specification_version: 4
101
69
  summary: Consume HTTP APIs with style
102
70
  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