shark-on-lambda 1.0.1 → 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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -0
  3. data/changelog.md +10 -0
  4. data/doc/upgrade-from-0.6.x-to-1.x.md +3 -3
  5. data/lib/shark-on-lambda.rb +9 -0
  6. data/lib/shark_on_lambda.rb +10 -58
  7. data/lib/shark_on_lambda/api_gateway_handler.rb +3 -55
  8. data/lib/shark_on_lambda/application.rb +72 -2
  9. data/lib/shark_on_lambda/base_controller.rb +29 -9
  10. data/lib/shark_on_lambda/configuration.rb +1 -65
  11. data/lib/shark_on_lambda/inferrers/serializer_inferrer.rb +10 -7
  12. data/lib/shark_on_lambda/jsonapi_renderer.rb +1 -2
  13. data/lib/shark_on_lambda/middleware/honeybadger.rb +5 -3
  14. data/lib/shark_on_lambda/middleware/jsonapi_rescuer.rb +21 -1
  15. data/lib/shark_on_lambda/middleware/lambda_logger.rb +5 -13
  16. data/lib/shark_on_lambda/rake_tasks.rb +16 -0
  17. data/lib/shark_on_lambda/request.rb +0 -3
  18. data/lib/shark_on_lambda/rspec/env_builder.rb +71 -37
  19. data/lib/shark_on_lambda/rspec/helpers.rb +5 -88
  20. data/lib/shark_on_lambda/rspec/request_helpers.rb +63 -0
  21. data/lib/shark_on_lambda/rspec/{jsonapi_helpers.rb → response_helpers.rb} +4 -10
  22. data/lib/shark_on_lambda/version.rb +1 -1
  23. data/shark-on-lambda.gemspec +7 -5
  24. metadata +32 -39
  25. data/lib/shark_on_lambda/concerns/resettable_singleton.rb +0 -18
  26. data/lib/shark_on_lambda/concerns/yaml_config_loader.rb +0 -28
  27. data/lib/shark_on_lambda/dispatcher.rb +0 -26
  28. data/lib/shark_on_lambda/inferrers/name_inferrer.rb +0 -66
  29. data/lib/shark_on_lambda/jsonapi_controller.rb +0 -32
  30. data/lib/shark_on_lambda/middleware/rescuer.rb +0 -37
  31. data/lib/shark_on_lambda/query.rb +0 -67
  32. data/lib/shark_on_lambda/rack_adapters/api_gateway.rb +0 -128
  33. data/lib/shark_on_lambda/secrets.rb +0 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e65d5fd63a3fe9849667d0a023286a7ec8b4c78e868d3576dfd8c229d627e7d1
4
- data.tar.gz: c30474a3ce2381caf7bf5e75e76d0ec441efef525554819ce1c6bc46e8cbec50
3
+ metadata.gz: 642998e593034c083639724031920edfe7568de50d276cc3c58932c099d94a0e
4
+ data.tar.gz: 8101e725e3ef4f710422625726f87c7a324e986b9eb6184a988e0fdd3812bdda
5
5
  SHA512:
6
- metadata.gz: 5c1ab8d3c7aedcd042dace73a1771a755fc3210e65a2a229591325e96902925f3b5aa5e6ee7efdde8890862a6059ba7be365d562f1a0f82216de10d7a495c42e
7
- data.tar.gz: 34398cf95e10a12e576735a0f09ac4b269301d48d9f34ce441f0d8d232d812173ab001181f215f2ceea9012e60372c54b97c5653e407a719edf2fadf63ef3900
6
+ metadata.gz: d23eac59ce2797aac609444509d571a54ffb22024f11070a54dd43d600ceeeb2b527e421c1c9463ac08cceb4fa2b9ad6a366e496cebb47c2873276e9abf4a9ec
7
+ data.tar.gz: 8932eeb3134b88fb0da09b35a3a70eb1b4d1bfb5b2a1f522b9f4bc23c07890b4c6c9cd061374aebf4eb80c09695ef69420da95cc7f608c415b81692724f41e56
@@ -1,4 +1,5 @@
1
1
  AllCops:
2
+ NewCops: enable
2
3
  TargetRubyVersion: 2.5
3
4
 
4
5
  Metrics/BlockLength:
@@ -6,6 +7,9 @@ Metrics/BlockLength:
6
7
  - 'spec/**/*_spec.rb'
7
8
  - 'spec/factories/*.rb'
8
9
 
10
+ Layout/LineLength:
11
+ Max: 80
12
+
9
13
  Naming/FileName:
10
14
  Exclude:
11
15
  - lib/shark-on-lambda.rb
@@ -2,6 +2,16 @@
2
2
 
3
3
  #### Unreleased
4
4
 
5
+ #### 2.0.0
6
+ - [Deprecate] Requiring `shark-on-lambda` is marked as deprecated in favour of requiring `shark_on_lambda`.
7
+ - [Break] `SharkOnLambda::Dispatcher` was removed in favour of routing via `ActionDispatch::Routing`.
8
+ - [Break] `SharkOnLambda::BaseController` now renders _JSON API_-compliant responses.
9
+ - [Break] `SharkOnLambda::JsonapiController` was removed.
10
+ - [Break] Support for `path_parameters` in RSpec helpers was removed.
11
+ - [Break] Configuration files are not loaded automatically anymore.
12
+ - Added support for routing.
13
+ - Use `rack-on-lambda` as an adapter for events from the (REST API flavoured) API Gateway.
14
+
5
15
  #### 1.0.1
6
16
 
7
17
  - [Fix] `Jsonapi::Renderer#render` should always return a hash.
@@ -31,13 +31,13 @@ your RSpec tests and then use the methods `delete`, `get`, `patch`, `post`, or
31
31
 
32
32
  ```ruby
33
33
  RSpec.describe MyController do
34
- let!(:service_token) { 'my-super-secret-service-token' }
35
- let!(:headers) do
34
+ let(:service_token) { 'my-super-secret-service-token' }
35
+ let(:headers) do
36
36
  {
37
37
  'authorization' => "Bearer #{service_token}"
38
38
  }
39
39
  end
40
- let!(:params) do
40
+ let(:params) do
41
41
  {
42
42
  id: 1
43
43
  }
@@ -1,3 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'active_support/core_ext/string'
4
+ require 'active_support/deprecation'
5
+
6
+ deprecation_message = <<-MESSAGE.squish
7
+ Requiring `shark-on-lambda` is deprecated and will be removed in version 3.0.
8
+ Please require `shark_on_lambda` instead.
9
+ MESSAGE
10
+ ActiveSupport::Deprecation.warn(deprecation_message, caller(2))
11
+
3
12
  require 'shark_on_lambda'
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'pry' if Gem.loaded_specs.key?('pry')
4
4
 
5
+ require 'erb'
5
6
  require 'forwardable'
6
7
  require 'ostruct'
7
8
  require 'pathname'
@@ -14,6 +15,7 @@ require 'active_support/all'
14
15
  require 'jsonapi/deserializable'
15
16
  require 'jsonapi/serializable'
16
17
  require 'rack/utils'
18
+ require 'rack-on-lambda'
17
19
  require 'yaml'
18
20
  require 'zeitwerk'
19
21
 
@@ -22,6 +24,7 @@ module SharkOnLambda; end
22
24
 
23
25
  Zeitwerk::Loader.for_gem.tap do |loader|
24
26
  loader.ignore(File.expand_path('shark-on-lambda.rb', __dir__))
27
+ loader.ignore(File.expand_path('shark_on_lambda/rake_tasks.rb', __dir__))
25
28
  loader.inflector.inflect(
26
29
  'rspec' => 'RSpec',
27
30
  'version' => 'VERSION'
@@ -35,75 +38,24 @@ module SharkOnLambda
35
38
  class << self
36
39
  extend Forwardable
37
40
 
38
- attr_writer :logger
41
+ attr_writer :application, :env, :logger
39
42
 
40
- def_instance_delegators :config, :root, :stage
43
+ def_instance_delegators :application, :initialize!, :root
41
44
 
42
45
  def application
43
46
  @application ||= Application.new
44
47
  end
45
48
 
46
- def config
47
- Configuration.instance
49
+ def configuration
50
+ application.config
48
51
  end
49
52
 
50
- def configure
51
- yield(config, secrets)
52
- end
53
-
54
- def initialize!
55
- enable_jsonapi!
56
-
57
- yield(config, secrets)
58
-
59
- Configuration.load(stage)
60
- Secrets.load(stage)
61
- run_initializers
62
-
63
- true
64
- end
65
-
66
- def load_configuration
67
- Configuration.load(stage)
68
- Secrets.load(stage)
69
-
70
- true
53
+ def env
54
+ @env || ENV['STAGE'].presence || 'development'
71
55
  end
72
56
 
73
57
  def logger
74
- @logger ||= Logger.new(STDOUT)
75
- end
76
-
77
- def reset_configuration
78
- known_stage = config.stage
79
- known_root = config.root
80
-
81
- Configuration.reset
82
- Secrets.reset
83
-
84
- config.root = known_root
85
- config.stage = known_stage
86
-
87
- true
88
- end
89
-
90
- def secrets
91
- Secrets.instance
92
- end
93
-
94
- private
95
-
96
- def enable_jsonapi!
97
- ::Mime::Type.register('application/vnd.api+json', :jsonapi)
98
- ::ActionDispatch::Request.parameter_parsers[:jsonapi] =
99
- ::ActionDispatch::Request.parameter_parsers[:json].dup
100
- end
101
-
102
- def run_initializers
103
- initializers_path = root.join('config', 'initializers')
104
- Dir.glob(initializers_path.join('*.rb')).each do |path|
105
- load path
106
- end
58
+ @logger ||= Logger.new($stdout)
107
59
  end
108
60
  end
109
61
  end
@@ -1,61 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SharkOnLambda
4
- class ApiGatewayHandler
5
- class << self
6
- attr_writer :controller_class_name
7
-
8
- def controller_action?(action)
9
- controller_actions.include?(action.to_sym)
10
- end
11
-
12
- def controller_class_name
13
- return @controller_class_name if defined?(@controller_class_name)
14
-
15
- name_inferrer = Inferrers::NameInferrer.from_handler_name(name)
16
- @controller_class_name = name_inferrer.controller
17
- end
18
-
19
- private
20
-
21
- def controller_actions
22
- return [] if controller_class.nil?
23
-
24
- controller_class.public_instance_methods(false)
25
- end
26
-
27
- def controller_class
28
- controller_class_name.safe_constantize
29
- end
30
-
31
- def method_missing(action, *args, &_block)
32
- return super unless respond_to_missing?(action)
33
-
34
- new.call(action, *args)
35
- end
36
-
37
- def respond_to_missing?(name, _include_all = false)
38
- controller_action?(name)
39
- end
40
- end
41
-
42
- attr_reader :application, :env
43
- delegate :context, :event, to: :adapter
44
-
45
- def initialize
46
- @application = Application.new
47
- end
48
-
49
- def call(action, event:, context:)
50
- raise NoMethodError unless self.class.controller_action?(action)
51
-
52
- adapter = RackAdapters::ApiGateway.new(context: context, event: event)
53
- env = adapter.env
54
- env['shark.controller'] = self.class.controller_class_name
55
- env['shark.action'] = action.to_s
56
-
57
- status, headers, body = @application.call(env)
58
- adapter.build_response(status, headers, body)
4
+ class ApiGatewayHandler < RackOnLambda::Handlers::RestApi
5
+ def self.call(event:, context:)
6
+ super(event: event, context: context, app: SharkOnLambda.application)
59
7
  end
60
8
  end
61
9
  end
@@ -2,14 +2,84 @@
2
2
 
3
3
  module SharkOnLambda
4
4
  class Application
5
+ attr_reader :routes
6
+
7
+ delegate :middleware, :root, to: :config
8
+
9
+ class << self
10
+ def config
11
+ @config ||= Configuration.new
12
+ end
13
+
14
+ def inherited(subclass)
15
+ super
16
+
17
+ SharkOnLambda.application = subclass.new
18
+ end
19
+ end
20
+
21
+ def initialize
22
+ register_jsonapi_rendering
23
+ initialize_router
24
+ end
25
+
5
26
  def call(env)
6
27
  dup.call!(env)
7
28
  end
8
29
 
9
30
  def call!(env)
10
- dispatcher = SharkOnLambda.config.dispatcher
11
- middleware_stack = SharkOnLambda.config.middleware.build(dispatcher)
31
+ middleware_stack = middleware.build(routes)
12
32
  middleware_stack.call(env)
13
33
  end
34
+
35
+ def config
36
+ self.class.config
37
+ end
38
+
39
+ def config_for(name, env: SharkOnLambda.env)
40
+ config = load_config_file(name, env: env)
41
+ config.deep_merge(load_config_file("#{name}.local", env: env))
42
+ end
43
+
44
+ def initialize!
45
+ load_routes
46
+ run_initializers
47
+ end
48
+
49
+ private
50
+
51
+ def initialize_router
52
+ router_config = ActionDispatch::Routing::RouteSet::Config.new(nil, true)
53
+ @routes = ActionDispatch::Routing::RouteSet.new_with_config(router_config)
54
+ end
55
+
56
+ def load_config_file(name, env:)
57
+ filename = "#{name}.yml"
58
+ config_file = SharkOnLambda.root.join('config', filename)
59
+ unless config_file.exist?
60
+ raise ArgumentError,
61
+ "Could not load configuration. No such file - #{config_file}"
62
+ end
63
+
64
+ erb_parsed_config = ERB.new(config_file.read).result
65
+ config = YAML.safe_load(erb_parsed_config, [], [], true, filename) || {}
66
+ config.fetch(env, {}).with_indifferent_access
67
+ end
68
+
69
+ def load_routes
70
+ routes_path = SharkOnLambda.root.join('config', 'routes.rb').to_s
71
+ load routes_path if File.exist?(routes_path)
72
+ end
73
+
74
+ def register_jsonapi_rendering
75
+ ::Mime::Type.register('application/vnd.api+json', :jsonapi)
76
+ ::ActionDispatch::Request.parameter_parsers[:jsonapi] =
77
+ ::ActionDispatch::Request.parameter_parsers[:json].dup
78
+ end
79
+
80
+ def run_initializers
81
+ initializers_folder = SharkOnLambda.root.join('config', 'initializers')
82
+ Dir.glob(initializers_folder.join('*.rb')).each { |path| load path }
83
+ end
14
84
  end
15
85
  end
@@ -6,13 +6,6 @@ module SharkOnLambda
6
6
  AbstractController::Translation,
7
7
  AbstractController::AssetPaths,
8
8
 
9
- ActionController::UrlFor,
10
- ActionController::ConditionalGet,
11
- ActionController::EtagWithTemplateDigest,
12
- ActionController::EtagWithFlash,
13
- ActionController::Caching,
14
- ActionController::MimeResponds,
15
- ActionController::ImplicitRender,
16
9
  ActionController::Cookies,
17
10
  ActionController::Flash,
18
11
  ActionController::FormBuilder,
@@ -24,10 +17,27 @@ module SharkOnLambda
24
17
  ActionController::HttpAuthentication::Token::ControllerMethods,
25
18
  ActionView::Layouts
26
19
  ].freeze
27
- ActionController::Base.without_modules(EXCLUDED_MODULES).each do |mod|
20
+ ActionController::API.without_modules(EXCLUDED_MODULES).each do |mod|
28
21
  include mod
29
22
  end
30
23
 
24
+ ActionController::Renderers.add :jsonapi do |object, options|
25
+ response.set_header('content-type', 'application/vnd.api+json')
26
+ return { data: {} }.to_json if object.nil?
27
+
28
+ jsonapi_renderer = JsonapiRenderer.new(object)
29
+
30
+ jsonapi_params = params.slice(:fields, :include)
31
+ jsonapi_params.permit!
32
+ jsonapi_params = JsonapiParameters.new(jsonapi_params.to_h)
33
+
34
+ render_options = jsonapi_params.to_h.deep_merge(options)
35
+ jsonapi_object = jsonapi_renderer.render(render_options)
36
+
37
+ response.status = jsonapi_renderer.status
38
+ jsonapi_object.to_json
39
+ end
40
+
31
41
  def self.dispatch(*)
32
42
  super
33
43
  rescue AbstractController::ActionNotFound,
@@ -38,7 +48,17 @@ module SharkOnLambda
38
48
 
39
49
  def redirect_to(*)
40
50
  super
41
- self.response_body = '' if no_body?
51
+
52
+ self.response_body = no_body? ? nil : { data: {} }.to_json
53
+ end
54
+
55
+ def render(object, options = {})
56
+ options.merge!(
57
+ jsonapi: object,
58
+ content_type: 'application/vnd.api+json'
59
+ )
60
+
61
+ super(options)
42
62
  end
43
63
 
44
64
  private
@@ -2,63 +2,7 @@
2
2
 
3
3
  module SharkOnLambda
4
4
  class Configuration < OpenStruct
5
- include Concerns::ResettableSingleton
6
-
7
- attr_writer :dispatcher, :stage
8
-
9
- class << self
10
- include Concerns::YamlConfigLoader
11
-
12
- attr_writer :database_files, :settings_files
13
-
14
- def database_files
15
- return @database_files if defined?(@database_files)
16
-
17
- files = %w[config/database.yml config/database.local.yml]
18
- @database_files = paths(files)
19
- end
20
-
21
- def load(stage, fallback: :default)
22
- load_settings(stage, fallback: fallback)
23
- load_database_configuration(stage, fallback: fallback)
24
-
25
- instance
26
- end
27
-
28
- def settings_files
29
- return @settings_files if defined?(@settings_files)
30
-
31
- files = %w[config/settings.yml config/settings.local.yml]
32
- @settings_files = paths(files)
33
- end
34
-
35
- protected
36
-
37
- def load_database_configuration(stage, fallback:)
38
- instance.database = load_yaml_files(stage: stage,
39
- fallback: fallback,
40
- paths: paths(database_files))
41
- end
42
-
43
- def load_settings(stage, fallback:)
44
- settings = load_yaml_files(stage: stage,
45
- fallback: fallback,
46
- paths: paths(settings_files))
47
- settings.each_pair do |key, value|
48
- next if key.to_s == 'serverless'
49
-
50
- instance.send("#{key}=", value)
51
- end
52
- end
53
-
54
- def paths(files)
55
- files.map { |file| SharkOnLambda.config.root.join(file) }
56
- end
57
- end
58
-
59
- def dispatcher
60
- @dispatcher ||= Dispatcher.new
61
- end
5
+ attr_reader :root
62
6
 
63
7
  def middleware
64
8
  @middleware ||= ActionDispatch::MiddlewareStack.new do |middleware_stack|
@@ -66,16 +10,8 @@ module SharkOnLambda
66
10
  end
67
11
  end
68
12
 
69
- def root
70
- @root ||= Pathname.new('.')
71
- end
72
-
73
13
  def root=(new_root)
74
14
  @root = Pathname.new(new_root)
75
15
  end
76
-
77
- def stage
78
- @stage || 'development'
79
- end
80
16
  end
81
17
  end