jets 1.1.5 → 1.2.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 +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +10 -6
- data/README/testing.md +5 -1
- data/jets.gemspec +1 -0
- data/lib/jets.rb +5 -1
- data/lib/jets/application.rb +39 -19
- data/lib/jets/aws_services.rb +16 -10
- data/lib/jets/aws_services/stack_status.rb +7 -0
- data/lib/jets/booter.rb +6 -2
- data/lib/jets/builders/code_builder.rb +14 -0
- data/lib/jets/builders/handler_generator.rb +15 -0
- data/lib/jets/builders/shim_vars/app.rb +4 -3
- data/lib/jets/builders/shim_vars/shared.rb +8 -4
- data/lib/jets/builders/templates/shim.js +7 -3
- data/lib/jets/camelizer.rb +2 -1
- data/lib/jets/cfn/builders.rb +0 -1
- data/lib/jets/cfn/builders/api_deployment_builder.rb +27 -0
- data/lib/jets/cfn/builders/api_gateway_builder.rb +22 -2
- data/lib/jets/cfn/ship.rb +38 -6
- data/lib/jets/commands/call.rb +0 -1
- data/lib/jets/commands/call/guesser.rb +0 -3
- data/lib/jets/commands/clean/log.rb +18 -0
- data/lib/jets/commands/console.rb +1 -1
- data/lib/jets/commands/import/sequence.rb +2 -3
- data/lib/jets/commands/runner.rb +1 -1
- data/lib/jets/commands/sequence.rb +0 -1
- data/lib/jets/commands/templates/skeleton/config/application.rb.tt +11 -0
- data/lib/jets/commands/url.rb +32 -7
- data/lib/jets/controller/base.rb +21 -5
- data/lib/jets/controller/layout.rb +0 -3
- data/lib/jets/controller/middleware/local/api_gateway.rb +2 -5
- data/lib/jets/controller/middleware/local/mimic_aws_call.rb +2 -2
- data/lib/jets/controller/params.rb +42 -10
- data/lib/jets/controller/rack/adapter.rb +5 -2
- data/lib/jets/controller/rack/env.rb +17 -8
- data/lib/jets/controller/renderers/rack_renderer.rb +1 -1
- data/lib/jets/controller/rendering.rb +4 -1
- data/lib/jets/core.rb +8 -16
- data/lib/jets/internal/app/functions/jets/base_path.rb +153 -0
- data/lib/jets/klass.rb +38 -5
- data/lib/jets/lambda/dsl.rb +0 -2
- data/lib/jets/mega/request.rb +44 -13
- data/lib/jets/mega/request/source.rb +21 -0
- data/lib/jets/middleware/configurator.rb +1 -1
- data/lib/jets/middleware/default_stack.rb +2 -2
- data/lib/jets/resource.rb +1 -0
- data/lib/jets/resource/api_gateway.rb +5 -3
- data/lib/jets/resource/api_gateway/base_path.rb +5 -0
- data/lib/jets/resource/api_gateway/base_path/function.rb +42 -0
- data/lib/jets/resource/api_gateway/base_path/mapping.rb +44 -0
- data/lib/jets/resource/api_gateway/base_path/role.rb +76 -0
- data/lib/jets/resource/api_gateway/cors.rb +1 -1
- data/lib/jets/resource/api_gateway/deployment.rb +9 -5
- data/lib/jets/resource/api_gateway/domain_name.rb +56 -0
- data/lib/jets/resource/api_gateway/method.rb +3 -4
- data/lib/jets/resource/api_gateway/resource.rb +4 -3
- data/lib/jets/resource/api_gateway/rest_api.rb +42 -14
- data/lib/jets/resource/api_gateway/rest_api/change_detection.rb +42 -0
- data/lib/jets/resource/api_gateway/rest_api/logical_id.rb +59 -0
- data/lib/jets/resource/api_gateway/rest_api/routes.rb +127 -0
- data/lib/jets/resource/child_stack/api_deployment.rb +5 -1
- data/lib/jets/resource/function.rb +3 -20
- data/lib/jets/resource/function/environment.rb +23 -0
- data/lib/jets/resource/iam/application_role.rb +1 -1
- data/lib/jets/resource/route53.rb +3 -0
- data/lib/jets/resource/route53/record_set.rb +70 -0
- data/lib/jets/router.rb +2 -0
- data/lib/jets/ruby_server.rb +6 -3
- data/lib/jets/stack.rb +1 -3
- data/lib/jets/stack/main/dsl.rb +1 -1
- data/lib/jets/stack/main/extensions/lambda.rb +4 -2
- data/lib/jets/turbine.rb +0 -3
- data/lib/jets/version.rb +1 -1
- data/vendor/jets-gems/lib/jets/gems.rb +1 -0
- data/vendor/jets-gems/lib/jets/gems/agree.rb +41 -0
- data/vendor/jets-gems/lib/jets/gems/check.rb +15 -2
- metadata +30 -2
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
1
3
|
module Jets::Controller::Rack
|
2
4
|
class Adapter
|
3
5
|
extend Memoist
|
@@ -21,15 +23,16 @@ module Jets::Controller::Rack
|
|
21
23
|
end
|
22
24
|
|
23
25
|
def env
|
24
|
-
Env.new(@event, @context).convert # convert to Rack env
|
26
|
+
Env.new(@event, @context, adapter: true).convert # convert to Rack env
|
25
27
|
end
|
26
28
|
memoize :env
|
27
29
|
|
28
30
|
# Transform the structure to AWS_PROXY compatiable structure
|
29
31
|
# http://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format
|
30
32
|
def convert_to_api_gateway(status, headers, body)
|
31
|
-
base64 = headers["x-jets-base64"] == '
|
33
|
+
base64 = headers["x-jets-base64"] == 'yes'
|
32
34
|
body = body.respond_to?(:read) ? body.read : body
|
35
|
+
body = Base64.encode64(body) if base64
|
33
36
|
{
|
34
37
|
"statusCode" => status,
|
35
38
|
"headers" => headers,
|
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'rack'
|
2
|
+
require 'base64'
|
2
3
|
|
3
4
|
# Takes an ApiGateway event and converts it to an Rack env that can be used for
|
4
5
|
# rack.call(env).
|
5
6
|
module Jets::Controller::Rack
|
6
7
|
class Env
|
7
|
-
def initialize(event, context)
|
8
|
-
@event, @context = event, context
|
8
|
+
def initialize(event, context, options={})
|
9
|
+
@event, @context, @options = event, context, options
|
9
10
|
end
|
10
11
|
|
11
12
|
def convert
|
@@ -13,7 +14,12 @@ module Jets::Controller::Rack
|
|
13
14
|
options = add_top_level(options)
|
14
15
|
options = add_http_headers(options)
|
15
16
|
path = @event['path'] || '/' # always set by API Gateway but might not be when testing shim, so setting it to make testing easier
|
16
|
-
Rack::MockRequest.env_for(path, options)
|
17
|
+
env = Rack::MockRequest.env_for(path, options)
|
18
|
+
if @options[:adapter]
|
19
|
+
env['adapter.event'] = @event
|
20
|
+
env['adapter.context'] = @context
|
21
|
+
end
|
22
|
+
env
|
17
23
|
end
|
18
24
|
|
19
25
|
private
|
@@ -35,10 +41,7 @@ module Jets::Controller::Rack
|
|
35
41
|
|
36
42
|
map['CONTENT_LENGTH'] = content_length if content_length
|
37
43
|
# Even if not set, Rack always assigns an StringIO to "rack.input"
|
38
|
-
map[
|
39
|
-
|
40
|
-
# TODO: handle decoding base64 encoded body from API Gateaway
|
41
|
-
# Will need to make sure that pass the base64 info via a request header
|
44
|
+
map['rack.input'] = StringIO.new(body) if body
|
42
45
|
|
43
46
|
options.merge(map)
|
44
47
|
end
|
@@ -52,8 +55,14 @@ module Jets::Controller::Rack
|
|
52
55
|
headers['Content-Length'] || bytesize
|
53
56
|
end
|
54
57
|
|
58
|
+
# Decoding base64 from API Gateaway if necessary
|
59
|
+
# Rack will be none the wiser
|
55
60
|
def body
|
56
|
-
@event['
|
61
|
+
if @event['isBase64Encoded']
|
62
|
+
Base64.decode64(@event['body'])
|
63
|
+
else
|
64
|
+
@event['body']
|
65
|
+
end
|
57
66
|
end
|
58
67
|
|
59
68
|
def add_http_headers(options)
|
@@ -17,7 +17,7 @@ module Jets::Controller::Renderers
|
|
17
17
|
headers = cors_headers.merge(headers)
|
18
18
|
headers["Content-Type"] ||= @options[:content_type] || Jets::Controller::DEFAULT_CONTENT_TYPE
|
19
19
|
# x-jets-base64 to convert this Rack triplet to a API Gateway hash structure later
|
20
|
-
headers["x-jets-base64"] = base64 ?
|
20
|
+
headers["x-jets-base64"] = base64 ? 'yes' : 'no' # headers values must be Strings
|
21
21
|
body = StringIO.new(body)
|
22
22
|
[status, headers, body] # triplet
|
23
23
|
end
|
@@ -71,7 +71,10 @@ class Jets::Controller
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def url_for(url)
|
74
|
-
|
74
|
+
# No longer need to add stage name, think this is due to rack middleware support
|
75
|
+
# Leaving in as comment for now just in case.
|
76
|
+
# add_stage_name(url)
|
77
|
+
url
|
75
78
|
end
|
76
79
|
|
77
80
|
def actual_host
|
data/lib/jets/core.rb
CHANGED
@@ -1,22 +1,9 @@
|
|
1
|
-
require 'active_support/dependencies'
|
2
|
-
require 'memoist'
|
3
|
-
|
4
1
|
module Jets::Core
|
5
2
|
extend Memoist
|
6
3
|
|
7
|
-
# Calling application triggers load of configs.
|
8
|
-
# Jets' the default config/application.rb is loaded,
|
9
|
-
# then the project's config/application.rb is loaded.
|
10
|
-
@@application = nil
|
11
4
|
def application
|
12
|
-
|
13
|
-
|
14
|
-
@@application = Jets::Application.instance
|
15
|
-
@@application.setup!
|
16
|
-
@@application
|
5
|
+
Jets::Application.instance
|
17
6
|
end
|
18
|
-
# For some reason memoize doesnt work with application, think there's
|
19
|
-
# some circular dependency issue. Figure this out later.
|
20
7
|
|
21
8
|
def config
|
22
9
|
application.config
|
@@ -123,7 +110,7 @@ module Jets::Core
|
|
123
110
|
def eager_load_app
|
124
111
|
Dir.glob("#{Jets.root}app/**/*.rb").select do |path|
|
125
112
|
next if !File.file?(path) or path =~ %r{/javascript/} or path =~ %r{/views/}
|
126
|
-
next if path.include?('app/functions') || path.include?('app/shared/functions')
|
113
|
+
next if path.include?('app/functions') || path.include?('app/shared/functions') || path.include?('app/internal/functions')
|
127
114
|
|
128
115
|
class_name = path
|
129
116
|
.sub(/\.rb$/,'') # remove .rb
|
@@ -177,9 +164,14 @@ module Jets::Core
|
|
177
164
|
|
178
165
|
def report_exception(exception)
|
179
166
|
Jets::Turbine.subclasses.each do |subclass|
|
180
|
-
subclass.exception_reporters
|
167
|
+
reporters = subclass.exception_reporters || []
|
168
|
+
reporters.each do |label, block|
|
181
169
|
block.call(exception)
|
182
170
|
end
|
183
171
|
end
|
184
172
|
end
|
173
|
+
|
174
|
+
def custom_domain?
|
175
|
+
Jets.config.domain.hosted_zone_name
|
176
|
+
end
|
185
177
|
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'aws-sdk-apigateway'
|
2
|
+
require 'aws-sdk-cloudformation'
|
3
|
+
|
4
|
+
STAGE_NAME = "<%= @stage_name %>"
|
5
|
+
|
6
|
+
def lambda_handler(event:, context:)
|
7
|
+
puts("event['RequestType'] #{event['RequestType']}")
|
8
|
+
puts("event: #{JSON.dump(event)}")
|
9
|
+
puts("context: #{JSON.dump(context)}")
|
10
|
+
puts("context.log_stream_name #{context.log_stream_name.inspect}")
|
11
|
+
|
12
|
+
mimic = event['ResourceProperties']['Mimic']
|
13
|
+
physical_id = event['ResourceProperties']['PhysicalId'] || "PhysicalId"
|
14
|
+
|
15
|
+
puts "mimic: #{mimic}"
|
16
|
+
puts "physical_id: #{physical_id}"
|
17
|
+
|
18
|
+
if event['RequestType'] == 'Delete'
|
19
|
+
if mimic == 'FAILED'
|
20
|
+
send_response(event, context, "FAILED")
|
21
|
+
else
|
22
|
+
mapping = BasePathMapping.new(event)
|
23
|
+
mapping.delete(true) if mapping.should_delete?
|
24
|
+
send_response(event, context, "SUCCESS")
|
25
|
+
end
|
26
|
+
return # early return
|
27
|
+
end
|
28
|
+
|
29
|
+
mapping = BasePathMapping.new(event)
|
30
|
+
mapping.update
|
31
|
+
|
32
|
+
response_status = mimic == "FAILED" ? "FAILED" : "SUCCESS"
|
33
|
+
response_data = { "Hello" => "World" }
|
34
|
+
|
35
|
+
send_response(event, context, response_status, response_data, physical_id)
|
36
|
+
|
37
|
+
# We rescue all exceptions and send an message to CloudFormation so we dont have to
|
38
|
+
# wait for over an hour for the stack operation to timeout and rollback.
|
39
|
+
rescue Exception => e
|
40
|
+
puts e.message
|
41
|
+
puts e.backtrace
|
42
|
+
sleep 10 # provide delete to make sure that the log gets sent to CloudWatch
|
43
|
+
send_response(event, context, "FAILED")
|
44
|
+
end
|
45
|
+
|
46
|
+
def send_response(event, context, response_status, response_data={}, physical_id="PhysicalId")
|
47
|
+
response_body = JSON.dump(
|
48
|
+
Status: response_status,
|
49
|
+
Reason: "See the details in CloudWatch Log Stream: #{context.log_stream_name.inspect}",
|
50
|
+
PhysicalResourceId: physical_id,
|
51
|
+
StackId: event['StackId'],
|
52
|
+
RequestId: event['RequestId'],
|
53
|
+
LogicalResourceId: event['LogicalResourceId'],
|
54
|
+
Data: response_data
|
55
|
+
)
|
56
|
+
|
57
|
+
puts "RESPONSE BODY:\n"
|
58
|
+
puts response_body
|
59
|
+
|
60
|
+
url = event['ResponseURL']
|
61
|
+
uri = URI(url)
|
62
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
63
|
+
http.open_timeout = http.read_timeout = 30
|
64
|
+
http.use_ssl = true if uri.scheme == 'https'
|
65
|
+
|
66
|
+
|
67
|
+
# must used url to include the AWSAccessKeyId and Signature
|
68
|
+
req = Net::HTTP::Put.new(url) # url includes query string and uri.path does not, must used url t
|
69
|
+
req.body = response_body
|
70
|
+
req.content_length = response_body.bytesize
|
71
|
+
|
72
|
+
# set headers
|
73
|
+
req['content-type'] = ''
|
74
|
+
req['content-length'] = response_body.bytesize
|
75
|
+
|
76
|
+
res = http.request(req)
|
77
|
+
puts "status code: #{res.code}"
|
78
|
+
puts "headers: #{res.each_header.to_h.inspect}"
|
79
|
+
puts "body: #{res.body}"
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
class BasePathMapping
|
84
|
+
def initialize(event)
|
85
|
+
@event = event
|
86
|
+
@rest_api_id = get_rest_api_id
|
87
|
+
@domain_name = get_domain_name
|
88
|
+
@base_path = ''
|
89
|
+
end
|
90
|
+
|
91
|
+
def update
|
92
|
+
# Cannot use update_base_path_mapping to update the base_mapping because it doesnt
|
93
|
+
# allow us to change the rest_api_id. So we delete and create.
|
94
|
+
delete(true)
|
95
|
+
create
|
96
|
+
end
|
97
|
+
|
98
|
+
# Dont delete the newly created base path mapping unless this is an operation
|
99
|
+
# where we're fully deleting the stack
|
100
|
+
def should_delete?
|
101
|
+
deleting_parent?
|
102
|
+
end
|
103
|
+
|
104
|
+
def delete(fail_silently=false)
|
105
|
+
apigateway.delete_base_path_mapping(
|
106
|
+
domain_name: @domain_name, # required
|
107
|
+
base_path: '(none)',
|
108
|
+
)
|
109
|
+
rescue Aws::APIGateway::Errors::NotFoundException => e
|
110
|
+
raise(e) unless fail_silently
|
111
|
+
end
|
112
|
+
|
113
|
+
def create
|
114
|
+
apigateway.create_base_path_mapping(
|
115
|
+
domain_name: @domain_name, # required
|
116
|
+
base_path: @base_path,
|
117
|
+
rest_api_id: @rest_api_id, # required
|
118
|
+
stage: STAGE_NAME,
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
def get_domain_name
|
123
|
+
param = deployment_stack[:parameters].find { |p| p.parameter_key == 'DomainName' }
|
124
|
+
param.parameter_value
|
125
|
+
end
|
126
|
+
|
127
|
+
def deployment_stack
|
128
|
+
@deployment_stack ||= cfn.describe_stacks(stack_name: @event['StackId']).stacks.first
|
129
|
+
end
|
130
|
+
|
131
|
+
def get_rest_api_id
|
132
|
+
param = deployment_stack[:parameters].find { |p| p.parameter_key == 'RestApi' }
|
133
|
+
param.parameter_value
|
134
|
+
end
|
135
|
+
|
136
|
+
def deleting_parent?
|
137
|
+
stack = cfn.describe_stacks(stack_name: parent_stack_name).stacks.first
|
138
|
+
stack.stack_status == 'DELETE_IN_PROGRESS'
|
139
|
+
end
|
140
|
+
|
141
|
+
def parent_stack_name
|
142
|
+
deployment_stack[:root_id]
|
143
|
+
end
|
144
|
+
|
145
|
+
private
|
146
|
+
def apigateway
|
147
|
+
@apigateway ||= Aws::APIGateway::Client.new
|
148
|
+
end
|
149
|
+
|
150
|
+
def cfn
|
151
|
+
@cfn ||= Aws::CloudFormation::Client.new
|
152
|
+
end
|
153
|
+
end
|
data/lib/jets/klass.rb
CHANGED
@@ -28,12 +28,12 @@ class Jets::Klass
|
|
28
28
|
# app/controllers, app/jobs, and app/functions.
|
29
29
|
def from_path(path)
|
30
30
|
class_name = class_name(path)
|
31
|
-
|
32
31
|
if path.include?("/functions/") # simple function
|
33
|
-
load_anonymous_class(class_name, path)
|
32
|
+
class_name = load_anonymous_class(class_name, path)
|
33
|
+
class_name.constantize # removed :: for anonymous classes
|
34
|
+
else
|
35
|
+
class_name.constantize # autoload
|
34
36
|
end
|
35
|
-
|
36
|
-
class_name.constantize # autoload or nothing if load_anonymous_class called
|
37
37
|
end
|
38
38
|
|
39
39
|
# app/controllers/posts_controller.rb => PostsController
|
@@ -61,15 +61,48 @@ class Jets::Klass
|
|
61
61
|
|
62
62
|
@@loaded_anonymous_classes = []
|
63
63
|
def load_anonymous_class(class_name, path)
|
64
|
+
parent_mod = modularize(class_name)
|
65
|
+
|
64
66
|
constructor = Jets::Lambda::FunctionConstructor.new(path)
|
65
67
|
# Dont load anonyomous class more than once to avoid these warnings:
|
66
68
|
# warning: already initialized constant Hello
|
67
69
|
# warning: previous definition of Hello was here
|
68
70
|
unless @@loaded_anonymous_classes.include?(class_name)
|
69
71
|
# use class_name as the variable name for prettier class name.
|
70
|
-
|
72
|
+
leaf_class_name = class_name.split('::').last
|
73
|
+
parent_mod.const_set(leaf_class_name, constructor.build)
|
71
74
|
@@loaded_anonymous_classes << class_name
|
72
75
|
end
|
76
|
+
|
77
|
+
class_name
|
78
|
+
end
|
79
|
+
|
80
|
+
# Ensures the parent namespace modules are defined. Example:
|
81
|
+
#
|
82
|
+
# modularize("Foo::Bar::Test")
|
83
|
+
# => Foo::Bar # is a now defined as a module if it wasnt before
|
84
|
+
#
|
85
|
+
# Also returns the parent module, so we can use it to do a const_set if needed. IE:
|
86
|
+
#
|
87
|
+
# parent_mod = modularize("Foo::Bar::Test")
|
88
|
+
# parent_mod.const_set("Test")
|
89
|
+
def modularize(class_name)
|
90
|
+
leaves = []
|
91
|
+
mods = class_name.split('::')[0..-2] # drop the last word
|
92
|
+
# puts "mods: #{mods}"
|
93
|
+
return Object if mods.empty?
|
94
|
+
|
95
|
+
leaves = []
|
96
|
+
mods.each do |leaf_mod|
|
97
|
+
leaves += [leaf_mod]
|
98
|
+
namespace = leaves.join('::')
|
99
|
+
previous_namespace = leaves[0..-2].join('::')
|
100
|
+
previous_namespace = "Object" if previous_namespace.empty?
|
101
|
+
previous_namespace = previous_namespace.constantize
|
102
|
+
previous_namespace.const_set(leaf_mod, Module.new) unless Object.const_defined?(namespace)
|
103
|
+
end
|
104
|
+
|
105
|
+
mods.join('::').constantize
|
73
106
|
end
|
74
107
|
|
75
108
|
end
|
data/lib/jets/lambda/dsl.rb
CHANGED
data/lib/jets/mega/request.rb
CHANGED
@@ -3,6 +3,10 @@ require 'rack'
|
|
3
3
|
|
4
4
|
module Jets::Mega
|
5
5
|
class Request
|
6
|
+
autoload :Source, 'jets/mega/request/source'
|
7
|
+
|
8
|
+
extend Memoist
|
9
|
+
|
6
10
|
def initialize(event, controller)
|
7
11
|
@event = event
|
8
12
|
@controller = controller # Jets::Controller instance
|
@@ -12,10 +16,10 @@ module Jets::Mega
|
|
12
16
|
http_method = @event['httpMethod'] # GET, POST, PUT, DELETE, etc
|
13
17
|
params = @controller.params(raw: true, path_parameters: false)
|
14
18
|
|
15
|
-
uri =
|
19
|
+
uri = get_uri
|
20
|
+
|
16
21
|
http = Net::HTTP.new(uri.host, uri.port)
|
17
|
-
http.open_timeout = 60
|
18
|
-
http.read_timeout = 60
|
22
|
+
http.open_timeout = http.read_timeout = 60
|
19
23
|
|
20
24
|
# Rails sets _method=patch or _method=put as workaround
|
21
25
|
# Falls back to GET when testing in lambda console
|
@@ -24,25 +28,23 @@ module Jets::Mega
|
|
24
28
|
|
25
29
|
request_class = "Net::HTTP::#{http_class}".constantize # IE: Net::HTTP::Get
|
26
30
|
request = request_class.new(uri.path)
|
31
|
+
|
32
|
+
# Set form data
|
27
33
|
if %w[Post Patch Put].include?(http_class)
|
28
34
|
params = HashConverter.encode(params)
|
29
35
|
request.set_form_data(params)
|
30
36
|
end
|
31
37
|
|
32
|
-
|
38
|
+
# Set body info
|
39
|
+
request.body = source.body
|
40
|
+
request.content_length = source.content_length
|
33
41
|
|
34
|
-
#
|
35
|
-
|
36
|
-
source_request = Rack::Request.new(env)
|
37
|
-
if source_request.body.respond_to?(:read)
|
38
|
-
request.body = source_request.body.read
|
39
|
-
request.content_length = source_request.content_length.to_i
|
40
|
-
source_request.body.rewind
|
41
|
-
end
|
42
|
+
# Need to set headers after body and form_data for some reason
|
43
|
+
request = set_headers!(request)
|
42
44
|
|
45
|
+
# Make request
|
43
46
|
response = http.request(request)
|
44
47
|
|
45
|
-
# TODO: handle binary
|
46
48
|
{
|
47
49
|
status: response.code.to_i,
|
48
50
|
headers: response.each_header.to_h,
|
@@ -50,6 +52,35 @@ module Jets::Mega
|
|
50
52
|
}
|
51
53
|
end
|
52
54
|
|
55
|
+
def get_uri
|
56
|
+
url = "http://localhost:9292#{@controller.request.path}" # local rack server
|
57
|
+
unless @controller.query_parameters.empty?
|
58
|
+
# Thanks: https://stackoverflow.com/questions/798710/ruby-how-to-turn-a-hash-into-http-parameters
|
59
|
+
query_string = Rack::Utils.build_nested_query(@controller.query_parameters)
|
60
|
+
url += "?#{query_string}"
|
61
|
+
end
|
62
|
+
URI(url)
|
63
|
+
end
|
64
|
+
|
65
|
+
def source
|
66
|
+
Source.new(@event)
|
67
|
+
end
|
68
|
+
memoize :source
|
69
|
+
|
70
|
+
# Rails sets _method=patch or _method=put as workaround
|
71
|
+
# Falls back to GET when testing in lambda console
|
72
|
+
# @event['httpMethod'] is GET, POST, PUT, DELETE, etc
|
73
|
+
def http_class
|
74
|
+
http_class = params['_method'] || @event['httpMethod'] || 'GET'
|
75
|
+
http_class.capitalize!
|
76
|
+
http_class
|
77
|
+
end
|
78
|
+
|
79
|
+
def params
|
80
|
+
@controller.params(raw: true, path_parameters: false, body_parameters: true)
|
81
|
+
end
|
82
|
+
memoize :params
|
83
|
+
|
53
84
|
# Set request headers. Forwards original request info from remote API gateway.
|
54
85
|
# By this time, the server/api_gateway.rb middleware.
|
55
86
|
def set_headers!(request)
|