shark-on-lambda 1.0.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -0
- data/changelog.md +12 -0
- data/doc/upgrade-from-0.6.x-to-1.x.md +3 -3
- data/lib/shark-on-lambda.rb +9 -0
- data/lib/shark_on_lambda.rb +14 -54
- data/lib/shark_on_lambda/api_gateway_handler.rb +3 -55
- data/lib/shark_on_lambda/application.rb +74 -2
- data/lib/shark_on_lambda/base_controller.rb +29 -9
- data/lib/shark_on_lambda/cacheable.rb +21 -0
- data/lib/shark_on_lambda/configuration.rb +1 -65
- data/lib/shark_on_lambda/inferrers/serializer_inferrer.rb +10 -7
- data/lib/shark_on_lambda/jsonapi_renderer.rb +1 -2
- data/lib/shark_on_lambda/middleware/honeybadger.rb +5 -3
- data/lib/shark_on_lambda/middleware/jsonapi_rescuer.rb +21 -1
- data/lib/shark_on_lambda/middleware/lambda_logger.rb +5 -13
- data/lib/shark_on_lambda/rake_tasks.rb +16 -0
- data/lib/shark_on_lambda/request.rb +0 -3
- data/lib/shark_on_lambda/rspec/env_builder.rb +71 -37
- data/lib/shark_on_lambda/rspec/helpers.rb +5 -88
- data/lib/shark_on_lambda/rspec/request_helpers.rb +63 -0
- data/lib/shark_on_lambda/rspec/{jsonapi_helpers.rb → response_helpers.rb} +4 -10
- data/lib/shark_on_lambda/version.rb +1 -1
- data/shark-on-lambda.gemspec +7 -5
- metadata +37 -37
- data/lib/shark_on_lambda/concerns/resettable_singleton.rb +0 -18
- data/lib/shark_on_lambda/concerns/yaml_config_loader.rb +0 -28
- data/lib/shark_on_lambda/dispatcher.rb +0 -26
- data/lib/shark_on_lambda/inferrers/name_inferrer.rb +0 -66
- data/lib/shark_on_lambda/jsonapi_controller.rb +0 -32
- data/lib/shark_on_lambda/middleware/rescuer.rb +0 -37
- data/lib/shark_on_lambda/query.rb +0 -67
- data/lib/shark_on_lambda/rack_adapters/api_gateway.rb +0 -128
- data/lib/shark_on_lambda/secrets.rb +0 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 224a4b3bddf92d9409d38d0ad65bae7511e05c0d9d40d8d2b1b6ba5c4224f6e0
|
4
|
+
data.tar.gz: 46a5ac6faeac926b023069ad953fb2b96340f969a9dcc8df116e29d6536999a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5cb73c903cddc2898212b09cc314f9cf35df9f099e8f21eba27df660b2d20ae78c6a828ab29e32a46e433e6485031e1609848c6af49fc53307c04651861d90c6
|
7
|
+
data.tar.gz: 92f7f4ab12057333a45089f8734c081dab440f22d42bbb6c72de0057e24cfb444089b72ffe1d3c2207ddd70e8d13ae16c88170807dbd6e68a5fd319ed65d0a84
|
data/.rubocop.yml
CHANGED
@@ -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
|
data/changelog.md
CHANGED
@@ -2,6 +2,18 @@
|
|
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 `SharkOnLambda::Cacheable`.
|
13
|
+
- Added `SharkOnLambda.cache` and `SharkOnLambda.global_cache`.
|
14
|
+
- Added support for routing.
|
15
|
+
- Use `rack-on-lambda` as an adapter for events from the (REST API flavoured) API Gateway.
|
16
|
+
|
5
17
|
#### 1.0.1
|
6
18
|
|
7
19
|
- [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
|
35
|
-
let
|
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
|
40
|
+
let(:params) do
|
41
41
|
{
|
42
42
|
id: 1
|
43
43
|
}
|
data/lib/shark-on-lambda.rb
CHANGED
@@ -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'
|
data/lib/shark_on_lambda.rb
CHANGED
@@ -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,32 @@ module SharkOnLambda
|
|
35
38
|
class << self
|
36
39
|
extend Forwardable
|
37
40
|
|
38
|
-
attr_writer :logger
|
41
|
+
attr_writer :application, :cache, :env, :global_cache, :logger
|
39
42
|
|
40
|
-
def_instance_delegators :
|
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
|
47
|
-
|
49
|
+
def configuration
|
50
|
+
application.config
|
48
51
|
end
|
49
52
|
|
50
|
-
def
|
51
|
-
|
53
|
+
def cache
|
54
|
+
@cache ||= ActiveSupport::Cache::NullStore.new
|
52
55
|
end
|
53
56
|
|
54
|
-
def
|
55
|
-
|
56
|
-
|
57
|
-
yield(config, secrets)
|
58
|
-
|
59
|
-
Configuration.load(stage)
|
60
|
-
Secrets.load(stage)
|
61
|
-
run_initializers
|
62
|
-
|
63
|
-
true
|
57
|
+
def env
|
58
|
+
@env || ENV['STAGE'].presence || 'development'
|
64
59
|
end
|
65
60
|
|
66
|
-
def
|
67
|
-
|
68
|
-
Secrets.load(stage)
|
69
|
-
|
70
|
-
true
|
61
|
+
def global_cache
|
62
|
+
@global_cache ||= ActiveSupport::Cache::NullStore.new
|
71
63
|
end
|
72
64
|
|
73
65
|
def logger
|
74
|
-
@logger ||= Logger.new(
|
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
|
66
|
+
@logger ||= Logger.new($stdout)
|
107
67
|
end
|
108
68
|
end
|
109
69
|
end
|
@@ -1,61 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SharkOnLambda
|
4
|
-
class ApiGatewayHandler
|
5
|
-
|
6
|
-
|
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,86 @@
|
|
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
|
-
|
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, fail_with_exception: true)
|
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:, fail_with_exception: false)
|
57
|
+
filename = "#{name}.yml"
|
58
|
+
config_file = SharkOnLambda.root.join('config', filename)
|
59
|
+
unless config_file.exist?
|
60
|
+
return {} unless fail_with_exception
|
61
|
+
|
62
|
+
raise ArgumentError,
|
63
|
+
"Could not load configuration. No such file - #{config_file}"
|
64
|
+
end
|
65
|
+
|
66
|
+
erb_parsed_config = ERB.new(config_file.read).result
|
67
|
+
config = YAML.safe_load(erb_parsed_config, [], [], true, filename) || {}
|
68
|
+
config.fetch(env, {}).with_indifferent_access
|
69
|
+
end
|
70
|
+
|
71
|
+
def load_routes
|
72
|
+
routes_path = SharkOnLambda.root.join('config', 'routes.rb').to_s
|
73
|
+
load routes_path if File.exist?(routes_path)
|
74
|
+
end
|
75
|
+
|
76
|
+
def register_jsonapi_rendering
|
77
|
+
::Mime::Type.register('application/vnd.api+json', :jsonapi)
|
78
|
+
::ActionDispatch::Request.parameter_parsers[:jsonapi] =
|
79
|
+
::ActionDispatch::Request.parameter_parsers[:json].dup
|
80
|
+
end
|
81
|
+
|
82
|
+
def run_initializers
|
83
|
+
initializers_folder = SharkOnLambda.root.join('config', 'initializers')
|
84
|
+
Dir.glob(initializers_folder.join('*.rb')).each { |path| load path }
|
85
|
+
end
|
14
86
|
end
|
15
87
|
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::
|
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
|
-
|
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
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SharkOnLambda
|
4
|
+
module Cacheable
|
5
|
+
delegate :cache, :global_cache, to: SharkOnLambda
|
6
|
+
|
7
|
+
def cache_duration(item)
|
8
|
+
cache_durations[item] || cache_durations[:default]
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def cache_durations
|
14
|
+
return @cache_durations if defined?(@cache_durations)
|
15
|
+
|
16
|
+
settings = SharkOnLambda.application.config_for(:settings) || {}
|
17
|
+
@cache_durations = settings.fetch(:cache_durations, {})
|
18
|
+
@cache_durations = @cache_durations.with_indifferent_access
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -2,63 +2,7 @@
|
|
2
2
|
|
3
3
|
module SharkOnLambda
|
4
4
|
class Configuration < OpenStruct
|
5
|
-
|
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
|