shark-on-lambda 0.6.10 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/push-gem.yml +67 -0
  3. data/.github/workflows/tests.yml +32 -0
  4. data/README.md +10 -12
  5. data/changelog.md +11 -0
  6. data/gems.locked +73 -23
  7. data/lib/shark_on_lambda/api_gateway_handler.rb +61 -0
  8. data/lib/shark_on_lambda/application.rb +17 -0
  9. data/lib/shark_on_lambda/base_controller.rb +50 -0
  10. data/lib/shark_on_lambda/configuration.rb +9 -1
  11. data/lib/shark_on_lambda/dispatcher.rb +26 -0
  12. data/lib/shark_on_lambda/errors/base.rb +47 -0
  13. data/lib/shark_on_lambda/errors/base_serializer.rb +18 -0
  14. data/lib/shark_on_lambda/jsonapi_controller.rb +29 -0
  15. data/lib/shark_on_lambda/jsonapi_parameters.rb +66 -0
  16. data/lib/shark_on_lambda/jsonapi_renderer.rb +115 -0
  17. data/lib/shark_on_lambda/middleware/base.rb +23 -0
  18. data/lib/shark_on_lambda/middleware/jsonapi_rescuer.rb +31 -0
  19. data/lib/shark_on_lambda/middleware/rescuer.rb +38 -0
  20. data/lib/shark_on_lambda/query.rb +67 -0
  21. data/lib/shark_on_lambda/rack_adapters/api_gateway.rb +127 -0
  22. data/lib/shark_on_lambda/request.rb +9 -0
  23. data/lib/shark_on_lambda/response.rb +6 -0
  24. data/lib/shark_on_lambda/rspec/env_builder.rb +64 -0
  25. data/lib/shark_on_lambda/rspec/helpers.rb +84 -0
  26. data/lib/shark_on_lambda/rspec/jsonapi_helpers.rb +27 -0
  27. data/lib/shark_on_lambda/version.rb +1 -1
  28. data/lib/shark_on_lambda.rb +25 -28
  29. data/shark-on-lambda.gemspec +8 -3
  30. metadata +104 -24
  31. data/.gitlab-ci.yml +0 -39
  32. data/.travis.yml +0 -14
  33. data/lib/shark_on_lambda/api_gateway/base_controller.rb +0 -76
  34. data/lib/shark_on_lambda/api_gateway/base_handler.rb +0 -82
  35. data/lib/shark_on_lambda/api_gateway/concerns/http_response_validation.rb +0 -61
  36. data/lib/shark_on_lambda/api_gateway/errors.rb +0 -49
  37. data/lib/shark_on_lambda/api_gateway/headers.rb +0 -37
  38. data/lib/shark_on_lambda/api_gateway/jsonapi_controller.rb +0 -77
  39. data/lib/shark_on_lambda/api_gateway/jsonapi_parameters.rb +0 -68
  40. data/lib/shark_on_lambda/api_gateway/jsonapi_renderer.rb +0 -105
  41. data/lib/shark_on_lambda/api_gateway/parameters.rb +0 -18
  42. data/lib/shark_on_lambda/api_gateway/query.rb +0 -69
  43. data/lib/shark_on_lambda/api_gateway/request.rb +0 -148
  44. data/lib/shark_on_lambda/api_gateway/response.rb +0 -82
  45. data/lib/shark_on_lambda/api_gateway/serializers/base_error_serializer.rb +0 -20
  46. data/lib/shark_on_lambda/concerns/filter_actions.rb +0 -93
  47. data/lib/shark_on_lambda/tasks/build.rake +0 -146
  48. data/lib/shark_on_lambda/tasks.rb +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6436ab76f14afebb7ef7601936489cd9304db7f6591db4262f29b76f1561cfd0
4
- data.tar.gz: eab44e17a31afc1933b6be70401b89f0d935c49871e65dfd6edc69c5e5334580
3
+ metadata.gz: 9de95366ac135aebf072c6ecdbb5cae42b25f072bffdd1e01bee446e8262f17b
4
+ data.tar.gz: a09d5288e281447de50cfbbd8f97a18c023d9750e5d5b5ab456f4d6187b229a6
5
5
  SHA512:
6
- metadata.gz: '08b36668e651e1448a6075990c11682188819cd45c0a654d4f1798ceafca83a2f7af52be9c25e49d6104820ff55c5bbdfb5d50751c6201d44378deb63d38a0c6'
7
- data.tar.gz: '08b8b93027da580a481c9f7ea91de8b0ef488dd4096a9ab7430f6939b2b4238d40987a822d005d9f7e111de36bb58c1227d0407d063d593d54b5313392d9670a'
6
+ metadata.gz: 9643f2cb448d20396f43ab9fd124e0aca1ae436773f1b29626ce44a644f12f6bd1477deb5c468a30b1992d824d1bf6049f8340705c11dde6a65432f1104bba38
7
+ data.tar.gz: '09d2eb6a2ffb09b969f3cd383a0f9a19ee6bd68fbf32b37ba1fc0acab488144dcf38d516788b421b601158d390e4eee162500c65efcb25e89f979ac4bb487c21'
@@ -0,0 +1,67 @@
1
+ name: Push Gem
2
+ on:
3
+ push:
4
+ tags:
5
+ - 'v*'
6
+
7
+ jobs:
8
+ rspec:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v1
12
+ - name: Set up Ruby 2.5
13
+ uses: actions/setup-ruby@v1
14
+ with:
15
+ ruby-version: 2.5.x
16
+ - name: Run RSpec
17
+ run: |
18
+ gem install bundler
19
+ bundle install --jobs 4 --retry 3
20
+ bundle exec rspec
21
+
22
+ rubocop:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@v1
26
+ - name: Set up Ruby 2.5
27
+ uses: actions/setup-ruby@v1
28
+ with:
29
+ ruby-version: 2.5.x
30
+ - name: Run rubocop
31
+ run: |
32
+ gem install bundler
33
+ bundle install --jobs 4 --retry 3
34
+ bundle exec rubocop
35
+
36
+ push-gem:
37
+ runs-on: ubuntu-latest
38
+ steps:
39
+ - uses: actions/checkout@master
40
+ - name: Set up Ruby 2.5
41
+ uses: actions/setup-ruby@v1
42
+ with:
43
+ ruby-version: 2.5.x
44
+ - name: Build gem
45
+ run: |
46
+ gem install bundler
47
+ bundle install --jobs 4 --retry 3
48
+ bundle exec rake build
49
+ - name: Push to GitHub Package Repository
50
+ run: |
51
+ mkdir -p $HOME/.gem
52
+ echo ":github: Bearer $GEM_HOST_API_KEY" >> $HOME/.gem/credentials
53
+ chmod 0600 $HOME/.gem/credentials
54
+ bundle exec rake build
55
+ gem push --key github --host https://rubygems.pkg.github.com/Skudo pkg/`ls -1t pkg | head -1`
56
+ env:
57
+ GEM_HOST_API_KEY: ${{secrets.GITHUB_AUTH_TOKEN}}
58
+ OWNER: username
59
+ - name: Push to RubyGems
60
+ run: |
61
+ mkdir -p $HOME/.gem
62
+ echo ":rubygems_api_key: $GEM_HOST_API_KEY" >> ~/.gem/credentials
63
+ chmod 0600 $HOME/.gem/credentials
64
+ bundle exec rake build
65
+ gem push pkg/`ls -1t pkg | head -1`
66
+ env:
67
+ GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}
@@ -0,0 +1,32 @@
1
+ name: Tests
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ rspec:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v1
10
+ - name: Set up Ruby 2.5
11
+ uses: actions/setup-ruby@v1
12
+ with:
13
+ ruby-version: 2.5.x
14
+ - name: Run RSpec
15
+ run: |
16
+ gem install bundler
17
+ bundle install --jobs 4 --retry 3
18
+ bundle exec rspec
19
+
20
+ rubocop:
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v1
24
+ - name: Set up Ruby 2.5
25
+ uses: actions/setup-ruby@v1
26
+ with:
27
+ ruby-version: 2.5.x
28
+ - name: Run rubocop
29
+ run: |
30
+ gem install bundler
31
+ bundle install --jobs 4 --retry 3
32
+ bundle exec rubocop
data/README.md CHANGED
@@ -1,6 +1,5 @@
1
1
  # shark-on-lambda
2
-
3
- [![Travis CI Build Status](https://travis-ci.org/Skudo/shark-on-lambda.svg?branch=develop)](https://travis-ci.org/Skudo/shark-on-lambda)
2
+ [![GitHub Actions Test Status](https://github.com/Skudo/shark-on-lambda/workflows/Tests/badge.svg?branch=develop)](https://github.com/Skudo/shark-on-lambda/actions)
4
3
  [![CodeClimate Maintainability Score](https://api.codeclimate.com/v1/badges/fb0c16b3c6212f97b753/maintainability)](https://codeclimate.com/github/Skudo/shark-on-lambda/maintainability)
5
4
 
6
5
  `shark-on-lambda` provides a lightweight framework to write Ruby on AWS Lambda
@@ -24,8 +23,7 @@ maintaining a smaller memory footprint.
24
23
 
25
24
  ## Changelog
26
25
 
27
- ### Pre-1.0
28
- * Supports events from the API Gateway.
26
+ Have a look at the [actual changelog](changelog.md).
29
27
 
30
28
  ## Installation
31
29
 
@@ -50,11 +48,11 @@ are triggered by HTTP requests on the API Gateway. They also are responsible for
50
48
  responding with a well-formed response to the caller.
51
49
 
52
50
  ```ruby
53
- class MyHandler < SharkOnLambda::ApiGateway::BaseHandler
51
+ class MyHandler < SharkOnLambda::BaseHandler
54
52
  end
55
53
  ```
56
54
 
57
- By inheriting from `SharkOnLambda::ApiGateway::BaseHandler`, your own handler
55
+ By inheriting from `SharkOnLambda::BaseHandler`, your own handler
58
56
  class is indirectly tied to your controller class by convention: It assumes
59
57
  the controller name is `MyController` and it will dispatch events to that
60
58
  controller.
@@ -63,7 +61,7 @@ If you however bring your own class with a different name, you can configure
63
61
  your handler to use that controller instead:
64
62
 
65
63
  ```ruby
66
- class MyHandler < SharkOnLambda::ApiGateway::BaseHandler
64
+ class MyHandler < SharkOnLambda::BaseHandler
67
65
  self.controller_class = AnotherController
68
66
  end
69
67
  ```
@@ -72,7 +70,7 @@ All controller methods are going to be automagically mapped to class methods
72
70
  on the handler class.
73
71
 
74
72
  ```ruby
75
- class MyController < SharkOnLambda::ApiGateway::BaseController
73
+ class MyController < SharkOnLambda::BaseController
76
74
  def index
77
75
  end
78
76
 
@@ -80,7 +78,7 @@ class MyController < SharkOnLambda::ApiGateway::BaseController
80
78
  end
81
79
  end
82
80
 
83
- class MyHandler < SharkOnLambda::ApiGateway::BaseHandler
81
+ class MyHandler < SharkOnLambda::BaseHandler
84
82
  end
85
83
  ```
86
84
 
@@ -103,7 +101,7 @@ functions you may know from Rails and `render` does not really support multiple
103
101
  renderers (yet).
104
102
 
105
103
  ```ruby
106
- class MyController < SharkOnLambda::ApiGateway::BaseController
104
+ class MyController < SharkOnLambda::BaseController
107
105
  def index
108
106
  # Make the API Gateway respond with a 201 response saying "Hello, World!"
109
107
  # in the response body.
@@ -124,7 +122,7 @@ end
124
122
  ### _JSON API_-compliant controllers
125
123
 
126
124
  If you inherit your controller from
127
- `SharkOnLambda::ApiGateway::JsonapiController`, `render` and `redirect_to` will
125
+ `SharkOnLambda::JsonapiController`, `render` and `redirect_to` will
128
126
  create _JSON API_-compliant responses.
129
127
 
130
128
  You however __must__ have a serialiser for the objects you want to render.
@@ -141,7 +139,7 @@ _JSON API_ compatibility. Therefore, we expect the serialisers to be inherited
141
139
  from `::JSONAPI::Serializable::Resource` (or `::JSONAPI::Serializable::Error`).
142
140
 
143
141
  ```ruby
144
- class SomethingSerializer < ::JSONAPI::Serializable::Resource
142
+ class SomethingSerializer < JSONAPI::Serializable::Resource
145
143
  type :somethings
146
144
 
147
145
  attributes :foo, :bar, :baz
data/changelog.md CHANGED
@@ -1,5 +1,16 @@
1
1
  ## Changelog
2
2
 
3
+ #### Unreleaesed
4
+
5
+ - [Break] HTTP redirection now uses the status code `302`.
6
+ - [Break] Remove the `ApiGateway` namespace, move all items from that namespace up by one level.
7
+ - [Break] Remove build rake tasks.
8
+ - Added support for Rack-compatible middleware.
9
+ - `SharkOnLambda::BaseController` now acts more like `ActionController::BaseController`.
10
+ - Support `ActiveModel::Errors` nested validation errors.
11
+ - Added `SharkOnLambda::RSpec::Helpers` and `SharkOnLambda::RSpec::JsonapiHelpers`.
12
+ - Moved to GitHub.
13
+
3
14
  #### 0.6.10
4
15
 
5
16
  - Upgrade `rack` for good measure.
data/gems.locked CHANGED
@@ -1,14 +1,29 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shark-on-lambda (0.6.10)
4
+ shark-on-lambda (1.0.0.rc1)
5
+ actionpack
5
6
  activesupport
6
7
  jsonapi-rb
7
- rack (>= 2.0.8)
8
+ rack (>= 2.0.8, < 3)
9
+ zeitwerk (~> 2.2)
8
10
 
9
11
  GEM
10
12
  remote: https://rubygems.org/
11
13
  specs:
14
+ actionpack (6.0.0)
15
+ actionview (= 6.0.0)
16
+ activesupport (= 6.0.0)
17
+ rack (~> 2.0)
18
+ rack-test (>= 0.6.3)
19
+ rails-dom-testing (~> 2.0)
20
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
21
+ actionview (6.0.0)
22
+ activesupport (= 6.0.0)
23
+ builder (~> 3.1)
24
+ erubi (~> 1.4)
25
+ rails-dom-testing (~> 2.0)
26
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
12
27
  activemodel (6.0.0)
13
28
  activesupport (= 6.0.0)
14
29
  activesupport (6.0.0)
@@ -18,14 +33,23 @@ GEM
18
33
  tzinfo (~> 1.1)
19
34
  zeitwerk (~> 2.1, >= 2.1.8)
20
35
  ast (2.4.0)
36
+ builder (3.2.4)
37
+ byebug (11.0.1)
38
+ coderay (1.1.2)
39
+ colorize (0.8.1)
21
40
  concurrent-ruby (1.1.5)
41
+ crass (1.0.6)
22
42
  diff-lcs (1.3)
23
43
  docile (1.3.2)
24
- factory_bot (5.1.0)
44
+ erubi (1.9.0)
45
+ factory_bot (5.1.1)
25
46
  activesupport (>= 4.2.0)
26
- i18n (1.6.0)
47
+ fasterer (0.8.2)
48
+ colorize (~> 0.7)
49
+ ruby_parser (>= 3.14.1)
50
+ i18n (1.7.0)
27
51
  concurrent-ruby (~> 1.0)
28
- jaro_winkler (1.5.3)
52
+ jaro_winkler (1.5.4)
29
53
  json (2.2.0)
30
54
  jsonapi-deserializable (0.2.0)
31
55
  jsonapi-rb (0.5.0)
@@ -34,27 +58,47 @@ GEM
34
58
  jsonapi-renderer (0.2.2)
35
59
  jsonapi-serializable (0.3.1)
36
60
  jsonapi-renderer (~> 0.2.0)
37
- minitest (5.12.0)
38
- parallel (1.17.0)
39
- parser (2.6.4.1)
61
+ loofah (2.4.0)
62
+ crass (~> 1.0.2)
63
+ nokogiri (>= 1.5.9)
64
+ method_source (0.9.2)
65
+ mini_portile2 (2.4.0)
66
+ minitest (5.13.0)
67
+ nokogiri (1.10.8)
68
+ mini_portile2 (~> 2.4.0)
69
+ parallel (1.18.0)
70
+ parser (2.6.5.0)
40
71
  ast (~> 2.4.0)
41
- rack (2.0.8)
72
+ pry (0.12.2)
73
+ coderay (~> 1.1.0)
74
+ method_source (~> 0.9.0)
75
+ pry-byebug (3.7.0)
76
+ byebug (~> 11.0)
77
+ pry (~> 0.10)
78
+ rack (2.2.2)
79
+ rack-test (1.1.0)
80
+ rack (>= 1.0, < 3)
81
+ rails-dom-testing (2.0.3)
82
+ activesupport (>= 4.2.0)
83
+ nokogiri (>= 1.6)
84
+ rails-html-sanitizer (1.3.0)
85
+ loofah (~> 2.3)
42
86
  rainbow (3.0.0)
43
87
  rake (13.0.0)
44
- rspec (3.8.0)
45
- rspec-core (~> 3.8.0)
46
- rspec-expectations (~> 3.8.0)
47
- rspec-mocks (~> 3.8.0)
48
- rspec-core (3.8.2)
49
- rspec-support (~> 3.8.0)
50
- rspec-expectations (3.8.4)
88
+ rspec (3.9.0)
89
+ rspec-core (~> 3.9.0)
90
+ rspec-expectations (~> 3.9.0)
91
+ rspec-mocks (~> 3.9.0)
92
+ rspec-core (3.9.0)
93
+ rspec-support (~> 3.9.0)
94
+ rspec-expectations (3.9.0)
51
95
  diff-lcs (>= 1.2.0, < 2.0)
52
- rspec-support (~> 3.8.0)
53
- rspec-mocks (3.8.1)
96
+ rspec-support (~> 3.9.0)
97
+ rspec-mocks (3.9.0)
54
98
  diff-lcs (>= 1.2.0, < 2.0)
55
- rspec-support (~> 3.8.0)
56
- rspec-support (3.8.2)
57
- rubocop (0.74.0)
99
+ rspec-support (~> 3.9.0)
100
+ rspec-support (3.9.0)
101
+ rubocop (0.76.0)
58
102
  jaro_winkler (~> 1.5.1)
59
103
  parallel (~> 1.10)
60
104
  parser (>= 2.6)
@@ -62,6 +106,9 @@ GEM
62
106
  ruby-progressbar (~> 1.7)
63
107
  unicode-display_width (>= 1.4.0, < 1.7)
64
108
  ruby-progressbar (1.10.1)
109
+ ruby_parser (3.14.2)
110
+ sexp_processor (~> 4.9)
111
+ sexp_processor (4.14.1)
65
112
  simplecov (0.17.1)
66
113
  docile (~> 1.1)
67
114
  json (>= 1.8, < 3)
@@ -72,7 +119,7 @@ GEM
72
119
  thread_safe (~> 0.1)
73
120
  unicode-display_width (1.6.0)
74
121
  yard (0.9.20)
75
- zeitwerk (2.1.10)
122
+ zeitwerk (2.2.1)
76
123
 
77
124
  PLATFORMS
78
125
  ruby
@@ -81,6 +128,9 @@ DEPENDENCIES
81
128
  activemodel
82
129
  bundler
83
130
  factory_bot
131
+ fasterer
132
+ pry
133
+ pry-byebug
84
134
  rake
85
135
  rspec
86
136
  rubocop
@@ -89,4 +139,4 @@ DEPENDENCIES
89
139
  yard
90
140
 
91
141
  BUNDLED WITH
92
- 2.1.2
142
+ 2.1.4
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
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)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SharkOnLambda
4
+ class Application
5
+ def call(env)
6
+ dup.send('_call', env)
7
+ end
8
+
9
+ private
10
+
11
+ def _call(env)
12
+ dispatcher = SharkOnLambda.config.dispatcher
13
+ middleware_stack = SharkOnLambda.config.middleware.build(dispatcher)
14
+ middleware_stack.call(env)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SharkOnLambda
4
+ class BaseController < ActionController::Metal
5
+ EXCLUDED_MODULES = [
6
+ AbstractController::Translation,
7
+ AbstractController::AssetPaths,
8
+
9
+ ActionController::UrlFor,
10
+ ActionController::ConditionalGet,
11
+ ActionController::EtagWithTemplateDigest,
12
+ ActionController::EtagWithFlash,
13
+ ActionController::Caching,
14
+ ActionController::MimeResponds,
15
+ ActionController::ImplicitRender,
16
+ ActionController::Cookies,
17
+ ActionController::Flash,
18
+ ActionController::FormBuilder,
19
+ ActionController::RequestForgeryProtection,
20
+ ActionController::ContentSecurityPolicy,
21
+ ActionController::ForceSSL,
22
+ ActionController::HttpAuthentication::Basic::ControllerMethods,
23
+ ActionController::HttpAuthentication::Digest::ControllerMethods,
24
+ ActionController::HttpAuthentication::Token::ControllerMethods,
25
+ ActionView::Layouts
26
+ ].freeze
27
+ ActionController::Base.without_modules(EXCLUDED_MODULES).each do |mod|
28
+ include mod
29
+ end
30
+
31
+ def self.dispatch(*)
32
+ super
33
+ rescue AbstractController::ActionNotFound,
34
+ AbstractController::DoubleRenderError,
35
+ ActionController::ActionControllerError => e
36
+ raise Errors[500], e.message
37
+ end
38
+
39
+ def redirect_to(*)
40
+ super
41
+ self.response_body = '' if no_body?
42
+ end
43
+
44
+ private
45
+
46
+ def no_body?
47
+ response.status.in?(Response::NO_CONTENT_CODES)
48
+ end
49
+ end
50
+ end
@@ -4,7 +4,7 @@ module SharkOnLambda
4
4
  class Configuration < OpenStruct
5
5
  include Concerns::ResettableSingleton
6
6
 
7
- attr_writer :stage
7
+ attr_writer :dispatcher, :stage
8
8
 
9
9
  class << self
10
10
  include Concerns::YamlConfigLoader
@@ -56,6 +56,14 @@ module SharkOnLambda
56
56
  end
57
57
  end
58
58
 
59
+ def dispatcher
60
+ @dispatcher ||= Dispatcher.new
61
+ end
62
+
63
+ def middleware
64
+ @middleware ||= ActionDispatch::MiddlewareStack.new
65
+ end
66
+
59
67
  def root
60
68
  @root ||= Pathname.new('.')
61
69
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SharkOnLambda
4
+ class Dispatcher
5
+ def call(env)
6
+ request = Request.new(env)
7
+ response = Response.new
8
+
9
+ controller = controller_class(env)
10
+ action = controller_action(env)
11
+ controller.dispatch(action, request, response)
12
+
13
+ response.prepare!
14
+ end
15
+
16
+ private
17
+
18
+ def controller_action(env)
19
+ env['shark.action']
20
+ end
21
+
22
+ def controller_class(env)
23
+ env['shark.controller'].camelize.constantize
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SharkOnLambda
4
+ module Errors
5
+ class Base < StandardError
6
+ attr_accessor :id, :code, :meta, :pointer, :parameter
7
+ attr_writer :detail
8
+
9
+ def self.status(status_code)
10
+ define_method :status do
11
+ status_code
12
+ end
13
+ end
14
+
15
+ def detail
16
+ return @detail if @detail.present?
17
+ return nil if message == self.class.name
18
+
19
+ message
20
+ end
21
+
22
+ def title
23
+ Rack::Utils::HTTP_STATUS_CODES[status]
24
+ end
25
+ end
26
+
27
+ def self.[](status_code)
28
+ @errors[status_code]
29
+ end
30
+
31
+ @errors = Rack::Utils::HTTP_STATUS_CODES.map do |status_code, message|
32
+ next unless (400..599).cover?(status_code) && message.present?
33
+
34
+ error_class = Class.new(Base) do
35
+ status status_code
36
+ end
37
+ class_name_parts = message.to_s.split(/\s+/)
38
+ class_name_parts.map! { |word| word.gsub(/[^a-z]/i, '').capitalize }
39
+ class_name = class_name_parts.join('')
40
+ const_set(class_name, error_class)
41
+
42
+ [status_code, error_class]
43
+ end
44
+ @errors.compact!
45
+ @errors = @errors.to_h
46
+ end
47
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SharkOnLambda
4
+ module Errors
5
+ class BaseSerializer < JSONAPI::Serializable::Error
6
+ id { @object.id }
7
+ status { @object.status }
8
+ code { @object.code }
9
+ title { @object.title }
10
+ detail { @object.detail }
11
+ meta { @object.meta }
12
+ source do
13
+ pointer @object.pointer if @object.pointer.present?
14
+ parameter @object.parameter if @object.parameter.present?
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SharkOnLambda
4
+ class JsonapiController < BaseController
5
+ ActionController::Renderers.add :jsonapi do |object, options|
6
+ response.set_header('content-type', 'application/vnd.api+json')
7
+ return { data: {} }.to_json if object.nil?
8
+
9
+ jsonapi_params = JsonapiParameters.new(params)
10
+ jsonapi_renderer = JsonapiRenderer.new
11
+ render_options = jsonapi_params.to_h.deep_merge(options)
12
+
13
+ jsonapi_renderer.render(object, render_options)
14
+ end
15
+
16
+ def redirect_to(options = {}, response_status = {})
17
+ super
18
+ return if response_status[:status] == 304
19
+
20
+ self.response_body = { data: {} }.to_json
21
+ end
22
+
23
+ def render(object, options = {})
24
+ options.merge!(jsonapi: object, content_type: 'application/vnd.api+json')
25
+
26
+ super(options)
27
+ end
28
+ end
29
+ end