Class: Jets::Controller::Middleware::Local::ApiGateway

Inherits:
Object
  • Object
show all
Extended by:
Memoist
Defined in:
lib/jets/controller/middleware/local/api_gateway.rb

Constant Summary collapse

CASING_MAP =

Annoying. The headers part of the AWS Lambda proxy structure does not consisently use the same casing scheme for the header keys. Sometimes it looks like this:

Accept-Encoding

and sometimes it looks like this:

cache-control

Map for special cases when the casing doesn’t match.

{
  "Cache-Control" => "cache-control",
  "Content-Type" => "content-type",
  "Origin" => "origin",
  "Upgrade-Insecure-Requests" => "upgrade-insecure-requests",
}

Instance Method Summary collapse

Constructor Details

#initialize(route, env) ⇒ ApiGateway

Returns a new instance of ApiGateway.



6
7
8
# File 'lib/jets/controller/middleware/local/api_gateway.rb', line 6

def initialize(route, env)
  @route, @env = route, env
end

Instance Method Details

#eventObject



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/jets/controller/middleware/local/api_gateway.rb', line 10

def event
  resource = @route.path(:api_gateway) # posts/{id}/edit
  path = @env['PATH_INFO'].sub('/','') # remove beginning slash
  {
    "resource" => "/#{resource}", # "/posts/{id}/edit"
    "path" => @env['PATH_INFO'],  # /posts/tung/edit
    "httpMethod" => @env['REQUEST_METHOD'], # GET
    "headers" => request_headers,
    "queryStringParameters" => query_string_parameters,
    "multiValueQueryStringParameters" => multi_value_query_string_parameters,
    "pathParameters" => @route.extract_parameters(path),
    "stageVariables" => nil,
    "requestContext" => {},
    "body" => get_body,
    "isBase64Encoded" => false,
  }
end

#get_bodyObject

To get the post body:

rack.input: #<StringIO:0x007f8ccf8db9a0>


97
98
99
100
101
102
103
# File 'lib/jets/controller/middleware/local/api_gateway.rb', line 97

def get_body
  input = @env["rack.input"] || StringIO.new
  body = input.read
  input.rewind # IMPORTANT or else it screws up other middlewares that use the body
  # return nil for blank string, because Lambda AWS_PROXY does this
  body unless body.empty?
end

#multi_value_query_string_parametersObject



87
88
89
90
91
92
93
# File 'lib/jets/controller/middleware/local/api_gateway.rb', line 87

def multi_value_query_string_parameters
  @env['QUERY_STRING']&.split('&')&.each_with_object({}) do |parameter, hash|
    key, value = parameter.split('=')
    hash[key] = [] if hash[key].nil?
    hash[key] << value
  end || {}
end

#query_string_parametersObject



80
81
82
83
84
85
# File 'lib/jets/controller/middleware/local/api_gateway.rb', line 80

def query_string_parameters
  @env['QUERY_STRING']&.split('&')&.each_with_object({}) do |parameter, hash|
    key, value = parameter.split('=')
    hash[key] = value
  end || {}
end

#request_headersObject

Map rack env headers to Api Gateway event headers. Most rack env headers are prepended by HTTP_.

Some API Gateway Lambda Proxy are also in the rack env headers. Example:

"X-Amz-Cf-Id": "W8DF6J-lx1bkV00eCiBwIq5dldTSGGiG4BinJlxvN_4o8fCZtbsVjw==",
"X-Amzn-Trace-Id": "Root=1-5a0dc1ac-58a7db712a57d6aa4186c2ac",
"X-Forwarded-For": "88.88.88.88, 54.239.203.117",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https",

For sample dump of the event headers, check out:

spec/fixtures/samples/event-headers-form-post.json

We generally do add those API Gateway Lambda specific headers because they would be fake anyway and by not adding them we can distinguish a local request from a remote request on API Gateway.



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/jets/controller/middleware/local/api_gateway.rb', line 60

def request_headers
  headers = @env.select { |k,v| k =~ /^HTTP_/ }.inject({}) do |h,(k,v)|
      # map things like HTTP_USER_AGENT to "User-Agent"
      key = k.sub('HTTP_','').split('_').map(&:capitalize).join('-')
      h[key] = v
      h
    end
  # Content type is not prepended with HTTP_
  headers["Content-Type"] = @env["CONTENT_TYPE"] if @env["CONTENT_TYPE"]

  # Adjust the casing so it matches the Lambda AWS Proxy structure
  CASING_MAP.each do |nice_casing, bad_casing|
    if headers.key?(nice_casing)
      headers[bad_casing] = headers.delete(nice_casing)
    end
  end

  headers
end