rack-on-lambda 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0f7ad6d89db4356964720a3d68ffa9a1c653e98dacbc75fa92acd574207447c9
4
+ data.tar.gz: 4ee99667a87bdbd3be31f7e9e7d5834c7395c738d50e55b41a2d9913b48a46dc
5
+ SHA512:
6
+ metadata.gz: cf68a5117d15b831fb46d3b0cb6972f53eed0d8dd809b65021595182613517b31d55cbe048351ca135c02644977bcde09fbe785f3e70d8aa41474e8d5b468064
7
+ data.tar.gz: 8a6e50798ec86cd68361c41e020bf519ec745e47868d38f3b69525392a2a1ba10737f84e71f22de2d9904be76ecd8b3e0a868726d1e2e946c962d3b4c9a2aadb
@@ -0,0 +1,96 @@
1
+ name: Push Gem
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ jobs:
9
+ rspec-ruby25:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v1
13
+ - name: Set up Ruby 2.5
14
+ uses: actions/setup-ruby@v1
15
+ with:
16
+ ruby-version: 2.5.x
17
+ - name: Run RSpec
18
+ run: |
19
+ gem install bundler
20
+ bundle install --jobs 4 --retry 3
21
+ bundle exec rspec
22
+
23
+ rubocop-ruby25:
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - uses: actions/checkout@v1
27
+ - name: Set up Ruby 2.5
28
+ uses: actions/setup-ruby@v1
29
+ with:
30
+ ruby-version: 2.5.x
31
+ - name: Run rubocop
32
+ run: |
33
+ gem install bundler
34
+ bundle install --jobs 4 --retry 3
35
+ bundle exec rubocop
36
+
37
+ rspec-ruby27:
38
+ runs-on: ubuntu-latest
39
+ steps:
40
+ - uses: actions/checkout@v1
41
+ - name: Set up Ruby 2.7
42
+ uses: actions/setup-ruby@v1
43
+ with:
44
+ ruby-version: 2.7.x
45
+ - name: Run RSpec
46
+ run: |
47
+ gem install bundler
48
+ bundle install --jobs 4 --retry 3
49
+ bundle exec rspec
50
+
51
+ rubocop-ruby27:
52
+ runs-on: ubuntu-latest
53
+ steps:
54
+ - uses: actions/checkout@v1
55
+ - name: Set up Ruby 2.7
56
+ uses: actions/setup-ruby@v1
57
+ with:
58
+ ruby-version: 2.7.x
59
+ - name: Run rubocop
60
+ run: |
61
+ gem install bundler
62
+ bundle install --jobs 4 --retry 3
63
+ bundle exec rubocop
64
+
65
+ push-gem:
66
+ runs-on: ubuntu-latest
67
+ steps:
68
+ - uses: actions/checkout@master
69
+ - name: Set up Ruby 2.5
70
+ uses: actions/setup-ruby@v1
71
+ with:
72
+ ruby-version: 2.5.x
73
+ - name: Build gem
74
+ run: |
75
+ gem install bundler
76
+ bundle install --jobs 4 --retry 3
77
+ bundle exec rake build
78
+ - name: Push to GitHub Package Repository
79
+ run: |
80
+ mkdir -p $HOME/.gem
81
+ echo ":github: Bearer $GEM_HOST_API_KEY" >> $HOME/.gem/credentials
82
+ chmod 0600 $HOME/.gem/credentials
83
+ bundle exec rake build
84
+ gem push --key github --host https://rubygems.pkg.github.com/Skudo pkg/`ls -1t pkg | head -1`
85
+ env:
86
+ GEM_HOST_API_KEY: ${{secrets.GH_AUTH_TOKEN}}
87
+ OWNER: username
88
+ - name: Push to RubyGems
89
+ run: |
90
+ mkdir -p $HOME/.gem
91
+ echo ":rubygems_api_key: $GEM_HOST_API_KEY" >> ~/.gem/credentials
92
+ chmod 0600 $HOME/.gem/credentials
93
+ bundle exec rake build
94
+ gem push pkg/`ls -1t pkg | head -1`
95
+ env:
96
+ GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}
@@ -0,0 +1,60 @@
1
+ name: Tests
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ rspec-ruby25:
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-ruby25:
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
33
+
34
+ rspec-ruby27:
35
+ runs-on: ubuntu-latest
36
+ steps:
37
+ - uses: actions/checkout@v1
38
+ - name: Set up Ruby 2.7
39
+ uses: actions/setup-ruby@v1
40
+ with:
41
+ ruby-version: 2.7.x
42
+ - name: Run RSpec
43
+ run: |
44
+ gem install bundler
45
+ bundle install --jobs 4 --retry 3
46
+ bundle exec rspec
47
+
48
+ rubocop-ruby27:
49
+ runs-on: ubuntu-latest
50
+ steps:
51
+ - uses: actions/checkout@v1
52
+ - name: Set up Ruby 2.7
53
+ uses: actions/setup-ruby@v1
54
+ with:
55
+ ruby-version: 2.7.x
56
+ - name: Run rubocop
57
+ run: |
58
+ gem install bundler
59
+ bundle install --jobs 4 --retry 3
60
+ bundle exec rubocop
@@ -0,0 +1,5 @@
1
+ .bundle
2
+ coverage
3
+
4
+ .rspec_status
5
+ gems.locked
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,21 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ TargetRubyVersion: 2.5
4
+
5
+ Metrics/BlockLength:
6
+ Exclude:
7
+ - 'spec/**/*_spec.rb'
8
+ - 'spec/factories/*.rb'
9
+ - 'spec/shared_examples/**/*.rb'
10
+
11
+ Layout/LineLength:
12
+ Max: 80
13
+
14
+ Naming/FileName:
15
+ Exclude:
16
+ - lib/rack-on-lambda.rb
17
+ - spec/rack-on-lambda_spec.rb
18
+
19
+ # TODO: Add documentation and remove the Style/Documentation exception.
20
+ Style/Documentation:
21
+ Enabled: false
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,6 @@
1
+ ## Changelog
2
+
3
+ #### Unreleased
4
+
5
+ #### 1.0.0
6
+ - Initial release.
data/gems.rb ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rack_on_lambda'
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+
5
+ require 'active_support/hash_with_indifferent_access'
6
+ require 'rack/body_proxy'
7
+ require 'rack/utils'
8
+ require 'rack/version'
9
+
10
+ require 'pry' if Gem.loaded_specs.key?('pry')
11
+
12
+ require_relative 'rack_on_lambda/version'
13
+
14
+ require_relative 'rack_on_lambda/response'
15
+ require_relative 'rack_on_lambda/query'
16
+ require_relative 'rack_on_lambda/adapters/rest_api'
17
+ require_relative 'rack_on_lambda/handlers/rest_api'
18
+
19
+ module RackOnLambda; end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RackOnLambda
4
+ module Adapters
5
+ class RestApi
6
+ attr_reader :context, :event
7
+
8
+ def initialize(context:, event:)
9
+ @context = context
10
+ @event = event.deep_stringify_keys
11
+ end
12
+
13
+ def env
14
+ @env ||= default_env.merge(env_request_metadata)
15
+ .merge(env_headers)
16
+ .merge(env_params)
17
+ .merge(env_body)
18
+ end
19
+
20
+ def response(status, headers, body)
21
+ Response.new(status, headers, body).as_json
22
+ end
23
+
24
+ private
25
+
26
+ def default_env
27
+ {
28
+ 'SCRIPT_NAME' => '',
29
+ 'rack.version' => Rack::VERSION,
30
+ 'rack.errors' => $stderr,
31
+ 'rack.multithread' => true,
32
+ 'rack.multiprocess' => true,
33
+ 'rack.run_once' => false
34
+ }
35
+ end
36
+
37
+ def env_body
38
+ result = event['body'] || ''
39
+ result = Base64.decode64(result) if event['isBase64Encoded']
40
+
41
+ {
42
+ 'rack.input' => StringIO.new(result).set_encoding(Encoding::BINARY),
43
+ 'CONTENT_LENGTH' => result.bytesize.to_s
44
+ }
45
+ end
46
+
47
+ def env_headers
48
+ result = {}
49
+ http_headers.each_pair do |header, value|
50
+ key = key_for_header(header)
51
+ result[key] = value.to_s
52
+ end
53
+ result
54
+ end
55
+
56
+ def env_params
57
+ {
58
+ 'QUERY_STRING' => query_string
59
+ }
60
+ end
61
+
62
+ def env_request_metadata
63
+ {
64
+ 'REQUEST_METHOD' => event['httpMethod'],
65
+ 'PATH_INFO' => path_info,
66
+ 'SERVER_NAME' => server_name,
67
+ 'SERVER_PORT' => server_port.to_s,
68
+ 'rack.url_scheme' => url_scheme
69
+ }
70
+ end
71
+
72
+ def http_headers
73
+ event['headers'] || {}
74
+ end
75
+
76
+ def key_for_header(header)
77
+ key = header.upcase.tr('-', '_')
78
+ case key
79
+ when 'CONTENT_LENGTH', 'CONTENT_TYPE' then key
80
+ else "HTTP_#{key}"
81
+ end
82
+ end
83
+
84
+ def path_info
85
+ event['path'] || ''
86
+ end
87
+
88
+ def query_string
89
+ return @query_string if defined?(@query_string)
90
+
91
+ query = Query.new
92
+ event['multiValueQueryStringParameters']&.each_pair do |key, value|
93
+ query.add(key, value)
94
+ end
95
+ @query_string = query.to_s
96
+ end
97
+
98
+ def server_name
99
+ http_headers['Host'] || 'localhost'
100
+ end
101
+
102
+ def server_port
103
+ http_headers['X-Forwarded-Port'] || 443
104
+ end
105
+
106
+ def url_scheme
107
+ http_headers['CloudFront-Forwarded-Proto'] ||
108
+ http_headers['X-Forwarded-Proto'] ||
109
+ 'https'
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RackOnLambda
4
+ module Handlers
5
+ class RestApi
6
+ def self.call(event:, context:, app:)
7
+ adapter = Adapters::RestApi.new(event: event, context: context)
8
+ status, headers, body = app.call(adapter.env)
9
+ adapter.response(status, headers, body)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RackOnLambda
4
+ # The `multiValueQueryStringParameters` object from the API Gateway event
5
+ # keeps _all_ values in an array, regardless of the actual size of the array
6
+ # and regardless of the "intent" of the query string parameter.
7
+ #
8
+ # In order to normalise this behaviour, we treat the query strings
9
+ #
10
+ # `key=value1&key=value2`
11
+ #
12
+ # and
13
+ #
14
+ # `key[]=value1&key[]=value2`
15
+ #
16
+ # the same. Both are to be serialised to the query string
17
+ #
18
+ # `key[]=value1&key[]=value2`
19
+ #
20
+ # However, the query strings
21
+ #
22
+ # `key=value`
23
+ #
24
+ # and
25
+ #
26
+ # `key[]=value`
27
+ #
28
+ # are _not_ to be treated the same.
29
+ class Query
30
+ def initialize(data = {})
31
+ @params = data.with_indifferent_access
32
+ end
33
+
34
+ def add(key, values)
35
+ if key.to_s.end_with?('[]')
36
+ actual_key = key[0..-3]
37
+ add_list(actual_key, values)
38
+ else
39
+ values.each { |value| add_item(key, value) }
40
+ end
41
+ end
42
+
43
+ def to_h
44
+ @params.dup
45
+ end
46
+
47
+ def to_s
48
+ Rack::Utils.build_nested_query(to_h)
49
+ end
50
+
51
+ private
52
+
53
+ def add_item(key, value)
54
+ if @params[key].nil?
55
+ @params[key] = value
56
+ else
57
+ @params[key] = Array(@params[key])
58
+ @params[key] << value
59
+ end
60
+ end
61
+
62
+ def add_list(key, value)
63
+ @params[key] ||= []
64
+ @params[key].concat(value)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RackOnLambda
4
+ class Response
5
+ def initialize(status, headers, body)
6
+ @status = status
7
+ @headers = headers
8
+ @body = stringify_body(body)
9
+ end
10
+
11
+ def as_json(_options = {})
12
+ {
13
+ 'statusCode' => @status,
14
+ 'headers' => @headers,
15
+ 'isBase64Encoded' => @base64_encoded,
16
+ 'body' => @body
17
+ }
18
+ end
19
+
20
+ private
21
+
22
+ def stringify_body(body)
23
+ result = ''
24
+ body.each { |chunk| result += chunk.to_s }
25
+
26
+ if result.ascii_only?
27
+ @base64_encoded = false
28
+ result
29
+ else
30
+ @base64_encoded = true
31
+ Base64.strict_encode64(result)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RackOnLambda
4
+ VERSION = '1.0.0'
5
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'rack_on_lambda/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'rack-on-lambda'
9
+ spec.version = RackOnLambda::VERSION
10
+ spec.authors = ['Huy Dinh']
11
+ spec.email = ['mail@huydinh.eu']
12
+
13
+ spec.summary = 'Write beautiful Ruby applications for AWS Lambda'
14
+ spec.description = 'Use your Rack application on AWS Lambda.'
15
+ spec.homepage = 'https://github.com/Skudo/rack-on-lambda'
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
19
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec)/}) }
20
+ end
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.required_ruby_version = '>= 2.5'
24
+
25
+ spec.add_dependency 'activesupport', '~> 6.0.0'
26
+ spec.add_dependency 'rack', '>= 2.0.8', '< 3'
27
+
28
+ spec.add_development_dependency 'bundler'
29
+ spec.add_development_dependency 'factory_bot'
30
+ spec.add_development_dependency 'pry-byebug'
31
+ spec.add_development_dependency 'rake'
32
+ spec.add_development_dependency 'rspec'
33
+ spec.add_development_dependency 'rubocop'
34
+ spec.add_development_dependency 'simplecov'
35
+ spec.add_development_dependency 'yard'
36
+ end
metadata ADDED
@@ -0,0 +1,206 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-on-lambda
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Huy Dinh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-09-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 6.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 6.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rack
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.0.8
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '3'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 2.0.8
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: '3'
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: factory_bot
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: pry-byebug
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rake
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: rspec
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: rubocop
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ - !ruby/object:Gem::Dependency
132
+ name: simplecov
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ - !ruby/object:Gem::Dependency
146
+ name: yard
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ description: Use your Rack application on AWS Lambda.
160
+ email:
161
+ - mail@huydinh.eu
162
+ executables: []
163
+ extensions: []
164
+ extra_rdoc_files: []
165
+ files:
166
+ - ".github/workflows/push-gem.yml"
167
+ - ".github/workflows/tests.yml"
168
+ - ".gitignore"
169
+ - ".rspec"
170
+ - ".rubocop.yml"
171
+ - Rakefile
172
+ - changelog.md
173
+ - gems.rb
174
+ - lib/rack-on-lambda.rb
175
+ - lib/rack_on_lambda.rb
176
+ - lib/rack_on_lambda/adapters/rest_api.rb
177
+ - lib/rack_on_lambda/handlers/rest_api.rb
178
+ - lib/rack_on_lambda/query.rb
179
+ - lib/rack_on_lambda/response.rb
180
+ - lib/rack_on_lambda/version.rb
181
+ - rack-on-lambda.gemspec
182
+ homepage: https://github.com/Skudo/rack-on-lambda
183
+ licenses:
184
+ - MIT
185
+ metadata: {}
186
+ post_install_message:
187
+ rdoc_options: []
188
+ require_paths:
189
+ - lib
190
+ required_ruby_version: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '2.5'
195
+ required_rubygems_version: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - ">="
198
+ - !ruby/object:Gem::Version
199
+ version: '0'
200
+ requirements: []
201
+ rubyforge_project:
202
+ rubygems_version: 2.7.6.2
203
+ signing_key:
204
+ specification_version: 4
205
+ summary: Write beautiful Ruby applications for AWS Lambda
206
+ test_files: []