Originally published at Codegram's blog
As a Serverless enthusiast at Codegram it was about time I published a new blog post since AWS Lambda has introduced official support for Ruby π.
You can read more at the official release blog post which also has an example Sinatra app to get started. If you want an in-depth review of the example and release, I recommend this nice review from EquiValent.
I was thrilled to learn that I can finally use Ruby with Lambda, but using Sinatra as an example feels wrong. If you want to build an API with it, you would want to have API Gateway do all the routing and request handling. Adding an extra layer to do the same at the application level is unnecessary and seems like an anti-pattern (I understand itβs used as an example of migrating microservices, but itβs still confusing).
After talking about it with my fellow Codegrammers I decided to build a small proof-of-concept GraphQL API with Ruby and Lambda, using Serverless to simplify the deployment and infrastructure, without Sinatra, Rack or any boilerplate.
The objective was to demonstrate that you can build an API and almost forget that youβre actually dealing with web requests, just focus on the GraphQL schema and the business logic. How does it look like? There are three key elements: serverless.yml exposes our function through an HTTP POST:
service: serverless-ruby-graphql
provider:
name: aws
runtime: ruby2.5
region: eu-west-1
stage: dev
functions:
api:
handler: app.request
events:
- http:
path: api
method: post
plugins:
- serverless-hooks-plugin
custom:
hooks:
package:initialize:
- bundle install --deployment
deploy:finalize:
- rm -fr .bundle
- rm -fr vendor
- bundle install
app.rb handles the incoming requests and delegates all the work to GraphQL Ruby:
require 'json'
require_relative "app/graphql/schema"
def request(event:, context:)
puts "Received Request: #{event}"
body = Schema.execute(event["body"]).to_json
{
statusCode: 200,
body: body
}
rescue StandardError => e
puts e.message
puts e.backtrace.inspect
{
statusCode: 400,
body: JSON.generate("Bad request, please POST a request body!")
}
end
And finally, app/ a folder with all the GraphQL schemas and models:
https://github.com/oriolgual/serverless-ruby-graphql/tree/master/app
Although this works OK, keep in mind that it is not production-ready code.
Let's build everything with Lambda
Well, maybe not. Building things with AWS Lambda and Ruby is straightforward, but would I build my next GraphQL API with it? Probably not.
Iβm not entirely sold on using AWS Lambda with user-facing APIs; response times are too unpredictable and quite high (yes, even if you keep your Lambdas warm). Things get [even]((https://www.robertvojta.com/aws-journey-api-gateway-lambda-vpc-performance/) slower if your Lambda needs to access resources inside a VPC (which is necessary if you want to access a database for example).
I really like Lambda, but I think it shines when used to respond to events (such as S3 uploads or Kinesis streams) where you donβt really care about some extra latency but scalability can be an issue.
Iβm eager to try something similar with Knative, Kubeless or OpenWhisk. So far Iβve only used AWS Lambda, and Iβd like to compare it to other solutions and get a better idea whether it would be a good option to deploy serverless, user-facing APIs.