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.
- checksums.yaml +4 -4
- data/{LICENSE.txt → MIT-LICENSE} +0 -0
- data/README.md +2 -2
- data/lib/api_recipes.rb +61 -61
- data/lib/api_recipes/api.rb +70 -0
- data/lib/api_recipes/configuration.rb +9 -9
- data/lib/api_recipes/endpoint.rb +109 -30
- data/lib/api_recipes/exceptions.rb +31 -23
- data/lib/api_recipes/response.rb +22 -0
- data/lib/api_recipes/route.rb +156 -0
- data/lib/api_recipes/settings.rb +9 -6
- data/lib/api_recipes/version.rb +1 -1
- metadata +15 -48
- data/.gitignore +0 -16
- data/.rspec +0 -2
- data/.travis.yml +0 -10
- data/CHANGELOG.md +0 -15
- data/CODE_OF_CONDUCT.md +0 -13
- data/Gemfile +0 -12
- data/Guardfile +0 -14
- data/Rakefile +0 -6
- data/api_recipes.gemspec +0 -23
- data/api_recipes.png +0 -0
- data/bin/console +0 -14
- data/bin/setup +0 -7
- data/examples/authorization.rb +0 -42
- data/examples/authorization_with_default_headers.rb +0 -41
- data/examples/basic_auth.rb +0 -32
- data/examples/config/apis.yml +0 -43
- data/examples/custom_configs.rb +0 -51
- data/examples/delete_me.rb +0 -21
- data/examples/multiple_endpoints.rb +0 -54
- data/examples/simple_usage.rb +0 -38
- data/lib/api_recipes/resource.rb +0 -157
@@ -1,8 +1,8 @@
|
|
1
1
|
module ApiRecipes
|
2
2
|
|
3
|
-
class
|
3
|
+
class ApiNameClashError < Exception
|
4
4
|
def initialize(object, endpoint_name)
|
5
|
-
message = "#{object.class} already defines a method called '#{endpoint_name}'. Tip: change
|
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
|
-
|
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
|
-
|
21
|
-
|
22
|
-
if
|
23
|
-
#
|
24
|
-
|
25
|
-
message = "route '#{
|
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
|
32
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
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
|
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
|
-
|
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
|
-
|
70
|
-
|
71
|
-
message = "
|
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
|
data/lib/api_recipes/settings.rb
CHANGED
@@ -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
|
-
|
11
|
-
api_version: '',
|
9
|
+
base_url: nil,
|
12
10
|
timeout: 3,
|
13
|
-
|
14
|
-
|
11
|
+
on_bad_code: 'raise',
|
12
|
+
endpoints: {}
|
15
13
|
}
|
16
14
|
|
17
15
|
DEFAULT_ROUTE_ATTRIBUTES = {
|
18
|
-
|
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)
|
data/lib/api_recipes/version.rb
CHANGED
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:
|
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:
|
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.
|
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.
|
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
|
-
-
|
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/
|
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.
|
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
|
-
|
98
|
-
|
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
data/.rspec
DELETED