diesel-api-dsl 0.1.3 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +4 -0
- data/diesel.gemspec +1 -1
- data/lib/diesel/api_builder.rb +82 -32
- data/lib/diesel/api_group.rb +3 -2
- data/lib/diesel/middleware/auth/api_key.rb +13 -1
- data/lib/diesel/middleware/auth/basic.rb +27 -0
- data/lib/diesel/middleware/auth/oauth2.rb +2 -2
- data/lib/diesel/middleware/convert_json_body.rb +15 -0
- data/lib/diesel/middleware/set_body_parameter.rb +5 -1
- data/lib/diesel/middleware/set_path_parameter.rb +2 -1
- data/lib/diesel/request_context.rb +7 -1
- data/lib/diesel/swagger/definition.rb +1 -1
- data/lib/diesel/swagger/operation.rb +3 -1
- data/lib/diesel/swagger/parser.rb +25 -9
- data/lib/diesel/uri.rb +36 -0
- data/lib/diesel/version.rb +1 -1
- data/spec/diesel/api_builder_spec.rb +9 -3
- data/spec/diesel/swagger/parser_spec.rb +14 -0
- data/spec/diesel_spec.rb +173 -56
- data/spec/files/github.json +186 -0
- data/spec/files/harvest.json +75 -0
- data/spec/files/mandrill.json +502 -0
- data/spec/files/uber.json +43 -0
- data/spec/fixtures/vcr_cassettes/github_checkAuthorization.yml +71 -0
- data/spec/fixtures/vcr_cassettes/github_getUser.yml +82 -0
- data/spec/fixtures/vcr_cassettes/harvest_invoiceList.yml +85 -0
- data/spec/fixtures/vcr_cassettes/mandrill_userPing.yml +44 -0
- data/spec/fixtures/vcr_cassettes/uber_getProducts.yml +60 -0
- data/spec/spec_helper.rb +1 -0
- metadata +28 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78e75164894839881d3adf47cef1575c25970140
|
4
|
+
data.tar.gz: 3ac675a70ef2bf4373a1e4a1b1601a68f8daaa65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eceaffc1b439c45851509eb72f4f1e109a16c01b7a8901c104f8c023818f337a43875ef40f77e273d9eb14f8f0fbb99049e0986853a07cfe3c7d3c6720981771
|
7
|
+
data.tar.gz: b7be5c3cfdb6bf224263dc13c02f3f0aeab75af8574364a0d9f44133ff3f6a1a77fd20f9d39a86ae060b988c5c5ae96dc717fa0eba3fa5303f5b72300f4be4cb
|
data/Gemfile
CHANGED
data/diesel.gemspec
CHANGED
data/lib/diesel/api_builder.rb
CHANGED
@@ -3,9 +3,11 @@ require 'diesel/api_error'
|
|
3
3
|
require 'diesel/utils/inflections'
|
4
4
|
require 'diesel/api_base'
|
5
5
|
require 'diesel/data_model'
|
6
|
+
require 'diesel/uri'
|
6
7
|
|
7
8
|
require 'diesel/middleware/debug'
|
8
9
|
require 'diesel/middleware/set_header'
|
10
|
+
require 'diesel/middleware/convert_json_body'
|
9
11
|
|
10
12
|
module Diesel
|
11
13
|
class APIBuilder
|
@@ -25,8 +27,8 @@ module Diesel
|
|
25
27
|
APIGroup.new.tap do |group|
|
26
28
|
group.endpoints = build_endpoints
|
27
29
|
group.endpoints.each do |endpoint|
|
28
|
-
klass.send(:define_method, endpoint.name.to_sym) do |
|
29
|
-
group.execute(self.options, endpoint,
|
30
|
+
klass.send(:define_method, endpoint.name.to_sym) do |*args|
|
31
|
+
group.execute(self.options, endpoint, *args)
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|
@@ -50,15 +52,13 @@ module Diesel
|
|
50
52
|
end
|
51
53
|
|
52
54
|
def build_endpoint_url(specification, path)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
resource_path
|
61
|
-
].join('')
|
55
|
+
uri = Diesel::URI.new
|
56
|
+
uri.scheme = specification.schemes.first
|
57
|
+
uri.host = specification.host
|
58
|
+
uri.base_host = specification.extensions[:base_host]
|
59
|
+
uri.base_path = specification.base_path.chomp('/')
|
60
|
+
uri.resource_path = path.sub(/^([^\/])/, '/\1').chomp('/')
|
61
|
+
uri
|
62
62
|
end
|
63
63
|
|
64
64
|
def build_endpoints
|
@@ -72,30 +72,73 @@ module Diesel
|
|
72
72
|
|
73
73
|
Diesel::Endpoint.new(endpoint_name, endpoint_url, method).tap do |endpoint|
|
74
74
|
endpoint.config_middleware do
|
75
|
-
|
75
|
+
consumes =
|
76
|
+
(operation.consumes && operation.consumes.first) ||
|
77
|
+
(spec.consumes && spec.consumes.first)
|
78
|
+
|
79
|
+
produces =
|
80
|
+
(operation.produces && operation.produces.first) ||
|
81
|
+
(spec.produces && spec.produces.first)
|
76
82
|
|
83
|
+
security = operation.security || spec.security
|
84
|
+
|
85
|
+
use Diesel::Middleware::Debug
|
77
86
|
use Diesel::Middleware::SetHeader, 'User-Agent' => "diesel-rb/#{Diesel::VERSION}"
|
78
87
|
|
79
|
-
if
|
80
|
-
use Diesel::Middleware::SetHeader, 'Content-Type' =>
|
88
|
+
if consumes
|
89
|
+
use Diesel::Middleware::SetHeader, 'Content-Type' => consumes
|
81
90
|
end
|
82
91
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
92
|
+
if produces
|
93
|
+
use Diesel::Middleware::SetHeader, 'Accept' => produces
|
94
|
+
end
|
95
|
+
|
96
|
+
security_ids = if security && !security.empty?
|
97
|
+
security.keys
|
98
|
+
else
|
99
|
+
if operation.security_definitions && !operation.security_definitions.empty?
|
100
|
+
[operation.security_definitions.keys.first]
|
101
|
+
elsif spec.security_definitions && !spec.security_definitions.empty?
|
102
|
+
[spec.security_definitions.keys.first]
|
103
|
+
else
|
104
|
+
[]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
unless security_ids.empty?
|
109
|
+
security_defs = spec.security_definitions || {}
|
110
|
+
if operation.security_definitions
|
111
|
+
security_defs = security_defs.merge(operation.security_definitions)
|
112
|
+
end
|
113
|
+
|
114
|
+
security_ids.each do |name|
|
115
|
+
security_def = security_defs[name]
|
116
|
+
|
117
|
+
if security_def.nil?
|
118
|
+
raise APIError, "Missing security definition: #{name}, operation=#{endpoint_name}, method=#{method}"
|
119
|
+
end
|
120
|
+
|
121
|
+
case security_def.type
|
122
|
+
when 'apiKey'
|
123
|
+
require 'diesel/middleware/auth/api_key'
|
124
|
+
use Diesel::Middleware::Auth::APIKey,
|
125
|
+
id: Diesel::Utils::Inflections.underscore(name).to_sym,
|
126
|
+
in: security_def.in,
|
127
|
+
name: security_def.name,
|
128
|
+
format: security_def.extensions[:format]
|
129
|
+
when 'oauth2'
|
130
|
+
require 'diesel/middleware/auth/oauth2'
|
131
|
+
use Diesel::Middleware::Auth::OAuth2,
|
132
|
+
id: Diesel::Utils::Inflections.underscore(name).to_sym,
|
133
|
+
in: security_def.in,
|
134
|
+
name: security_def.name
|
135
|
+
when "basic"
|
136
|
+
require "diesel/middleware/auth/basic"
|
137
|
+
use Diesel::Middleware::Auth::Basic,
|
138
|
+
id: Diesel::Utils::Inflections.underscore(name).to_sym
|
139
|
+
else
|
140
|
+
raise APIError, "Unsupported security definition: #{security_def.type}"
|
141
|
+
end
|
99
142
|
end
|
100
143
|
end
|
101
144
|
|
@@ -106,14 +149,21 @@ module Diesel
|
|
106
149
|
param_class = Diesel::Utils::Inflections.constantize(param_class_name)
|
107
150
|
middleware_opts = {name: parameter.name}
|
108
151
|
if parameter.schema?
|
109
|
-
|
110
|
-
|
152
|
+
schema = parameter.schema
|
153
|
+
if schema.kind_of? String
|
154
|
+
schema = data_models[parameter.schema]
|
155
|
+
end
|
156
|
+
unless schema
|
157
|
+
raise APIError, "Unspecified schema: #{parameter.schema}; parameter=#{parameter.name}"
|
111
158
|
end
|
112
159
|
middleware_opts[:schema] = schema
|
113
160
|
end
|
114
161
|
use param_class, middleware_opts
|
115
162
|
end
|
116
163
|
|
164
|
+
if consumes == "application/json"
|
165
|
+
use Diesel::Middleware::ConvertJSONBody
|
166
|
+
end
|
117
167
|
end
|
118
168
|
end
|
119
169
|
end
|
data/lib/diesel/api_group.rb
CHANGED
@@ -20,8 +20,9 @@ module Diesel
|
|
20
20
|
@data_models = data_models
|
21
21
|
end
|
22
22
|
|
23
|
-
def execute(options, endpoint, parameters)
|
24
|
-
|
23
|
+
def execute(options, endpoint, *parameters)
|
24
|
+
params = parameters.last || {}
|
25
|
+
RequestContext.new(options, self, endpoint, params).perform
|
25
26
|
end
|
26
27
|
end
|
27
28
|
end
|
@@ -8,19 +8,31 @@ module Diesel
|
|
8
8
|
@id = options[:id]
|
9
9
|
@in = options[:in]
|
10
10
|
@name = options[:name]
|
11
|
+
@format = options[:format]
|
11
12
|
end
|
12
13
|
|
13
14
|
def call(env)
|
14
15
|
context = env[:context]
|
15
|
-
value = context.options[@id]
|
16
|
+
value = format_value(context.options[@id])
|
16
17
|
if @in == :header
|
17
18
|
env[:request_headers][@name] = value
|
18
19
|
elsif @in == :query
|
19
20
|
env[:params][@name] = value
|
21
|
+
elsif @in == :body
|
22
|
+
env[:body] = if body = env[:body]
|
23
|
+
body.merge(@name => value)
|
24
|
+
else
|
25
|
+
{ @name => value }
|
26
|
+
end
|
20
27
|
end
|
21
28
|
@app.call(env)
|
22
29
|
end
|
23
30
|
|
31
|
+
protected
|
32
|
+
def format_value(val)
|
33
|
+
return val unless @format
|
34
|
+
@format % val
|
35
|
+
end
|
24
36
|
end
|
25
37
|
end
|
26
38
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Diesel
|
2
|
+
module Middleware
|
3
|
+
module Auth
|
4
|
+
class Basic
|
5
|
+
|
6
|
+
AUTHORIZATION_HEADER = 'Authorization'.freeze
|
7
|
+
|
8
|
+
def initialize(app, options)
|
9
|
+
@app = app
|
10
|
+
@id = options[:id]
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
context = env[:context]
|
15
|
+
auth_options = context.options[@id]
|
16
|
+
username = auth_options[:username]
|
17
|
+
password = auth_options[:password]
|
18
|
+
value = Base64.encode64([username, password].join(':'))
|
19
|
+
value.gsub!("\n", '')
|
20
|
+
env[:request_headers][AUTHORIZATION_HEADER] = "Basic #{value}"
|
21
|
+
@app.call(env)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -3,8 +3,8 @@ module Diesel
|
|
3
3
|
module Auth
|
4
4
|
class OAuth2
|
5
5
|
|
6
|
-
AUTHORIZATION_HEADER = 'Authorization'
|
7
|
-
AUTHORIZATION_HEADER_FORMAT = 'Bearer %s'
|
6
|
+
AUTHORIZATION_HEADER = 'Authorization'.freeze
|
7
|
+
AUTHORIZATION_HEADER_FORMAT = 'Bearer %s'.freeze
|
8
8
|
|
9
9
|
def initialize(app, options)
|
10
10
|
@app = app
|
@@ -12,6 +12,10 @@ module Diesel
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def perform
|
15
|
+
if endpoint.url.base_host
|
16
|
+
endpoint.url.subdomain = options[:subdomain]
|
17
|
+
end
|
18
|
+
|
15
19
|
env = {
|
16
20
|
method: endpoint.request_method,
|
17
21
|
url: endpoint.url,
|
@@ -20,6 +24,7 @@ module Diesel
|
|
20
24
|
logger: logger,
|
21
25
|
context: self
|
22
26
|
}
|
27
|
+
|
23
28
|
endpoint.middleware_stack.call(env)
|
24
29
|
perform_request(env)
|
25
30
|
end
|
@@ -46,7 +51,8 @@ module Diesel
|
|
46
51
|
|
47
52
|
protected
|
48
53
|
def perform_request(env)
|
49
|
-
HTTParty.send(env[:method],
|
54
|
+
HTTParty.send(env[:method],
|
55
|
+
env[:url].to_s,
|
50
56
|
headers: env[:request_headers],
|
51
57
|
query: env[:params],
|
52
58
|
body: env[:body])
|
@@ -18,32 +18,48 @@ module Diesel
|
|
18
18
|
specification.external_docs = build_node(ExternalDocs, json['externalDocs'])
|
19
19
|
specification.schemes = json['schemes']
|
20
20
|
specification.produces = json['produces'] || []
|
21
|
-
specification.
|
22
|
-
specification
|
23
|
-
|
24
|
-
security.scopes = v
|
25
|
-
memo
|
26
|
-
end
|
21
|
+
specification.consumes = json['consumes'] || []
|
22
|
+
build_security_definition_hash(specification, json)
|
23
|
+
build_security_hash(specification, json)
|
27
24
|
specification.paths = build_node_hash(Path, json, 'paths') do |path, path_json|
|
28
25
|
[:get, :put, :post, :delete, :options, :head, :patch].each do |method|
|
29
26
|
if op_json = path_json[method.to_s]
|
30
27
|
op = build_node(Operation, op_json, constructor_args: [method])
|
31
28
|
op.external_docs = build_node(ExternalDocs, op_json['externalDocs'])
|
32
|
-
op.parameters = build_node_list(Parameter, op_json, 'parameters')
|
29
|
+
op.parameters = build_node_list(Parameter, op_json, 'parameters') do |param, param_json|
|
30
|
+
if param_json["schema"] && param_json["schema"].kind_of?(Hash)
|
31
|
+
schema_json = param_json["schema"]
|
32
|
+
param.schema = build_node(Definition, schema_json)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
build_security_definition_hash(specification, json)
|
36
|
+
build_security_hash(op, op_json)
|
33
37
|
path.send("#{method}=".to_sym, op)
|
34
38
|
end
|
35
39
|
end
|
36
40
|
end
|
37
41
|
specification.definitions = build_node_hash(Definition, json, 'definitions') do |definition, def_json|
|
38
42
|
definition.properties = build_node_hash(Property, def_json, 'properties') do |prop, prop_json|
|
39
|
-
prop.enum = prop_json[
|
40
|
-
prop.items = prop_json[
|
43
|
+
prop.enum = prop_json["enum"]
|
44
|
+
prop.items = prop_json["items"]
|
41
45
|
end
|
42
46
|
end
|
43
47
|
specification
|
44
48
|
end
|
45
49
|
|
46
50
|
protected
|
51
|
+
def build_security_hash(parent_node, json)
|
52
|
+
sec_json = json['security']
|
53
|
+
parent_node.security = (sec_json || {}).reduce({}) do |memo, (k,v)|
|
54
|
+
memo[k] = security = Security.new(k)
|
55
|
+
security.scopes = v
|
56
|
+
memo
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def build_security_definition_hash(parent_node, json)
|
61
|
+
parent_node.security_definitions = build_node_hash(SecurityDefinition, json, 'securityDefinitions')
|
62
|
+
end
|
47
63
|
|
48
64
|
def build_node(model_class, json, options = {})
|
49
65
|
if json
|
data/lib/diesel/uri.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Diesel
|
2
|
+
class URI
|
3
|
+
|
4
|
+
components = [:scheme, :host, :base_host, :subdomain, :base_path, :resource_path]
|
5
|
+
|
6
|
+
attr_reader *components
|
7
|
+
|
8
|
+
components.each do |comp|
|
9
|
+
define_method "#{comp}=".to_sym do |v|
|
10
|
+
instance_variable_set("@#{comp}", v)
|
11
|
+
build_url
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
build_url
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def build_url
|
22
|
+
host = if base_host && subdomain
|
23
|
+
[subdomain, base_host].join('.')
|
24
|
+
else
|
25
|
+
self.host
|
26
|
+
end
|
27
|
+
[
|
28
|
+
scheme,
|
29
|
+
'://',
|
30
|
+
host,
|
31
|
+
base_path,
|
32
|
+
resource_path
|
33
|
+
].join('')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|