diesel-api-dsl 0.1.3 → 0.1.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1d4d0c9b3ef66d9ba223bc4f9844a5ca7785c087
4
- data.tar.gz: bdce05f100ab2fa3207150fa5fcd867052aa180f
3
+ metadata.gz: 78e75164894839881d3adf47cef1575c25970140
4
+ data.tar.gz: 3ac675a70ef2bf4373a1e4a1b1601a68f8daaa65
5
5
  SHA512:
6
- metadata.gz: 747c888131145da4de241043438788ccdd6b9657da281efe64a83f4b781bf2705e65a31cfd848f3c7a2e8d420e3f597fa7d8f831c76faa6027a083e2bbf99dbb
7
- data.tar.gz: ff267d0ab287faf7e07a1806955996453e58a9aa7ae40c1991769734b993b767ca1a2c692263031d64ebd8c27013d8d68f3cb287bb60e41295af967752868776
6
+ metadata.gz: eceaffc1b439c45851509eb72f4f1e109a16c01b7a8901c104f8c023818f337a43875ef40f77e273d9eb14f8f0fbb99049e0986853a07cfe3c7d3c6720981771
7
+ data.tar.gz: b7be5c3cfdb6bf224263dc13c02f3f0aeab75af8574364a0d9f44133ff3f6a1a77fd20f9d39a86ae060b988c5c5ae96dc717fa0eba3fa5303f5b72300f4be4cb
data/Gemfile CHANGED
@@ -1,4 +1,8 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ group :development do
4
+ gem "pry-byebug"
5
+ end
6
+
3
7
  # Specify your gem's dependencies in diesel.gemspec
4
8
  gemspec
@@ -25,5 +25,5 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency "webmock", "~> 1.20.0"
26
26
 
27
27
  spec.add_dependency "httparty", "~> 0.12"
28
- spec.add_dependency "multi_json", "~> 1.10.1"
28
+ spec.add_dependency "multi_json", ">= 1.3"
29
29
  end
@@ -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 |parameters|
29
- group.execute(self.options, endpoint, parameters)
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
- base_path = specification.base_path.chomp('/')
54
- resource_path = path.sub(/^([^\/])/, '/\1').chomp('/')
55
- [
56
- specification.schemes.first,
57
- '://',
58
- specification.host,
59
- base_path,
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
- use Diesel::Middleware::Debug
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 spec.produces.any?
80
- use Diesel::Middleware::SetHeader, 'Content-Type' => spec.produces.first
88
+ if consumes
89
+ use Diesel::Middleware::SetHeader, 'Content-Type' => consumes
81
90
  end
82
91
 
83
- spec.security_definitions.each_pair do |name, security_def|
84
- case security_def.type
85
- when 'apiKey'
86
- require 'diesel/middleware/auth/api_key'
87
- use Diesel::Middleware::Auth::APIKey,
88
- id: Diesel::Utils::Inflections.underscore(name).to_sym,
89
- in: security_def.in,
90
- name: security_def.name
91
- when 'oauth2'
92
- require 'diesel/middleware/auth/oauth2'
93
- use Diesel::Middleware::Auth::OAuth2,
94
- id: Diesel::Utils::Inflections.underscore(name).to_sym,
95
- in: security_def.in,
96
- name: security_def.name
97
- else
98
- raise APIError, "Unsupported security definition: #{security_def.type}"
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
- unless schema = data_models[parameter.schema]
110
- raise APIError, "Unspecified schema: #{parameter.schema}"
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
@@ -20,8 +20,9 @@ module Diesel
20
20
  @data_models = data_models
21
21
  end
22
22
 
23
- def execute(options, endpoint, parameters)
24
- RequestContext.new(options, self, endpoint, parameters).perform
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
@@ -0,0 +1,15 @@
1
+ module Diesel
2
+ module Middleware
3
+ class ConvertJSONBody
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+ def call(env)
8
+ @app.call(env)
9
+ if body = env[:body]
10
+ env[:body] = MultiJson.dump(body)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -4,7 +4,11 @@ module Diesel
4
4
  module Middleware
5
5
  class SetBodyParameter < SetParameterBase
6
6
  def apply_parameter_value(env, value)
7
- env[:body] = value
7
+ env[:body] = if body = env[:body]
8
+ body.merge(value)
9
+ else
10
+ value
11
+ end
8
12
  end
9
13
  end
10
14
  end
@@ -10,7 +10,8 @@ module Diesel
10
10
  end
11
11
 
12
12
  def apply_parameter_value(env, value)
13
- env[:url] = env[:url].gsub(@regex, value.to_s)
13
+ uri = env[:url]
14
+ uri.resource_path = uri.resource_path.gsub(@regex, value.to_s)
14
15
  end
15
16
  end
16
17
  end
@@ -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], env[:url],
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])
@@ -11,7 +11,7 @@ module Diesel
11
11
 
12
12
  hash :properties
13
13
 
14
- def initialize(id)
14
+ def initialize(id = "<Inline>")
15
15
  super()
16
16
  @id = id
17
17
  end
@@ -19,7 +19,9 @@ module Diesel
19
19
  list :parameters, validate: true
20
20
  list :responses, validate: true
21
21
  list :schemes
22
- list :security, validate: true
22
+
23
+ hash :security_definitions, validate: true
24
+ hash :security, validate: true
23
25
 
24
26
  def initialize(id)
25
27
  super()
@@ -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.security_definitions = build_node_hash(SecurityDefinition, json, 'securityDefinitions')
22
- specification.security = (json['security'] || {}).reduce({}) do |memo, (k,v)|
23
- memo[k] = security = Security.new(k)
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['enum']
40
- prop.items = prop_json['items']
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
@@ -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