shark-on-lambda 1.0.0.rc4 → 1.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f6a831332c510a5977edd5ca1db24a68a9cf7cc323433fb807f5b65a707df0e7
4
- data.tar.gz: 9beabc2ae1d3d81d9a6b10d80b69668629d902726c535dc3aec403db4ac38c36
3
+ metadata.gz: e858c687476151fddf9bc5d464c7845f09680b389fe2a31fe2d72f21c7d2403d
4
+ data.tar.gz: 4fb28a197425d9f26c28fe4c807d0548add701b8b2cea902987c1244c0ac1318
5
5
  SHA512:
6
- metadata.gz: b607fdff10e8ff558fb85e3d92bc9697e783aaf2f856822fe84591101f974d89af3cd9a11c41640409c5f0590fb9ef0bf9b0c86e68029112388cd0a110283a08
7
- data.tar.gz: 4ea5be6f0d30ce7b6f4a05632a9b9c1c96ce18673cb52be4907cdf726fb56982052a06f16874eeb772947ad387b2472d3079e585087146aee7865035ef6a42f7
6
+ metadata.gz: 3a420db54811cc256092094caa222be976d525ffd0d0b64da5fe0640b0d98287894c114ca1d16c6f735132bfe59f0480f0191902a8c9bfef296bd3cb0c70ae81
7
+ data.tar.gz: 4fbd6882b0dba434fc6781f3a831db2fddb10f38501d90008a09ce0ca1aa5e44294e34ba4f4ab4e103fb334e983531fef740f59d6fe868a3f28173b2079f169f
data/.gitignore CHANGED
@@ -2,15 +2,14 @@
2
2
  /.yardoc
3
3
  /_yardoc/
4
4
  /coverage/
5
- /doc/
6
5
  /pkg/
7
6
  /spec/reports/
8
7
  /tmp/
9
8
 
9
+ gems.locked
10
+
10
11
  # rspec failure tracking
11
12
  .rspec_status
12
13
 
13
14
  # Add gems to `vendor/cache`
14
15
  vendor/cache/*
15
- !vendor/cache/bima*.gem
16
- !vendor/cache/shark*.gem
data/README.md CHANGED
@@ -25,12 +25,19 @@ maintaining a smaller memory footprint.
25
25
 
26
26
  Have a look at the [actual changelog](changelog.md).
27
27
 
28
+ ## Upgrading?
29
+
30
+ If you are upgrading from a previous version of `shark-on-lambda`, these
31
+ upgrade guides might be of some help to you.
32
+
33
+ * [Upgrading from `v0.6.x` to `v1.x`](doc/upgrade-from-0.6.x-to-1.x.md)
34
+
28
35
  ## Installation
29
36
 
30
37
  Add this line to your application's `gems.rb`:
31
38
 
32
39
  ```ruby
33
- gem 'shark_on_lambda'
40
+ gem 'shark-on-lambda'
34
41
  ```
35
42
 
36
43
  And then execute:
@@ -39,7 +46,7 @@ And then execute:
39
46
 
40
47
  Or install it yourself:
41
48
 
42
- $ gem install shark_on_lambda
49
+ $ gem install shark-on-lambda
43
50
 
44
51
  ## Handlers
45
52
 
@@ -48,11 +55,11 @@ are triggered by HTTP requests on the API Gateway. They also are responsible for
48
55
  responding with a well-formed response to the caller.
49
56
 
50
57
  ```ruby
51
- class MyHandler < SharkOnLambda::BaseHandler
58
+ class MyHandler < SharkOnLambda::ApiGatewayHandler
52
59
  end
53
60
  ```
54
61
 
55
- By inheriting from `SharkOnLambda::BaseHandler`, your own handler
62
+ By inheriting from `SharkOnLambda::ApiGatewayHandler`, your own handler
56
63
  class is indirectly tied to your controller class by convention: It assumes
57
64
  the controller name is `MyController` and it will dispatch events to that
58
65
  controller.
@@ -78,7 +85,7 @@ class MyController < SharkOnLambda::BaseController
78
85
  end
79
86
  end
80
87
 
81
- class MyHandler < SharkOnLambda::BaseHandler
88
+ class MyHandler < SharkOnLambda::ApiGatewayHandler
82
89
  end
83
90
  ```
84
91
 
@@ -89,16 +96,13 @@ handler class method is called.
89
96
 
90
97
  ## Controllers
91
98
 
92
- Controllers are similar to Rails controllers: In addition to having access to
93
- the AWS Lambda `event` and `context` objects, you also have access to `params`,
94
- `request`, and `response` objects that are derived from the `event` object.
99
+ Controllers are similar to Rails controllers: You have access to `params`,
100
+ `request`, and `response` objects that contain informatoni retrieved from the
101
+ AWS Lambda `event` object.
95
102
 
96
103
  ### "Basic" controllers
97
104
 
98
- You also have access to the `render` and `redirect_to` methods __that are not as
99
- powerful as the Rails equivalent by far__. There are none of the `render_*`
100
- functions you may know from Rails and `render` does not really support multiple
101
- renderers (yet).
105
+ You also have access to the `render` and `redirect_to`.
102
106
 
103
107
  ```ruby
104
108
  class MyController < SharkOnLambda::BaseController
@@ -113,17 +117,19 @@ class MyController < SharkOnLambda::BaseController
113
117
  def show
114
118
  # Does what you think it does.
115
119
  #
116
- # The default status code for `redirect_to` is 307.
117
- redirect_to 'https://github.com', status: 302
120
+ # The default status code for `redirect_to` is 302.
121
+ redirect_to 'https://github.com', status: 307
118
122
  end
119
123
  end
120
124
  ```
121
125
 
126
+ `before_action`, `around_action`, and `after_action` filters also are available,
127
+ as well as `rescue_from`.
128
+
122
129
  ### _JSON API_-compliant controllers
123
130
 
124
- If you inherit your controller from
125
- `SharkOnLambda::JsonapiController`, `render` and `redirect_to` will
126
- create _JSON API_-compliant responses.
131
+ If you inherit your controller from `SharkOnLambda::JsonapiController`,
132
+ `render` and `redirect_to` will create _JSON API_-compliant responses.
127
133
 
128
134
  You however __must__ have a serialiser for the objects you want to render.
129
135
  Otherwise, rendering will fail and you will receive an _Internal Server Error_
@@ -196,6 +202,53 @@ If `SharkOnLambda.config.stage` was set inside the block passed to
196
202
  the default set (the `default` node in the YAML files) of configuration and
197
203
  secrets, overwriting values where applicable.
198
204
 
205
+ ## Test helpers
206
+
207
+ By including `SharkOnLambda::RSpec::Helpers` in your RSpec test suite, you can
208
+ use `delete`, `get`, `patch`, `post`, and `put` methods, which will return
209
+ a `Rack::MockResponse` object. You can also access that response object in your
210
+ test examples by calling `response`, but only after you've called either of the
211
+ aforementioned methods. Otherwise, an exception will be raised.
212
+
213
+ You can include the test helpers like this in your `spec/spec_helper.rb`.
214
+
215
+ ```ruby
216
+ RSpec.configure do |config|
217
+ config.include SharkOnLambda::RSpec::Helpers
218
+ end
219
+ ```
220
+
221
+ ### _JSON API_ helpers
222
+
223
+ By including `SharkOnLambda::RSpec::JsonapiHelpers`, you gain all the goodies
224
+ from `SharkOnLambda::RSpec::Helpers` _and_ access to `jsonapi_data` and
225
+ `jsonapi_errors` methods, which contain the `data` and `errors` keys of the
226
+ parsed response body respectively. In addition to that, there is
227
+ `jsonapi_attributes`, which returns the `attributes` key from `jsonapi_data`.
228
+
229
+ ## _Rack_ compatibility
230
+
231
+ As `SharkOnLambda.application` is a _Rack_-compatible application, treating it
232
+ as such and using existing _Rack_ middleware is straightforward.
233
+
234
+ ### Using _Rack_ middleware
235
+
236
+ The middleware stack can be found at `SharkOnLambda.config.middleware`. Adding
237
+ middleware to your stack can be either done by calling `#use`:
238
+
239
+ ```ruby
240
+ SharkOnLambda.config.middleware.use Your::Middleware
241
+ ```
242
+
243
+ You can also just set up your middleware stack during your
244
+ `SharkOnLambda.initialize!` call:
245
+
246
+ ```ruby
247
+ SharkOnLambda.initialize! do |config, secrets|
248
+ config.middleware.use Your::Middleware
249
+ end
250
+ ```
251
+
199
252
  ## Development
200
253
 
201
254
  Clone this repository and change away. Then, once you are done, please submit
data/changelog.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ## Changelog
2
2
 
3
- #### Unreleaesed
3
+ #### 1.0.0
4
4
 
5
5
  - [Break] HTTP redirection now uses the status code `302`.
6
6
  - [Break] Remove the `ApiGateway` namespace, move all items from that namespace up by one level.
@@ -0,0 +1,122 @@
1
+ # Upgrading from version `0.6.x` to version `1.x`
2
+
3
+ ## Mandatory changes
4
+
5
+ ### `SharkOnLambda::ApiGateway::*` => `SharkOnLambda::*`
6
+
7
+ The `ApiGateway` module was removed in favour of a shallower hierarchy, because
8
+ `shark-on-lambda` only really does lifting work in an HTTP request context.
9
+
10
+ ### `SharkOnLambda::ApiGateway::BaseHandler` => `SharkOnLambda::ApiGatewayHandler`
11
+
12
+ In an attempt to make the ties to the _API Gateway_ a bit more explicit, the
13
+ handler base class now is `SharkOnLambda::ApiGatewayHandler` instead of what
14
+ might be expected to be `SharkOnLambda::BaseHandler`.
15
+
16
+ ### Use `SharkOnLambda::RSpec::JsonapiHelpers` (or `SharkOnLambda::RSpec::Helpers`)
17
+
18
+ Until now, making a request to your application has involved building your own
19
+ _API Gateway_ event object and then passing it to your handler/controller.
20
+
21
+ If you have been passing the event object to your handlers solely, this change
22
+ is optional. If you however have been passing the event object to your
23
+ controllers, upgrading `shark-on-lambda` to `v1.x` makes changing the way your
24
+ tests run a necessity, because controller do not know about _API Gateway_ events
25
+ anymore and thus cannot handle them properly.
26
+
27
+ The recommended way to test controllers is to use
28
+ `SharkOnLambda::RSpec::JsonapiHelpers` (or `SharkOnLambda::RSpec::Helpers`) in
29
+ your RSpec tests and then use the methods `delete`, `get`, `patch`, `post`, or
30
+ `put` to test your controllers like this:
31
+
32
+ ```ruby
33
+ RSpec.describe MyController do
34
+ let!(:service_token) { 'my-super-secret-service-token' }
35
+ let!(:headers) do
36
+ {
37
+ 'authorization' => "Bearer #{service_token}"
38
+ }
39
+ end
40
+ let!(:params) do
41
+ {
42
+ id: 1
43
+ }
44
+ end
45
+
46
+ subject { get :show, headers: headers, params: params }
47
+
48
+ it { expect(subject.status).to eq(200) }
49
+ end
50
+ ```
51
+
52
+ If you, for some reason, want to distinguish between `params` and
53
+ `path_parameters`, you can also pass in `path_parameters` using the
54
+ `path_parameters:` keyword argument like this:
55
+
56
+ ```ruby
57
+ get :show, headers: headers, params: params, path_parameters: path_parameters
58
+ ```
59
+
60
+ Using `SharkOnLambda::RSpec::JsonapiHelpers` or `SharkOnLambda::RSpec::Helpers`
61
+ also lets you access the `response` object in your test examples. This object
62
+ is an instance of `Rack::MockResponse`, which you might be familiar with from
63
+ e. g. controller testing in Rails.
64
+
65
+ You can use these helpers by e. g. setting them up in `spec/spec_helper.rb`:
66
+
67
+ ```ruby
68
+ RSpec.configure do |config|
69
+ config.include SharkOnLambda::RSpec::JsonapiHelpers
70
+ end
71
+ ```
72
+
73
+ ## Recommended changes
74
+
75
+ ### Move to a _Rack_-compatible implementation for CORS headers
76
+
77
+ Until now, the way to add CORS headers prior to sending the response to the
78
+ _API Gateway_ has been to "decorate" the `#call` method in your handler, e. g.
79
+ using a module like
80
+
81
+ ```ruby
82
+ module CORS
83
+ def call(action, event:, context:)
84
+ response = super
85
+ response[:headers].reverse_merge!(
86
+ 'access-control-allow-origin' => '*',
87
+ 'access-control-allow-credentials' => 'true'
88
+ )
89
+ response
90
+ end
91
+ end
92
+ ```
93
+
94
+ and then including it in your handler:
95
+
96
+ ```ruby
97
+ class MyHandler < SharkOnLambda::ApiGateway::BaseHandler
98
+ include CORS
99
+ end
100
+ ```
101
+
102
+ This _still_ works for the time being, but it is recommended to switch to an
103
+ approach based on using _Rack_ middleware, e. g. `rack-cors` or implementing
104
+ your own middleware.
105
+
106
+ ### Use `SharkOnLambda::Middleware::JsonapiRescuer` (or `SharkOnLambda::Middleware::Rescuer`)
107
+
108
+ Until now, `shark-on-lambda` has caught all uncaught exceptions before building
109
+ the response object for _API Gateway_, turning those exceptions into sensible
110
+ response objects.
111
+
112
+ This behaviour changes drastically with `v1.0.0`: Exceptions are not being
113
+ caught by the main application anymore. Therefore, it is recommended to add
114
+ `SharkOnLambda::Middleware::JsonapiRescuer`
115
+ (or `SharkOnLambda::Middleware::Rescuer`) to your middleware stack to restore
116
+ this kind of behaviour.
117
+
118
+ ```ruby
119
+ SharkOnLambda.initialize! do |config, secrets|
120
+ config.middleware.use SharkOnLambda::Middleware::JsonapiRescuer
121
+ end
122
+ ```
@@ -3,12 +3,10 @@
3
3
  module SharkOnLambda
4
4
  class Application
5
5
  def call(env)
6
- dup.send('_call', env)
6
+ dup.call!(env)
7
7
  end
8
8
 
9
- private
10
-
11
- def _call(env)
9
+ def call!(env)
12
10
  dispatcher = SharkOnLambda.config.dispatcher
13
11
  middleware_stack = SharkOnLambda.config.middleware.build(dispatcher)
14
12
  middleware_stack.call(env)
@@ -7,10 +7,13 @@ module SharkOnLambda
7
7
  return { data: {} }.to_json if object.nil?
8
8
 
9
9
  jsonapi_params = JsonapiParameters.new(params)
10
- jsonapi_renderer = JsonapiRenderer.new
10
+ jsonapi_renderer = JsonapiRenderer.new(object)
11
11
  render_options = jsonapi_params.to_h.deep_merge(options)
12
12
 
13
- jsonapi_renderer.render(object, render_options)
13
+ jsonapi_object = jsonapi_renderer.render(render_options)
14
+ response.status = jsonapi_renderer.status
15
+
16
+ jsonapi_object.to_json
14
17
  end
15
18
 
16
19
  def redirect_to(options = {}, response_status = {})
@@ -2,21 +2,27 @@
2
2
 
3
3
  module SharkOnLambda
4
4
  class JsonapiRenderer
5
- def initialize(renderer: nil)
5
+ attr_reader :object, :status
6
+
7
+ def initialize(object, renderer: nil)
8
+ @object = object
6
9
  @renderer = renderer || JSONAPI::Serializable::Renderer.new
10
+
11
+ @status = 200
7
12
  end
8
13
 
9
- def render(object, options = {})
10
- object = transform_active_model_errors(object)
14
+ def render(options = {})
15
+ @status = options[:status] if options[:status]
16
+ object_to_render = transform_active_model_errors(object)
11
17
 
12
- unless renderable?(object, options)
13
- return handle_unrenderable_objects(object, options)
18
+ unless renderable?(object_to_render, options)
19
+ return handle_unrenderable_objects(object_to_render, options)
14
20
  end
15
21
 
16
- if error?(object)
17
- render_errors(object, options).to_json
22
+ if error?(object_to_render)
23
+ render_errors(object_to_render, options).to_json
18
24
  else
19
- render_success(object, options).to_json
25
+ render_success(object_to_render, options).to_json
20
26
  end
21
27
  end
22
28
 
@@ -54,6 +60,7 @@ module SharkOnLambda
54
60
  Errors[500].new("Could not find serializer for: #{item.name}.")
55
61
  end
56
62
 
63
+ @status = 500
57
64
  render_errors(errors, options)
58
65
  end
59
66
 
@@ -10,12 +10,10 @@ module SharkOnLambda
10
10
  end
11
11
 
12
12
  def call(env)
13
- dup.send('_call', env)
13
+ dup.call!(env)
14
14
  end
15
15
 
16
- private
17
-
18
- def _call(_env)
16
+ def call!(_env)
19
17
  raise NotImplementedError
20
18
  end
21
19
  end
@@ -11,24 +11,27 @@ module SharkOnLambda
11
11
  @tags = tags
12
12
  end
13
13
 
14
- private
15
-
16
- def _call(env)
17
- @env = env
14
+ def call!(env)
18
15
  app.call(env)
19
16
  rescue StandardError => e
20
- notify(e) unless shark_error?(e)
17
+ notify(e, env) unless shark_error?(e) && client_error?(e)
21
18
 
22
19
  raise e
23
20
  end
24
21
 
25
- def notify(error)
22
+ private
23
+
24
+ def client_error?(error)
25
+ error.respond_to?(:status) && error.status < 500
26
+ end
27
+
28
+ def notify(error, env)
26
29
  ::Honeybadger.notify(
27
30
  error,
28
31
  tags: tags,
29
- controller: @env['shark.controller'],
30
- action: @env['shark.action'],
31
- parameters: @env['action_dispatch.request.parameters']
32
+ controller: env['shark.controller'],
33
+ action: env['shark.action'],
34
+ parameters: env['action_dispatch.request.parameters']
32
35
  )
33
36
  end
34
37
 
@@ -10,9 +10,7 @@ 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
16
  end_time = Time.now
@@ -27,6 +25,8 @@ module SharkOnLambda
27
25
  response
28
26
  end
29
27
 
28
+ private
29
+
30
30
  def body_size(body)
31
31
  size = 0
32
32
  body.each { |chunk| size += chunk.bytesize }
@@ -3,9 +3,7 @@
3
3
  module SharkOnLambda
4
4
  module Middleware
5
5
  class Rescuer < Base
6
- private
7
-
8
- def _call(env)
6
+ def call!(env)
9
7
  app.call(env)
10
8
  rescue Errors::Base => e
11
9
  rescue_shark_error(e)
@@ -13,6 +11,8 @@ module SharkOnLambda
13
11
  rescue_standard_error(e)
14
12
  end
15
13
 
14
+ private
15
+
16
16
  def error_response(status, headers, message)
17
17
  response_body = Rack::BodyProxy.new([message]) do
18
18
  message.close if message.respond_to?(:close)
@@ -19,7 +19,7 @@ module SharkOnLambda
19
19
  'body' => body_content
20
20
  }
21
21
  response['isBase64Encoded'] = false if elb?
22
- response
22
+ response.with_indifferent_access
23
23
  end
24
24
 
25
25
  def env
@@ -3,7 +3,8 @@
3
3
  module SharkOnLambda
4
4
  module RSpec
5
5
  class EnvBuilder
6
- attr_reader :action, :controller, :headers, :method, :params
6
+ attr_reader :action, :controller, :headers, :method
7
+ attr_reader :params, :path_parameters
7
8
 
8
9
  def initialize(options = {})
9
10
  @method = options.fetch(:method).to_s.upcase
@@ -12,7 +13,8 @@ module SharkOnLambda
12
13
 
13
14
  @headers = (options[:headers] || {}).deep_stringify_keys
14
15
  @headers.transform_keys!(&:downcase)
15
- @params = options[:params]
16
+ @params = options[:params] || {}
17
+ @path_parameters = options[:path_parameters] || {}
16
18
 
17
19
  initialize_env
18
20
  add_headers
@@ -56,7 +58,8 @@ module SharkOnLambda
56
58
  method: method,
57
59
  params: params,
58
60
  'shark.controller' => controller,
59
- 'shark.action' => action
61
+ 'shark.action' => action,
62
+ 'shark.path_parameters' => path_parameters
60
63
  )
61
64
  end
62
65
 
@@ -39,7 +39,8 @@ module SharkOnLambda
39
39
  controller: controller_name,
40
40
  action: action,
41
41
  headers: options[:headers],
42
- params: options[:params]
42
+ params: options[:params],
43
+ path_parameters: options[:path_parameters]
43
44
  )
44
45
  env_builder.build
45
46
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SharkOnLambda
4
- VERSION = '1.0.0.rc4'
4
+ VERSION = '1.0.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shark-on-lambda
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.rc4
4
+ version: 1.0.0
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-03 00:00:00.000000000 Z
11
+ date: 2020-03-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -260,6 +260,7 @@ files:
260
260
  - bin/console
261
261
  - bin/setup
262
262
  - changelog.md
263
+ - doc/upgrade-from-0.6.x-to-1.x.md
263
264
  - gems.rb
264
265
  - lib/shark-on-lambda.rb
265
266
  - lib/shark_on_lambda.rb
@@ -307,9 +308,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
307
308
  version: '0'
308
309
  required_rubygems_version: !ruby/object:Gem::Requirement
309
310
  requirements:
310
- - - ">"
311
+ - - ">="
311
312
  - !ruby/object:Gem::Version
312
- version: 1.3.1
313
+ version: '0'
313
314
  requirements: []
314
315
  rubyforge_project:
315
316
  rubygems_version: 2.7.6.2