shark-on-lambda 1.0.0.rc2 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -3
  3. data/.rubocop.yml +4 -0
  4. data/README.md +70 -17
  5. data/changelog.md +17 -1
  6. data/doc/upgrade-from-0.6.x-to-1.x.md +122 -0
  7. data/lib/shark-on-lambda.rb +9 -0
  8. data/lib/shark_on_lambda.rb +10 -50
  9. data/lib/shark_on_lambda/api_gateway_handler.rb +3 -55
  10. data/lib/shark_on_lambda/application.rb +73 -5
  11. data/lib/shark_on_lambda/base_controller.rb +29 -9
  12. data/lib/shark_on_lambda/configuration.rb +1 -65
  13. data/lib/shark_on_lambda/inferrers/serializer_inferrer.rb +10 -7
  14. data/lib/shark_on_lambda/jsonapi_renderer.rb +16 -10
  15. data/lib/shark_on_lambda/middleware/base.rb +2 -4
  16. data/lib/shark_on_lambda/middleware/honeybadger.rb +45 -0
  17. data/lib/shark_on_lambda/middleware/jsonapi_rescuer.rb +21 -1
  18. data/lib/shark_on_lambda/middleware/lambda_logger.rb +8 -16
  19. data/lib/shark_on_lambda/rake_tasks.rb +16 -0
  20. data/lib/shark_on_lambda/request.rb +0 -3
  21. data/lib/shark_on_lambda/rspec/env_builder.rb +73 -31
  22. data/lib/shark_on_lambda/rspec/helpers.rb +5 -74
  23. data/lib/shark_on_lambda/rspec/request_helpers.rb +63 -0
  24. data/lib/shark_on_lambda/rspec/{jsonapi_helpers.rb → response_helpers.rb} +4 -6
  25. data/lib/shark_on_lambda/version.rb +1 -1
  26. data/shark-on-lambda.gemspec +7 -5
  27. metadata +32 -38
  28. data/gems.locked +0 -142
  29. data/lib/shark_on_lambda/concerns/resettable_singleton.rb +0 -18
  30. data/lib/shark_on_lambda/concerns/yaml_config_loader.rb +0 -28
  31. data/lib/shark_on_lambda/dispatcher.rb +0 -26
  32. data/lib/shark_on_lambda/inferrers/name_inferrer.rb +0 -66
  33. data/lib/shark_on_lambda/jsonapi_controller.rb +0 -29
  34. data/lib/shark_on_lambda/middleware/rescuer.rb +0 -38
  35. data/lib/shark_on_lambda/query.rb +0 -67
  36. data/lib/shark_on_lambda/rack_adapters/api_gateway.rb +0 -127
  37. data/lib/shark_on_lambda/secrets.rb +0 -43
@@ -10,37 +10,34 @@ module SharkOnLambda
10
10
  @logger = logger
11
11
  end
12
12
 
13
- private
14
-
15
- def _call(env)
13
+ def call!(env)
16
14
  start_time = Time.now
17
15
  response = app.call(env)
18
- end_time = Time.now
16
+ duration = duration_in_ms(start_time, Time.now)
19
17
 
20
18
  if logger.info?
21
- log_request(env: env,
22
- response: response,
23
- start_time: start_time,
24
- end_time: end_time)
19
+ log_request(env: env, response: response, duration: duration)
25
20
  end
26
21
 
27
22
  response
28
23
  end
29
24
 
25
+ private
26
+
30
27
  def body_size(body)
31
28
  size = 0
32
29
  body.each { |chunk| size += chunk.bytesize }
33
30
  size
34
31
  end
35
32
 
36
- def log_request(env:, response:, start_time:, end_time:)
33
+ def log_request(env:, response:, duration:)
37
34
  log_object = {
38
35
  url: env['PATH_INFO'],
39
36
  method: env['REQUEST_METHOD'],
40
- params: params(env),
37
+ params: env.fetch('action_dispatch.request.parameters', {}),
41
38
  status: response[0],
42
39
  length: body_size(response[2]),
43
- duration: "#{duration_in_ms(start_time, end_time)} ms"
40
+ duration: "#{duration} ms"
44
41
  }
45
42
  logger.info log_object.to_json
46
43
  end
@@ -49,11 +46,6 @@ module SharkOnLambda
49
46
  duration = (end_time - start_time) * 1000
50
47
  duration.abs.floor(3)
51
48
  end
52
-
53
- def params(env)
54
- query_params = Rack::Utils.parse_nested_query(env['QUERY_STRING'])
55
- query_params.merge(env['shark.path_parameters'] || {})
56
- end
57
49
  end
58
50
  end
59
51
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_dispatch/routing/inspector'
4
+ require 'rake'
5
+ require 'shark_on_lambda'
6
+
7
+ namespace :'shark-on-lambda' do
8
+ desc 'Print out all defined routes in match order, with names'
9
+ task :routes do
10
+ routes = SharkOnLambda.application.routes.routes
11
+ inspector = ActionDispatch::Routing::RoutesInspector.new(routes)
12
+ formatter = ActionDispatch::Routing::ConsoleFormatter::Sheet.new
13
+
14
+ puts inspector.format(formatter)
15
+ end
16
+ end
@@ -2,8 +2,5 @@
2
2
 
3
3
  module SharkOnLambda
4
4
  class Request < ActionDispatch::Request
5
- def path_parameters
6
- super.merge(env['shark.path_parameters'] || {})
7
- end
8
5
  end
9
6
  end
@@ -3,22 +3,14 @@
3
3
  module SharkOnLambda
4
4
  module RSpec
5
5
  class EnvBuilder
6
- attr_reader :action, :controller, :headers, :method, :params
7
-
8
- def initialize(options = {})
9
- @method = options.fetch(:method).to_s.upcase
10
- @controller = options.fetch(:controller)
11
- @action = options.fetch(:action)
12
-
13
- @headers = (options[:headers] || {}).deep_stringify_keys
14
- @params = options[:params]
15
-
16
- initialize_env
17
- add_headers
18
- add_request_body
6
+ def initialize(**options)
7
+ @options = options
19
8
  end
20
9
 
21
10
  def build
11
+ initialize_env
12
+ add_headers
13
+ add_request_body_as_json if body? && jsonable_params? && json_request?
22
14
  env.deep_stringify_keys
23
15
  end
24
16
 
@@ -26,39 +18,89 @@ module SharkOnLambda
26
18
 
27
19
  attr_reader :env
28
20
 
29
- def add_header(name, value)
30
- name = name.upcase.tr('-', '_')
31
- key = case name
32
- when 'CONTENT_LENGTH', 'CONTENT_TYPE' then name
33
- else "HTTP_#{name}"
34
- end
35
- @env[key] = value.to_s
21
+ def action
22
+ @options.fetch(:action)
36
23
  end
37
24
 
38
25
  def add_headers
39
- headers.each_pair { |name, value| add_header(name, value) }
26
+ headers.each_pair do |name, value|
27
+ name = name.upcase.tr('-', '_')
28
+ key = case name
29
+ when 'CONTENT_LENGTH', 'CONTENT_TYPE' then name
30
+ else "HTTP_#{name}"
31
+ end
32
+ env[key] = value.to_s
33
+ end
40
34
  end
41
35
 
42
- def add_request_body
43
- return if %w[GET HEAD OPTIONS].include?(env['REQUEST_METHOD'])
44
- return unless params.is_a?(Hash)
45
-
36
+ def add_request_body_as_json
46
37
  body = params.to_json
47
38
 
48
39
  env['rack.input'] = StringIO.new(body).set_encoding(Encoding::BINARY)
49
- env['CONTENT_TYPE'] = 'application/json'
50
- env['CONTENT_LENGTH'] = body.bytesize.to_s
40
+ env['CONTENT_TYPE'] = headers['content-type']
41
+ env['CONTENT_LENGTH'] = env['rack.input'].length.to_s
42
+ end
43
+
44
+ def as
45
+ @options.fetch(:as, :json)
46
+ end
47
+
48
+ def body?
49
+ !%w[GET HEAD OPTIONS].include?(env['REQUEST_METHOD'])
51
50
  end
52
51
 
53
52
  def initialize_env
54
53
  @env = Rack::MockRequest.env_for(
55
- 'https://localhost:9292',
54
+ request_uri.to_s,
56
55
  method: method,
57
- params: params,
58
- 'shark.controller' => controller,
59
- 'shark.action' => action
56
+ params: params
60
57
  )
61
58
  end
59
+
60
+ def controller
61
+ @options.fetch(:controller, nil)
62
+ end
63
+
64
+ def headers
65
+ return @headers if defined?(@headers)
66
+
67
+ @headers = @options.fetch(:headers, {}).deep_stringify_keys
68
+ @headers.transform_keys!(&:downcase)
69
+ @headers
70
+ end
71
+
72
+ def json_request?
73
+ as == :json
74
+ end
75
+
76
+ def jsonable_params?
77
+ params.is_a?(Hash)
78
+ end
79
+
80
+ def method
81
+ @options.fetch(:method).to_s.upcase
82
+ end
83
+
84
+ def params
85
+ @options.fetch(:params, {}).deep_stringify_keys
86
+ end
87
+
88
+ def path_from_routes
89
+ path_params = {
90
+ controller: controller.name.underscore.sub(/_controller$/, ''),
91
+ action: action,
92
+ only_path: true
93
+ }
94
+ url = SharkOnLambda.application.routes.url_for(path_params, nil)
95
+ URI.parse(url).path
96
+ end
97
+
98
+ def request_uri
99
+ return @request_uri if defined?(@request_uri)
100
+
101
+ path = action.is_a?(String) ? action : path_from_routes
102
+ @request_uri = URI.join('https://localhost:9292', path)
103
+ end
62
104
  end
63
105
  end
64
106
  end
@@ -3,81 +3,12 @@
3
3
  module SharkOnLambda
4
4
  module RSpec
5
5
  module Helpers
6
- def delete(controller_method, options = {})
7
- make_request('DELETE', controller_method, options)
8
- end
9
-
10
- def get(controller_method, options = {})
11
- make_request('GET', controller_method, options)
12
- end
13
-
14
- def patch(controller_method, options = {})
15
- make_request('PATCH', controller_method, options)
16
- end
17
-
18
- def post(controller_method, options = {})
19
- make_request('POST', controller_method, options)
20
- end
21
-
22
- def put(controller_method, options = {})
23
- make_request('PUT', controller_method, options)
24
- end
25
-
26
- def response
27
- if @response.nil?
28
- raise 'You must make a request before you can request a response.'
29
- end
30
-
31
- @response
32
- end
33
-
34
- private
35
-
36
- def build_env(method, action, options = {})
37
- env_builder = EnvBuilder.new(
38
- method: method,
39
- controller: controller_name,
40
- action: action,
41
- headers: options[:headers],
42
- params: options[:params]
43
- )
44
- env_builder.build
45
- end
46
-
47
- def controller?
48
- controller_name.present?
49
- end
50
-
51
- def controller_name
52
- self.class.ancestors.find do |klass|
53
- klass.name.end_with?('Controller')
54
- end&.description
55
- end
56
-
57
- def dispatch_request(env, skip_middleware: false)
58
- return SharkOnLambda.application.call(env) unless skip_middleware
59
-
60
- controller_class = env['shark.controller'].constantize
61
- action = env['shark.action']
62
-
63
- request = Request.new(env)
64
- response = Response.new
65
- controller_class.dispatch(action, request, response)
66
- response.prepare!
67
- end
68
-
69
- def make_request(method, action, options = {})
70
- raise ArgumentError, 'Cannot find controller name.' unless controller?
71
-
72
- options = options.with_indifferent_access
73
- env = build_env(method, action, options)
6
+ extend ActiveSupport::Concern
7
+ include RequestHelpers
8
+ include ResponseHelpers
74
9
 
75
- status, headers, body = dispatch_request(
76
- env,
77
- skip_middleware: options[:skip_middleware]
78
- )
79
- errors = env['rack.errors']
80
- @response = Rack::MockResponse.new(status, headers, body, errors)
10
+ included do
11
+ include SharkOnLambda.application.routes.url_helpers
81
12
  end
82
13
  end
83
14
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SharkOnLambda
4
+ module RSpec
5
+ module RequestHelpers
6
+ attr_writer :app
7
+
8
+ SUPPORTED_HTTP_METHODS = %w[
9
+ DELETE GET HEAD OPTIONS PATCH POST PUT
10
+ ].freeze
11
+
12
+ SUPPORTED_HTTP_METHODS.each do |http_method|
13
+ define_method(http_method.underscore) do |action, **options|
14
+ make_request(http_method, action, **options)
15
+ end
16
+ end
17
+
18
+ def app
19
+ @app ||= SharkOnLambda.application
20
+ end
21
+
22
+ def response
23
+ if @response.nil?
24
+ raise 'You must make a request before you can request a response.'
25
+ end
26
+
27
+ @response
28
+ end
29
+
30
+ private
31
+
32
+ def build_env(method, action, **options)
33
+ headers = options.fetch(:headers, {})
34
+ env_builder = EnvBuilder.new(
35
+ method: method,
36
+ controller: described_class,
37
+ action: action,
38
+ headers: normalized_headers(headers),
39
+ params: options.fetch(:params, {})
40
+ )
41
+ env_builder.build
42
+ end
43
+
44
+ def default_content_type
45
+ 'application/vnd.api+json'
46
+ end
47
+
48
+ def make_request(method, action, **options)
49
+ env = build_env(method, action, **options)
50
+
51
+ status, headers, body = app.call(env)
52
+ errors = env['rack.errors']
53
+ @response = Rack::MockResponse.new(status, headers, body, errors)
54
+ end
55
+
56
+ def normalized_headers(headers)
57
+ headers.transform_keys! { |key| key.to_s.downcase }
58
+ headers['content-type'] ||= default_content_type
59
+ headers
60
+ end
61
+ end
62
+ end
63
+ end
@@ -2,19 +2,17 @@
2
2
 
3
3
  module SharkOnLambda
4
4
  module RSpec
5
- module JsonapiHelpers
6
- include Helpers
7
-
5
+ module ResponseHelpers
8
6
  def jsonapi_attributes
9
- jsonapi_data[:attributes] || {}
7
+ jsonapi_data.fetch(:attributes, {})
10
8
  end
11
9
 
12
10
  def jsonapi_data
13
- parsed_body[:data] || {}
11
+ parsed_body.fetch(:data, {})
14
12
  end
15
13
 
16
14
  def jsonapi_errors
17
- parsed_body[:errors] || []
15
+ parsed_body.fetch(:errors, [])
18
16
  end
19
17
 
20
18
  private
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SharkOnLambda
4
- VERSION = '1.0.0.rc2'
4
+ VERSION = '2.0.0.rc1'
5
5
  end
@@ -30,18 +30,20 @@ Gem::Specification.new do |spec|
30
30
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
31
  spec.require_paths = ['lib']
32
32
 
33
- spec.add_dependency 'actionpack'
34
- spec.add_dependency 'activesupport'
35
- spec.add_dependency 'jsonapi-rb'
33
+ spec.required_ruby_version = '>= 2.5'
34
+
35
+ spec.add_dependency 'actionpack', '~> 6.0.0'
36
+ spec.add_dependency 'activesupport', '~> 6.0.0'
37
+ spec.add_dependency 'jsonapi-rb', '~> 0.5.0'
36
38
  spec.add_dependency 'rack', '>= 2.0.8', '< 3'
37
- spec.add_dependency 'zeitwerk', '~> 2.2'
39
+ spec.add_dependency 'rack-on-lambda', '~> 1.0'
40
+ spec.add_dependency 'zeitwerk', '~> 2.3'
38
41
 
39
42
  # TODO: Do we really need `activemodel`?
40
43
  # Or can we get away with mocking out ActiveModel::Errors?
41
44
  spec.add_development_dependency 'activemodel'
42
45
  spec.add_development_dependency 'bundler'
43
46
  spec.add_development_dependency 'factory_bot'
44
- spec.add_development_dependency 'fasterer'
45
47
  spec.add_development_dependency 'pry'
46
48
  spec.add_development_dependency 'pry-byebug'
47
49
  spec.add_development_dependency 'rake'
metadata CHANGED
@@ -1,57 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shark-on-lambda
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.rc2
4
+ version: 2.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Huy Dinh
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-02 00:00:00.000000000 Z
11
+ date: 2020-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 6.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: 6.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activesupport
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 6.0.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 6.0.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: jsonapi-rb
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 0.5.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 0.5.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rack
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -73,35 +73,35 @@ dependencies:
73
73
  - !ruby/object:Gem::Version
74
74
  version: '3'
75
75
  - !ruby/object:Gem::Dependency
76
- name: zeitwerk
76
+ name: rack-on-lambda
77
77
  requirement: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '2.2'
81
+ version: '1.0'
82
82
  type: :runtime
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: '2.2'
88
+ version: '1.0'
89
89
  - !ruby/object:Gem::Dependency
90
- name: activemodel
90
+ name: zeitwerk
91
91
  requirement: !ruby/object:Gem::Requirement
92
92
  requirements:
93
- - - ">="
93
+ - - "~>"
94
94
  - !ruby/object:Gem::Version
95
- version: '0'
96
- type: :development
95
+ version: '2.3'
96
+ type: :runtime
97
97
  prerelease: false
98
98
  version_requirements: !ruby/object:Gem::Requirement
99
99
  requirements:
100
- - - ">="
100
+ - - "~>"
101
101
  - !ruby/object:Gem::Version
102
- version: '0'
102
+ version: '2.3'
103
103
  - !ruby/object:Gem::Dependency
104
- name: bundler
104
+ name: activemodel
105
105
  requirement: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - ">="
@@ -115,7 +115,7 @@ dependencies:
115
115
  - !ruby/object:Gem::Version
116
116
  version: '0'
117
117
  - !ruby/object:Gem::Dependency
118
- name: factory_bot
118
+ name: bundler
119
119
  requirement: !ruby/object:Gem::Requirement
120
120
  requirements:
121
121
  - - ">="
@@ -129,7 +129,7 @@ dependencies:
129
129
  - !ruby/object:Gem::Version
130
130
  version: '0'
131
131
  - !ruby/object:Gem::Dependency
132
- name: fasterer
132
+ name: factory_bot
133
133
  requirement: !ruby/object:Gem::Requirement
134
134
  requirements:
135
135
  - - ">="
@@ -260,36 +260,30 @@ files:
260
260
  - bin/console
261
261
  - bin/setup
262
262
  - changelog.md
263
- - gems.locked
263
+ - doc/upgrade-from-0.6.x-to-1.x.md
264
264
  - gems.rb
265
265
  - lib/shark-on-lambda.rb
266
266
  - lib/shark_on_lambda.rb
267
267
  - lib/shark_on_lambda/api_gateway_handler.rb
268
268
  - lib/shark_on_lambda/application.rb
269
269
  - lib/shark_on_lambda/base_controller.rb
270
- - lib/shark_on_lambda/concerns/resettable_singleton.rb
271
- - lib/shark_on_lambda/concerns/yaml_config_loader.rb
272
270
  - lib/shark_on_lambda/configuration.rb
273
- - lib/shark_on_lambda/dispatcher.rb
274
271
  - lib/shark_on_lambda/errors/base.rb
275
272
  - lib/shark_on_lambda/errors/base_serializer.rb
276
- - lib/shark_on_lambda/inferrers/name_inferrer.rb
277
273
  - lib/shark_on_lambda/inferrers/serializer_inferrer.rb
278
- - lib/shark_on_lambda/jsonapi_controller.rb
279
274
  - lib/shark_on_lambda/jsonapi_parameters.rb
280
275
  - lib/shark_on_lambda/jsonapi_renderer.rb
281
276
  - lib/shark_on_lambda/middleware/base.rb
277
+ - lib/shark_on_lambda/middleware/honeybadger.rb
282
278
  - lib/shark_on_lambda/middleware/jsonapi_rescuer.rb
283
279
  - lib/shark_on_lambda/middleware/lambda_logger.rb
284
- - lib/shark_on_lambda/middleware/rescuer.rb
285
- - lib/shark_on_lambda/query.rb
286
- - lib/shark_on_lambda/rack_adapters/api_gateway.rb
280
+ - lib/shark_on_lambda/rake_tasks.rb
287
281
  - lib/shark_on_lambda/request.rb
288
282
  - lib/shark_on_lambda/response.rb
289
283
  - lib/shark_on_lambda/rspec/env_builder.rb
290
284
  - lib/shark_on_lambda/rspec/helpers.rb
291
- - lib/shark_on_lambda/rspec/jsonapi_helpers.rb
292
- - lib/shark_on_lambda/secrets.rb
285
+ - lib/shark_on_lambda/rspec/request_helpers.rb
286
+ - lib/shark_on_lambda/rspec/response_helpers.rb
293
287
  - lib/shark_on_lambda/version.rb
294
288
  - shark-on-lambda.gemspec
295
289
  homepage: https://github.com/Skudo/shark-on-lambda
@@ -304,7 +298,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
304
298
  requirements:
305
299
  - - ">="
306
300
  - !ruby/object:Gem::Version
307
- version: '0'
301
+ version: '2.5'
308
302
  required_rubygems_version: !ruby/object:Gem::Requirement
309
303
  requirements:
310
304
  - - ">"