api_recipes 0.7.1 → 2.6.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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