Skip to content

Commit

Permalink
refactoring the code
Browse files Browse the repository at this point in the history
  • Loading branch information
BlazingRockStorm committed Aug 25, 2024
1 parent a719f7a commit d0824f8
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 66 deletions.
6 changes: 4 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
source 'http://rubygems.org'

ruby '3.2.0'

gem 'sinatra'
gem 'json'
gem 'rack'
Expand All @@ -10,6 +12,6 @@ gem 'rubysl-base64'

# These are the dependencies that are used only for unit tests.
group :test do
gem "rspec"
gem "rack-test"
gem 'rspec'
gem 'rack-test'
end
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ RSpec::Core::RakeTask.new :specs do |task|
task.pattern = Dir['spec/**/*_spec.rb']
end

task :default => ['specs']
task default: ['specs']
4 changes: 2 additions & 2 deletions app/config.ru
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
require 'rack'
require 'rack/contrib'
require_relative './server'
require_relative 'server'

set :root, File.dirname(__FILE__)
set :views, Proc.new { File.join(root, "views") }
set :views, proc { File.join(root, 'views') }

run Sinatra::Application
18 changes: 9 additions & 9 deletions app/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
require 'aws-record'

before do
if (request.body && request.body.read.empty? && request.body.size > 0)
if request.body && request.body.read.empty? && request.body.size.positive?
request.body.rewind
@params = Sinatra::IndifferentHash.new
@params.merge!(JSON.parse(request.body.read))
Expand All @@ -21,12 +21,12 @@
##################################
get '/hello-world' do
content_type :json
{ :Output => 'Hello World!' }.to_json
{ Output: 'Hello World!' }.to_json
end

post '/hello-world' do
content_type :json
{ :Output => 'Hello World!' }.to_json
content_type :json
{ Output: 'Hello World!' }.to_json
end

##################################
Expand All @@ -49,11 +49,11 @@ class FeedbackServerlessSinatraTable

get '/api/feedback' do
content_type :json
items = FeedbackServerlessSinatraTable.scan()
items
.map { |r| { :ts => r.ts, :name => r.name, :feedback => r.feedback } }
.sort { |a, b| a[:ts] <=> b[:ts] }
.to_json
items = FeedbackServerlessSinatraTable.scan
items.
map { |r| { ts: r.ts, name: r.name, feedback: r.feedback } }.
sort { |a, b| a[:ts] <=> b[:ts] }.
to_json
end

post '/api/feedback' do
Expand Down
31 changes: 15 additions & 16 deletions lambda.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,13 @@
$app ||= Rack::Builder.parse_file("#{__dir__}/app/config.ru").first
ENV['RACK_ENV'] ||= 'production'


def handler(event:, context:)
# Check if the body is base64 encoded. If it is, try to decode it
body = if event['isBase64Encoded']
Base64.decode64 event['body']
else
event['body']
end || ''
Base64.decode64 event['body']
else
event['body']
end || ''

# Rack expects the querystring in plain text, not a hash
headers = event.fetch 'headers', {}
Expand All @@ -39,14 +38,14 @@ def handler(event:, context:)
'REQUEST_METHOD' => event.fetch('httpMethod'),
'SCRIPT_NAME' => '',
'PATH_INFO' => event.fetch('path', ''),
'QUERY_STRING' => (event['queryStringParameters'] || {}).map { |k,v| "#{k}=#{v}" }.join('&'),
'QUERY_STRING' => (event['queryStringParameters'] || {}).map { |k, v| "#{k}=#{v}" }.join('&'),
'SERVER_NAME' => headers.fetch('Host', 'localhost'),
'SERVER_PORT' => headers.fetch('X-Forwarded-Port', 443).to_s,

'rack.version' => Rack::VERSION,
'rack.url_scheme' => headers.fetch('CloudFront-Forwarded-Proto') { headers.fetch('X-Forwarded-Proto', 'https') },
'rack.input' => StringIO.new(body),
'rack.errors' => $stderr,
'rack.errors' => $stderr
}

# Pass request headers to Rack if they are available
Expand All @@ -55,11 +54,11 @@ def handler(event:, context:)
# Content-Type and Content-Length are handled specially per the Rack SPEC linked above.
name = key.upcase.gsub '-', '_'
header = case name
when 'CONTENT_TYPE', 'CONTENT_LENGTH'
name
else
"HTTP_#{name}"
end
when 'CONTENT_TYPE', 'CONTENT_LENGTH'
name
else
"HTTP_#{name}"
end
env[header] = value.to_s
end

Expand All @@ -68,7 +67,7 @@ def handler(event:, context:)
status, headers, body = $app.call env

# body is an array. We combine all the items to a single string
body_content = ""
body_content = ''
body.each do |item|
body_content += item.to_s
end
Expand All @@ -80,15 +79,15 @@ def handler(event:, context:)
'headers' => headers,
'body' => body_content
}
if event['requestContext'].has_key?('elb')
if event['requestContext'].key?('elb')
# Required if we use Application Load Balancer instead of API Gateway
response['isBase64Encoded'] = false
end
rescue Exception => exception
rescue Exception => e
# If there is _any_ exception, we return a 500 error with an error message
response = {
'statusCode' => 500,
'body' => exception.message
'body' => e.message
}
end

Expand Down
56 changes: 26 additions & 30 deletions spec/server_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,52 +5,48 @@
include Rack::Test::Methods

# Test for HTTP GET for URL-matching pattern '/'
it "should return successfully on GET" do
it 'returns successfully on GET' do
get '/hello-world'
expect(last_response).to be_ok
json_result = JSON.parse(last_response.body)
expect(json_result["Output"]).to eq("Hello World!")
expect(json_result['Output']).to eq('Hello World!')
end

# Test for HTTP POST for URL-matching pattern '/'
it "should return successfully on POST" do
it 'returns successfully on POST' do
post '/hello-world'
expect(last_response).to be_ok
expect(json_result["Output"]).to eq("Hello World!")
expect(json_result['Output']).to eq('Hello World!')
end

it "should POST params to API feedback endpoint with success" do
expect(stub_client)
.to receive(:put_item)
.with({
:condition_expression=>be_kind_of(String),
:expression_attribute_names=>be_kind_of(Hash),
:item=>
{"feedback"=>"AWS Lambda + Ruby == <3",
"id"=>be_kind_of(String),
"name"=>"Tomas",
"ts"=>be_within(3).of(Time.now.to_i)},
:table_name=>"FeedbackServerlessSinatraTable"})
.and_call_original

api_gateway_post('/api/feedback', { name: "Tomas", feedback: "AWS Lambda + Ruby == <3" })
it 'POSTS params to API feedback endpoint with success' do
expect(stub_client).
to receive(:put_item).
with({
condition_expression: be_a(String),
expression_attribute_names: be_a(Hash),
item: { 'feedback' => 'AWS Lambda + Ruby == <3',
'id' => be_a(String),
'name' => 'Tomas',
'ts' => be_within(3).of(Time.now.to_i) },
table_name: 'FeedbackServerlessSinatraTable'
}).
and_call_original

api_gateway_post('/api/feedback', { name: 'Tomas', feedback: 'AWS Lambda + Ruby == <3' })

expect(last_response).to be_ok
end

it "should successfuly GET items from API feedback endpoint in right order" do
stub_client.stub_responses(:scan, :items => [
{'name' => 'Zdenka', "ts" => 2345678, "feedback" => "Halestorm"},
{'name' => 'Tomas', "ts" => 1234567, "feedback" => "Trivium"},
{'name' => 'xiangshen', "ts" => 5678901, "feedback" => "Awesome !"},
])
it 'successfulies GET items from API feedback endpoint in right order' do
stub_client.stub_responses(:scan, items: [
{ 'name' => 'Zdenka', 'ts' => 2_345_678, 'feedback' => 'Halestorm' },
{ 'name' => 'Tomas', 'ts' => 1_234_567, 'feedback' => 'Trivium' },
{ 'name' => 'xiangshen', 'ts' => 5_678_901, 'feedback' => 'Awesome !' }
])

get '/api/feedback'
expect(last_response).to be_ok
expect(json_result).to match_array([
{ "name" => "Tomas", "feedback"=>"Trivium", "ts"=> be_kind_of(String)},
{ "name" => "Zdenka", "feedback"=>"Halestorm", "ts"=> be_kind_of(String)},
{ "name" => "xiangshen","feedback"=>"Awesome !", "ts"=> be_kind_of(String)}
])
expect(json_result).to contain_exactly({ 'name' => 'Tomas', 'feedback' => 'Trivium', 'ts' => be_a(String) }, { 'name' => 'Zdenka', 'feedback' => 'Halestorm', 'ts' => be_a(String) }, { 'name' => 'xiangshen', 'feedback' => 'Awesome !', 'ts' => be_a(String) })
end
end
10 changes: 4 additions & 6 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
require_relative '../app/server.rb'
require_relative '../app/server'
require 'rack/test'

set :environment, :test

RSpec.configure do |config|
config.before(:each) do
config.before do
FeedbackServerlessSinatraTable.configure_client(client: stub_client)
end
end
Expand All @@ -14,9 +14,7 @@ def app
end

def stub_client
@stub_client ||= begin
Aws::DynamoDB::Client.new(stub_responses: true) # don't send real calls to DynamoDB in test env
end
@stub_client ||= Aws::DynamoDB::Client.new(stub_responses: true) # don't send real calls to DynamoDB in test env
end

# We could use native RSpec `post '/endpoint', param1: 'foo', param2: 'bar'
Expand All @@ -27,7 +25,7 @@ def api_gateway_post(path, params)
api_gateway_body_fwd = params.to_json
rack_input = StringIO.new(api_gateway_body_fwd)

post path, real_params = {}, {"rack.input" => rack_input}
post path, {}, { 'rack.input' => rack_input }
end

def json_result
Expand Down

0 comments on commit d0824f8

Please sign in to comment.