api_recipes 0.6.2 → 2.6.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,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.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
+ 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.6.2'
2
+ VERSION = '2.6.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.2
4
+ version: 2.6.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-10-22 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,15 @@ 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
+ rubygems_version: 3.1.4
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