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

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