shark-on-lambda 1.0.0.rc4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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