Introducing Jets - A Ruby Serverless Framework
Introducing Jets - A Ruby Serverless Framework ๊ด๋ จ
Update 2018/12/12
Official Ruby Support was announced at AWS re:Invent 2018 on Nov 29! Jets has switched over to it: Official AWS Ruby Support for Jets ๐. This article has been updated to reflect official Ruby support, but video in the post is out-of-date and will be updated in time.
Ruby on Jets is a framework that allows you to build serverless applications in a beautiful language: Ruby. It includes everything needed to build and deploy applications to AWS Lambda. I love working with Rails, Ruby and AWS; and wanted to work with something similar in the serverless world. So I built Jets.
It is key to understand AWS Lambda and API Gateway to understand Jets conceptually. Jets maps your code to Lambda functions and API Gateway resources.
- AWS Lambda provides Functions as a Service. It allows you to upload and run functions without worrying about the underlying infrastructure.
- API Gateway is the routing layer for Lambda. It is used to route REST URL endpoints to Lambda functions.
Example Architecture
Many architectures can be built with Jets. Hereโs an example traditional Web architecture that can easily be accomplished with Jets:
Functions
Jets supports writing simple AWS Lambda functions with Ruby. You define them in the app/functions
folder. A function looks like this:
app/functions/
simple.rb
:
def handler_function(event:, context:)
puts "hello world"
end
The default handler is named handler_function
.
Though simple functions are supported by Jets, they do not add much value as other classes like Controllers and Jobs. These other classes add many conveniences and are more powerful to use. Weโll cover them next.
Controllers
Hereโs the first example of Jets code, a controller:
app/controllers/
posts_controller.rb
:
class PostsController < ApplicationController
def index
# renders Lambda Proxy structure compatiable with API Gateway
render json: {hello: "world", action: "index"}
end
def show
id = params[:id] # params available
# puts goes to the lambda logs
puts event # raw lambda event available
render json: {action: "show", id: id}
end
end
If youโre familiar with Rails and Sinatra, this will look familiar. Helper methods like params provide the parameters from the API Gateway event. The render method renders a Lambda Proxy structure back that API Gateway understands.
Jets takes each controllerโs public methods and turns them into Lambda functions.
Routes
Hereโs what a routes file could look like:
config/
routes.rb
:
Jets.application.routes.draw do
get "posts", to: "posts#index"
get "posts/new", to: "posts#new"
get "posts/:id", to: "posts#show"
post "posts", to: "posts#create"
get "posts/:id/edit", to: "posts#edit"
put "posts", to: "posts#update"
delete "posts", to: "posts#delete"
end
Jets takes the routes file, creates the corresponding API Gateway resources, and associates them with Lambda functions.
Jobs
Jets also supports asynchronous jobs that work outside the web request-response cycle. Job code looks like:
app/jobs/
hard_job.rb
:
class HardJob < ApplicationJob
rate "10 hours" # every 10 hours
def dig
{done: "digging"}
end
cron "0 */12 * * ? *" # every 12 hours
def lift
{done: "lifting"}
end
end
The code above creates Lambda functions and CloudWatch event rules to handle the scheduling of work.
Project structure
Hereโs what a Jets project structure looks like.
.
โโโ app
โ โโโ controllers
โ โโโ helpers
โ โโโ javascript
โ โโโ jobs
โ โโโ models
โ โโโ views
โโโ bin
โโโ config
โโโ db
โโโ public
โโโ spec
We have the traditional MVC folders: app/models
, app/views
, and app/controllers
. The config
folder contains your applicationโs configuration settings. Further explanation for each folder is provided on the Project Structure docs.
Quick Start
Here are commands that generate a CRUD app to get you started:
gem install jets
jets new demo
cd demo
jets generate scaffold Post title:string
vim .env.development # edit with local db settings
jets db:create db:migrate
jets server
The jets server command starts a server that mimics API Gateway so you can test locally. Open http://localhost:8888/posts and test out the CRUD site created from the scaffold.
When youโre ready, adjust your .env.development.remote
with an RDS database and deploy to AWS Lambda.
vim .env.development.remote # adjust with remote db settings
jets deploy
#
# API Gateway Endpoint: https://puc3xyk4cj.execute-api.us-west-2.amazonaws.com/dev/
You should see something like this
Hereโs a live Demo of this tutorial. Note, the example records automatically get deleted and reseeded daily.
Other Live demos
Here are additional Live Demos of Jets applications:
- A Simple API with Jets: A Simple API. Hereโs a the blog post: Build an API with the Jets Ruby Serverless Framework
- Jets Afterburner: Rails Support: Please read over the considerations in the docs.
- Mega Mode: Jets and Rails Combined: A interesting hybrid mode.
- Image Upload with CarrierWave: Binary Support
More examples are in the tongueroo/jets-examples
repo.
Extra Environments
An interesting benefit of running applications on AWS Lambda is that you only get charged for actual requests. So extra environments are likely in the AWS free tier. You could do this:
JETS_ENV_EXTRA=2 jets deploy
JETS_ENV_EXTRA=3 jets deploy
...
JETS_ENV_EXTRA=8 jets deploy
You essentially get unlimited free environments, each of them taking a few minutes to provision.
Binary Gems
With Serverless, you will might run into the quirky binary gem issue. Most gems are pure Ruby code and can be used as-is on AWS Lambda. However, some gems like nokogiri use compiled native extensions. So you must compile these binary gems to the Lambda target architecture for them to work. Jets uses Lambda Gems to resolve this and makes for a much more seamless and pleasant developer experience. The Beta for Lambda Gems is has been open. Early signups for Lambda Gems will receive a special offer for their support.