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 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