SlideShare a Scribd company logo
1 of 53
Download to read offline
Using	
  Sinatra	
  to	
  Build	
  
REST	
  APIs	
  in	
  Ruby	
  
James	
  Higginbotham	
  
API	
  Architect	
  
@launchany	
  
Introduc?on	
  
WHAT	
  IS	
  SINATRA?	
  
Sinatra	
  is	
  a	
  DSL	
  for	
  quickly	
  
crea<ng	
  web	
  applica<ons	
  in	
  
Ruby	
  
# hi.rb
require 'rubygems’
require 'sinatra'
get '/' do
'Hello world!’
end
$ gem install sinatra
$ ruby hi.rb
== Sinatra has taken the stage ...
>> Listening on 0.0.0.0:4567
$ curl http://0.0.0.0:4567
Hello World
HOW	
  DOES	
  SINATRA	
  WORK?	
  
Rou?ng:	
  Verb	
  +	
  PaCern	
  +	
  Block	
  
post ’/' do
.. block ..
end
Rou?ng:	
  Named	
  Params	
  
get '/:id' do
model = MyModel.find( params[:id] )
...
end
Rou?ng:	
  Splat	
  Support	
  
get '/say/*/to/*' do
# matches /say/hello/to/world
params['splat'] # => ["hello", "world"]
...
end
get '/download/*.*' do
# matches /download/path/to/file.xml
params['splat'] # => ["path/to/file", "xml"]
...
end
Rou?ng:	
  Regex	
  Support	
  
get /A/hello/([w]+)z/ do
"Hello, #{params['captures'].first}!”
...
end
Rou?ng:	
  Op?onal	
  Parameters	
  
get '/posts.?:format?' do
# matches "GET /posts" and
# any extension "GET /posts.rss", "GET /posts.xml" etc.
end
Rou?ng:	
  URL	
  Query	
  Parameters	
  
get '/posts' do
# matches "GET /posts?title=foo&author=bar"
title = params['title']
author = params['author']
# uses title and author variables;
# query is optional to the /posts route
End
Rou?ng:	
  Condi?onal	
  Matching	
  
get '/', :host_name => /^admin./ do
"Admin Area, Access denied!"
end
get '/', :provides => 'html' do
haml :index
end
get '/', :provides => ['rss', 'atom', 'xml'] do
builder :feed
end
Rou?ng:	
  Custom	
  Condi?ons	
  
set(:probability) { |value| condition { rand <= value } }
get '/win_a_car', :probability => 0.1 do
"You won!"
end
get '/win_a_car' do
"Sorry, you lost."
End
Returning	
  Results	
  
# 1. String containing the body and default code of 200
get '/' do
'Hello world!’
end
# 2. Response code + body
get '/' do
[200, 'Hello world!’]
end
# 3. Response code + headers + body
get '/' do
[200, {'Content-Type' => 'text/plain'}, 'Hello world!’]
end
BUILDING	
  ON	
  RACK	
  
Hello	
  World	
  with	
  Rack	
  
# hello_world.rb
require 'rack'
require 'rack/server’
class HelloWorldApp
def self.call(env)
[200, {}, 'Hello World’]
end
end
Rack::Server.start :app => HelloWorldApp
Rack	
  env	
  
# hello_world.rb
require 'rack'
require 'rack/server’
class HelloWorldApp
def self.call(env)
[200, {},
"Hello World. You said: #{env['QUERY_STRING']}"]
end
end
Rack::Server.start :app => HelloWorldApp
Typical	
  env	
  
{
"SERVER_SOFTWARE"=>"thin 1.4.1 codename Chromeo",
"SERVER_NAME"=>"localhost",
"rack.input"=>#<StringIO:0x007fa1bce039f8>,
"rack.version"=>[1, 0],
"rack.errors"=>#<IO:<STDERR>>,
"rack.multithread"=>false,
"rack.multiprocess"=>false,
"rack.run_once"=>false,
"REQUEST_METHOD"=>"GET",
"REQUEST_PATH"=>"/favicon.ico",
"PATH_INFO"=>"/favicon.ico",
"REQUEST_URI"=>"/favicon.ico",
"HTTP_VERSION"=>"HTTP/1.1",
"HTTP_HOST"=>"localhost:8080",
"HTTP_CONNECTION"=>"keep-alive",
"HTTP_ACCEPT"=>"*/*”,
...
Typical	
  env	
  (con’t)	
  
...
"HTTP_USER_AGENT"=>
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4)
AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47
Safari/536.11",
"HTTP_ACCEPT_ENCODING"=>"gzip,deflate,sdch",
"HTTP_ACCEPT_LANGUAGE"=>"en-US,en;q=0.8",
"HTTP_ACCEPT_CHARSET"=>"ISO-8859-1,utf-8;q=0.7,*;q=0.3",
"HTTP_COOKIE"=> "_gauges_unique_year=1;
_gauges_unique_month=1",
"GATEWAY_INTERFACE"=>"CGI/1.2",
"SERVER_PORT"=>"8080",
"QUERY_STRING"=>"",
"SERVER_PROTOCOL"=>"HTTP/1.1",
"rack.url_scheme"=>"http",
"SCRIPT_NAME"=>"",
"REMOTE_ADDR"=>"127.0.0.1",
...
}
The	
  Rack::Request	
  Wrapper	
  
class HelloWorldApp
def self.call(env)
request = Rack::Request.new(env)
request.params # contains the union of GET and POST
params
request.xhr? # requested with AJAX
require.body # the incoming request IO stream
if request.params['message']
[200, {}, request.params['message']]
else
[200, {}, 'Say something to me!']
end
end
end
Rack	
  Middleware	
  
u  Rack	
  allows	
  for	
  chaining	
  mul?ple	
  call()	
  
methods	
  
u  We	
  can	
  do	
  anything	
  we	
  want	
  within	
  each	
  call()	
  
u  This	
  includes	
  separa?ng	
  behavior	
  into	
  
reusable	
  classes	
  (e.g.	
  across	
  Sinatra	
  and	
  Rails)	
  
u  SRP	
  (Single	
  Responsibility	
  Principle)	
  
– Each	
  class	
  has	
  a	
  single	
  responsibility	
  
– Our	
  app	
  is	
  composed	
  of	
  mul?ple	
  classes	
  that	
  each	
  
do	
  one	
  thing	
  well	
  
Rack::Builder	
  for	
  Middleware	
  
# this returns an app that responds to call cascading down
# the list of middlewares.
app = Rack::Builder.new do
use Rack::Etag # Add an ETag
use Rack::ConditionalGet # Support Caching
use Rack::Deflator # GZip
run HelloWorldApp # Say Hello
end
Rack::Server.start :app => app
# Resulting call tree:
# Rack::Etag
# Rack::ConditionalGet
# Rack::Deflator
# HelloWorldApp
Using	
  the	
  Rackup	
  Command	
  
u  Combines	
  all	
  of	
  these	
  concepts	
  into	
  a	
  config	
  
u  Will	
  start	
  a	
  web	
  process	
  with	
  your	
  Rack	
  app	
  
u  Central	
  loca?on	
  for	
  requires,	
  bootstrapping	
  
u  Enables	
  middleware	
  to	
  be	
  configured	
  as	
  well	
  
u  Default	
  filename	
  is	
  config.ru	
  
u  Used	
  to	
  bootstrap	
  Rails	
  
Using	
  Rackup	
  
# config.ru
# HelloWorldApp defintion
# EnsureJsonResponse defintion
# Timer definition
use Timer
use EnsureJsonResponse
run HelloWorldApp
$ rackup –p 4567
Using	
  Mul?ple	
  Sinatra	
  Apps	
  
u  Rackup	
  allows	
  for	
  moun?ng	
  mul?ple	
  Sinatra	
  
Apps	
  
u  This	
  allows	
  for	
  more	
  modular	
  APIs	
  
u  Recommend	
  one	
  Sinatra	
  app	
  per	
  top-­‐level	
  
resource	
  
Moun?ng	
  Mul?ple	
  Sinatra	
  Apps	
  
# config.ru
require 'sinatra'
require 'app/auth_api'
require 'app/users_api'
require 'app/organizations_api'
map "/auth" do
run AuthApi
end
map "/users" do
run UsersApi
end
map "/organizations" do
run OrganizationsApi
end
Important:	
  Require	
  !=	
  Automa?c	
  
u  Must	
  manage	
  your	
  own	
  requires	
  
u  No	
  free	
  ride	
  (like	
  with	
  Rails)	
  
u  This	
  means	
  order	
  of	
  requires	
  is	
  important!	
  
WHAT	
  IS	
  A	
  REST	
  API?	
  
Mul?ple	
  API	
  Design	
  Choices	
  
u  RPC-­‐based	
  
– Uses	
  HTTP	
  for	
  transport	
  only	
  
– Endpoints	
  are	
  not	
  unique,	
  only	
  the	
  payload	
  
– No	
  HTTP	
  caching	
  available	
  
– e.g.	
  POST	
  /getUserDetails,	
  POST	
  /createUser	
  
u  Resource-­‐based	
  
– Unique	
  URLs	
  for	
  resources	
  and	
  collec?ons	
  
– HTTP	
  caching	
  available	
  
– e.g.	
  GET	
  /users/{userId}	
  and	
  GET	
  /users	
  
Hypermedia	
  REST	
  
u  An	
  architectural	
  style,	
  with	
  constraints	
  
u  A	
  set	
  of	
  constraints,	
  usually	
  on	
  top	
  of	
  HTTP	
  
u  Not	
  a	
  standard;	
  builds	
  on	
  the	
  standard	
  of	
  
HTTP	
  
u  Mul?ple	
  content	
  types	
  (e.g.	
  JSON,	
  XML,	
  CSV)	
  
u  The	
  response	
  is	
  a	
  representa?on	
  of	
  the	
  
resource	
  state	
  (data)	
  plus	
  server-­‐side	
  state	
  in	
  
the	
  form	
  of	
  ac<ons/transi<ons	
  (links)	
  
BUILDING	
  AN	
  API	
  USING	
  SINATRA	
  
Resource	
  Lifecycle	
  using	
  Sinatra	
  
get '/users' do
.. list a resource collection (and search) ..
end
get '/users/:id' do
.. resource instance details ..
end
post '/users' do
.. create new resource ..
end
put '/users/:id' do
.. replace resource ..
End
delete ’/users/:id' do
.. annihilate resource ..
end
List	
  Resources	
  Example	
  
get '/users' do
# 1. capture any search filters using params[]
email_filter = params[:email]
# 2. build query and fetch results from database
if email_filter
users = User.where( email: email_filter ).all
else
users = User.all
# 3. marshal results to proper content type (e.g. JSON)
[200, users.to_json]
end
List	
  Resources	
  Example	
  
get '/users' do
# 1. capture any search filters using params[]
email_filter = params[:email]
# 2. build query and fetch results from database
if email_filter
users = User.where( email: email_filter ).all
else
users = User.all
# 3. marshal results to proper content type (e.g. JSON)
[200, users.to_json]
# Q: Which ORM should we use with Sinatra?
# Q: Can we customize the results format easily?
end
USEFUL	
  GEMS	
  
Selec?ng	
  an	
  ORM	
  
u  Ac?veRecord	
  
u  DataMapper	
  
u  Sequel	
  (my	
  favorite)	
  
– Flexible	
  as	
  it	
  supports	
  Datasets	
  and	
  Models	
  
Sequel	
  Datasets	
  Example	
  
require 'sequel'
DB = Sequel.sqlite # memory database
DB.create_table :items do
primary_key :id
String :name
Float :price
end
items = DB[:items] # Create a dataset
items.insert(:name => 'abc', :price => rand * 100)
items.insert(:name => 'def', :price => rand * 100)
items.insert(:name => 'ghi', :price => rand * 100)
puts "Item count: #{items.count}"
puts "The average price is: #{items.avg(:price)}”
Sequel	
  Model	
  Example	
  
require 'sequel'
DB = Sequel.sqlite # memory database
class Post < Sequel::Model
end
post = Post[123]
post = Post.new
post.title = 'hello world'
post.save
Select	
  a	
  Marshaling	
  Library	
  
u  Ac?veModel::Serializers	
  (AMS)	
  	
  
– Works	
  with	
  Kaminari	
  and	
  WillPaginate	
  
– Supported	
  by	
  Rails	
  core	
  team	
  
– One-­‐way	
  JSON	
  genera?on	
  only	
  
u  Roar+Representable	
  (my	
  favorite)	
  
– Works	
  with	
  and	
  without	
  Rails	
  
– Bi-­‐direc?onal	
  marshaling	
  
– Supports	
  JSON,	
  XML,	
  YAML,	
  hash	
  
Representable	
  
module SongRepresenter
include Representable::JSON
property :title
property :track
collection :composers
end
class Song < OpenStruct
end
song = Song.new(title: "Fallout", track: 1)
song.extend(SongRepresenter).to_json
> {"title":"Fallout","track":1}
song = Song.new.extend(SongRepresenter).from_json(%
{ {"title":"Roxanne"} })
> #<Song title="Roxanne">
Roar	
  +	
  Representable	
  
module SongRepresenter
include Roar::JSON
include Roar::Hypermedia
property :title
property :track
collection :composers
link :self do
"/songs/#{title}"
end
end
song = Song.new(title: "Fallout", track: 1)
song.extend(SongRepresenter).to_json
> {"title":"Fallout","track":1,"links":
[{"rel":"self","href":"/songs/Fallout"}]}"
Tools	
  for	
  Tes?ng	
  Your	
  API	
  
u  Unit	
  –	
  RSpec	
  
– Models,	
  helpers	
  
u  Integra?on	
  –	
  RSpec	
  
– Make	
  HTTP	
  calls	
  to	
  a	
  running	
  Sinatra	
  process	
  
– Controller-­‐focused	
  
u  Acceptance/BDD	
  –	
  RSpec,	
  Cucumber	
  
– Make	
  HTTP	
  calls	
  to	
  a	
  running	
  Sinatra	
  process	
  
– Use-­‐case/story	
  focused	
  
MATURING	
  YOUR	
  SINATRA	
  APPS	
  
Addi?onal	
  Gems	
  
u  faraday	
  –	
  HTTP	
  client	
  with	
  middleware	
  for	
  
tes?ng	
  and	
  3rd	
  party	
  API	
  integra?on	
  
u  xml-­‐simple	
  –	
  Easy	
  XML	
  parsing	
  and	
  genera?on	
  
u  faker	
  –	
  Generates	
  fake	
  names,	
  addresses,	
  etc.	
  
u  uuidtools	
  –	
  uuid	
  generator	
  when	
  incremen?ng	
  
integers	
  aren’t	
  good	
  enough	
  
u  bcrypt	
  –	
  Ruby	
  binding	
  for	
  OpenBSD	
  hashing	
  
algorithm,	
  to	
  secure	
  data	
  at	
  rest	
  
Addi?onal	
  Gems	
  (part	
  2)	
  
u  rack-­‐conneg	
  –	
  Content	
  nego?a?on	
  support	
  
get '/hello' do
response = { :message => 'Hello, World!' }
respond_to do |wants|
wants.json { response.to_json }
wants.xml { response.to_xml }
wants.other {
content_type 'text/plain'
error 406, "Not Acceptable"
}
end
end
curl -H "Accept: application/json" http://localhost:4567/
hello
Addi?onal	
  Gems	
  (part	
  3)	
  
u  hirb	
  –	
  Console	
  formaing	
  of	
  data	
  from	
  CLI,	
  
Rake	
  tasks	
  
irb>> Tag.last
+-----+-------------------------+-------------+
| id | created_at | description |
+-----+-------------------------+-------------+
| 907 | 2009-03-06 21:10:41 UTC | blah |
+-----+-------------------------+-------------+
1 row in set
Reloading	
  with	
  Shotgun	
  Gem	
  
u  No	
  automa?c	
  reload	
  of	
  classes	
  with	
  Sinatra	
  
u  Instead,	
  use	
  the	
  shotgun	
  gem:	
  
u  Note:	
  Only	
  works	
  with	
  Ruby	
  MRI	
  where	
  fork()	
  
is	
  available	
  (POSIX)	
  
$ gem install shotgun
$ shotgun config.ru
Puma	
  +	
  JRuby	
  
u  Ruby	
  MRI	
  is	
  geing	
  beCer	
  
u  JVM	
  is	
  faster	
  (2-­‐5x),	
  very	
  mature	
  (since	
  1997)	
  
u  High	
  performance	
  garbage	
  collectors,	
  na?ve	
  
threading,	
  JMX	
  management	
  extensions	
  
u  JDBC	
  libraries	
  very	
  mature	
  and	
  performant	
  for	
  
SQL-­‐based	
  access	
  
u  Puma	
  is	
  recommended	
  over	
  unicorn	
  for	
  JRuby	
  	
  
From	
  Sinatra	
  to	
  Padrino	
  
u  Padrino	
  provides	
  Rails-­‐like	
  environment	
  for	
  
Sinatra	
  
u  Build	
  in	
  Sinatra,	
  move	
  to	
  Padrino	
  when	
  
needed	
  
u  Generators,	
  pluggable	
  modules,	
  admin	
  
generator	
  
Resources	
  
u  Sinatra	
  Docs:	
  	
  
hCp://www.sinatrarb.com/intro.html	
  	
  
u  Introduc?on	
  to	
  Rack:	
  
hCp://hawkins.io/2012/07/rack_from_the_beginning/	
  	
  
u  Sequel	
  Gem:	
  
hCps://github.com/jeremyevans/sequel	
  	
  
u  Roar/Representable:	
  
hCps://github.com/apotonick/roar	
  	
  
hCps://github.com/apotonick/representable	
  	
  
Thanks	
  Ya’ll	
  
James	
  Higginbotham	
  
james@launchany.com	
  
hCp://launchany.com	
  	
  
@launchany	
  
	
  
Design	
  Beau?ful	
  APIs:	
  
hCp://TheApiDesignBook.com	
  	
  
QUESTIONS	
  

More Related Content

What's hot

Mongodb 특징 분석
Mongodb 특징 분석Mongodb 특징 분석
Mongodb 특징 분석
Daeyong Shin
 
Unbreaking Your Django Application
Unbreaking Your Django ApplicationUnbreaking Your Django Application
Unbreaking Your Django Application
OSCON Byrum
 

What's hot (20)

Apache Jackrabbit Oak - Scale your content repository to the cloud
Apache Jackrabbit Oak - Scale your content repository to the cloudApache Jackrabbit Oak - Scale your content repository to the cloud
Apache Jackrabbit Oak - Scale your content repository to the cloud
 
Managing dependencies with gradle
Managing dependencies with gradleManaging dependencies with gradle
Managing dependencies with gradle
 
JCR - Java Content Repositories
JCR - Java Content RepositoriesJCR - Java Content Repositories
JCR - Java Content Repositories
 
Curso de ReactJS
Curso de ReactJSCurso de ReactJS
Curso de ReactJS
 
Local Apache NiFi Processor Debug
Local Apache NiFi Processor DebugLocal Apache NiFi Processor Debug
Local Apache NiFi Processor Debug
 
HDFS Federation
HDFS FederationHDFS Federation
HDFS Federation
 
Laravel Tutorial PPT
Laravel Tutorial PPTLaravel Tutorial PPT
Laravel Tutorial PPT
 
MongoDB Schema Design
MongoDB Schema DesignMongoDB Schema Design
MongoDB Schema Design
 
Java concurrency - Thread pools
Java concurrency - Thread poolsJava concurrency - Thread pools
Java concurrency - Thread pools
 
하둡 HDFS 훑어보기
하둡 HDFS 훑어보기하둡 HDFS 훑어보기
하둡 HDFS 훑어보기
 
Jest
JestJest
Jest
 
Mongodb 특징 분석
Mongodb 특징 분석Mongodb 특징 분석
Mongodb 특징 분석
 
Basics of MongoDB
Basics of MongoDB Basics of MongoDB
Basics of MongoDB
 
Tomcat and apache httpd training
Tomcat and apache httpd trainingTomcat and apache httpd training
Tomcat and apache httpd training
 
Laravel Introduction
Laravel IntroductionLaravel Introduction
Laravel Introduction
 
[D2 CAMPUS]웹 개발자의 스펙 : HTTP
[D2 CAMPUS]웹 개발자의 스펙 : HTTP[D2 CAMPUS]웹 개발자의 스펙 : HTTP
[D2 CAMPUS]웹 개발자의 스펙 : HTTP
 
Installing Groovy engine in Apache Jmeter
Installing Groovy engine in Apache JmeterInstalling Groovy engine in Apache Jmeter
Installing Groovy engine in Apache Jmeter
 
Comparison of Top CMS Systems
Comparison of Top CMS SystemsComparison of Top CMS Systems
Comparison of Top CMS Systems
 
facebook architecture for 600M users
facebook architecture for 600M usersfacebook architecture for 600M users
facebook architecture for 600M users
 
Unbreaking Your Django Application
Unbreaking Your Django ApplicationUnbreaking Your Django Application
Unbreaking Your Django Application
 

Similar to Using Sinatra to Build REST APIs in Ruby

RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
崇之 清水
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Tatsuhiko Miyagawa
 
Socket applications
Socket applicationsSocket applications
Socket applications
João Moura
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
Wesley Beary
 

Similar to Using Sinatra to Build REST APIs in Ruby (20)

Rack
RackRack
Rack
 
Sinatra and JSONQuery Web Service
Sinatra and JSONQuery Web ServiceSinatra and JSONQuery Web Service
Sinatra and JSONQuery Web Service
 
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
 
Sinatra
SinatraSinatra
Sinatra
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
 
Rhebok, High Performance Rack Handler / Rubykaigi 2015
Rhebok, High Performance Rack Handler / Rubykaigi 2015Rhebok, High Performance Rack Handler / Rubykaigi 2015
Rhebok, High Performance Rack Handler / Rubykaigi 2015
 
fog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloudfog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloud
 
Socket applications
Socket applicationsSocket applications
Socket applications
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
 
8 Minutes On Rack
8 Minutes On Rack8 Minutes On Rack
8 Minutes On Rack
 
Intro to Rack
Intro to RackIntro to Rack
Intro to Rack
 
Crossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end FrameworkCrossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end Framework
 
Wider than rails
Wider than railsWider than rails
Wider than rails
 
Rack Middleware
Rack MiddlewareRack Middleware
Rack Middleware
 
Rapid Prototyping FTW!!!
Rapid Prototyping FTW!!!Rapid Prototyping FTW!!!
Rapid Prototyping FTW!!!
 
infra-as-code
infra-as-codeinfra-as-code
infra-as-code
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Rack
 
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine YardHow I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
 
Build Web Apps using Node.js
Build Web Apps using Node.jsBuild Web Apps using Node.js
Build Web Apps using Node.js
 
Swing when you're winning - an introduction to Ruby and Sinatra
Swing when you're winning - an introduction to Ruby and SinatraSwing when you're winning - an introduction to Ruby and Sinatra
Swing when you're winning - an introduction to Ruby and Sinatra
 

More from LaunchAny

More from LaunchAny (20)

Refining Your API Design - Architecture and Modeling Learning Event
Refining Your API Design - Architecture and Modeling Learning EventRefining Your API Design - Architecture and Modeling Learning Event
Refining Your API Design - Architecture and Modeling Learning Event
 
Event-Based API Patterns and Practices
Event-Based API Patterns and PracticesEvent-Based API Patterns and Practices
Event-Based API Patterns and Practices
 
Event-based API Patterns and Practices - AsyncAPI Online Conference
Event-based API Patterns and Practices - AsyncAPI Online ConferenceEvent-based API Patterns and Practices - AsyncAPI Online Conference
Event-based API Patterns and Practices - AsyncAPI Online Conference
 
GlueCon 2019: Beyond REST - Moving to Event-Based APIs and Streaming
GlueCon 2019: Beyond REST - Moving to Event-Based APIs and StreamingGlueCon 2019: Beyond REST - Moving to Event-Based APIs and Streaming
GlueCon 2019: Beyond REST - Moving to Event-Based APIs and Streaming
 
Austin API Summit 2019 - APIs, Microservices, and Serverless: The Shape of Th...
Austin API Summit 2019 - APIs, Microservices, and Serverless: The Shape of Th...Austin API Summit 2019 - APIs, Microservices, and Serverless: The Shape of Th...
Austin API Summit 2019 - APIs, Microservices, and Serverless: The Shape of Th...
 
APIStrat Keynote: Lessons in Transforming the Enterprise to an API Platform
APIStrat Keynote: Lessons in Transforming the Enterprise to an API PlatformAPIStrat Keynote: Lessons in Transforming the Enterprise to an API Platform
APIStrat Keynote: Lessons in Transforming the Enterprise to an API Platform
 
Austin API Summit 2018: Are REST APIs Still Relevant Today?
Austin API Summit 2018: Are REST APIs Still Relevant Today?Austin API Summit 2018: Are REST APIs Still Relevant Today?
Austin API Summit 2018: Are REST APIs Still Relevant Today?
 
GlueCon 2018: Are REST APIs Still Relevant Today?
GlueCon 2018: Are REST APIs Still Relevant Today?GlueCon 2018: Are REST APIs Still Relevant Today?
GlueCon 2018: Are REST APIs Still Relevant Today?
 
Lessons in Transforming the Enterprise to an API Platform
Lessons in Transforming the Enterprise to an API PlatformLessons in Transforming the Enterprise to an API Platform
Lessons in Transforming the Enterprise to an API Platform
 
APIStrat 2017: API Design in the Age of Bots, IoT, and Voice
APIStrat 2017: API Design in the Age of Bots, IoT, and VoiceAPIStrat 2017: API Design in the Age of Bots, IoT, and Voice
APIStrat 2017: API Design in the Age of Bots, IoT, and Voice
 
API Design in the Age of Bots, IoT, and Voice
API Design in the Age of Bots, IoT, and VoiceAPI Design in the Age of Bots, IoT, and Voice
API Design in the Age of Bots, IoT, and Voice
 
APIStrat 2016: Moving Toward a Modular Enterprise
APIStrat 2016: Moving Toward a Modular EnterpriseAPIStrat 2016: Moving Toward a Modular Enterprise
APIStrat 2016: Moving Toward a Modular Enterprise
 
API:World 2016 - Applying Domain Driven Design to APIs and Microservices
API:World 2016 - Applying Domain Driven Design to APIs and MicroservicesAPI:World 2016 - Applying Domain Driven Design to APIs and Microservices
API:World 2016 - Applying Domain Driven Design to APIs and Microservices
 
Moving Toward a Modular Enterprise - All About the API Conference 2016
Moving Toward a Modular Enterprise - All About the API Conference 2016Moving Toward a Modular Enterprise - All About the API Conference 2016
Moving Toward a Modular Enterprise - All About the API Conference 2016
 
Designing APIs and Microservices Using Domain-Driven Design
Designing APIs and Microservices Using Domain-Driven DesignDesigning APIs and Microservices Using Domain-Driven Design
Designing APIs and Microservices Using Domain-Driven Design
 
Applying Domain-Driven Design to APIs and Microservices - Austin API Meetup
Applying Domain-Driven Design to APIs and Microservices  - Austin API MeetupApplying Domain-Driven Design to APIs and Microservices  - Austin API Meetup
Applying Domain-Driven Design to APIs and Microservices - Austin API Meetup
 
APIs Are Forever - How to Design Long-Lasting APIs
APIs Are Forever - How to Design Long-Lasting APIsAPIs Are Forever - How to Design Long-Lasting APIs
APIs Are Forever - How to Design Long-Lasting APIs
 
API Thinking - How to Design APIs Through Systems Design
API Thinking - How to Design APIs Through Systems DesignAPI Thinking - How to Design APIs Through Systems Design
API Thinking - How to Design APIs Through Systems Design
 
Swagger 2.0: Latest and Greatest
Swagger 2.0: Latest and GreatestSwagger 2.0: Latest and Greatest
Swagger 2.0: Latest and Greatest
 
Gluecon 2015 Recap
Gluecon 2015 RecapGluecon 2015 Recap
Gluecon 2015 Recap
 

Recently uploaded

The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
shinachiaurasa2
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 

Recently uploaded (20)

The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
Pharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodologyPharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodology
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfAzure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptxBUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
ManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide DeckManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide Deck
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 

Using Sinatra to Build REST APIs in Ruby

  • 1. Using  Sinatra  to  Build   REST  APIs  in  Ruby   James  Higginbotham   API  Architect   @launchany  
  • 4. Sinatra  is  a  DSL  for  quickly   crea<ng  web  applica<ons  in   Ruby  
  • 5. # hi.rb require 'rubygems’ require 'sinatra' get '/' do 'Hello world!’ end $ gem install sinatra $ ruby hi.rb == Sinatra has taken the stage ... >> Listening on 0.0.0.0:4567 $ curl http://0.0.0.0:4567 Hello World
  • 6. HOW  DOES  SINATRA  WORK?  
  • 7. Rou?ng:  Verb  +  PaCern  +  Block   post ’/' do .. block .. end
  • 8. Rou?ng:  Named  Params   get '/:id' do model = MyModel.find( params[:id] ) ... end
  • 9. Rou?ng:  Splat  Support   get '/say/*/to/*' do # matches /say/hello/to/world params['splat'] # => ["hello", "world"] ... end get '/download/*.*' do # matches /download/path/to/file.xml params['splat'] # => ["path/to/file", "xml"] ... end
  • 10. Rou?ng:  Regex  Support   get /A/hello/([w]+)z/ do "Hello, #{params['captures'].first}!” ... end
  • 11. Rou?ng:  Op?onal  Parameters   get '/posts.?:format?' do # matches "GET /posts" and # any extension "GET /posts.rss", "GET /posts.xml" etc. end
  • 12. Rou?ng:  URL  Query  Parameters   get '/posts' do # matches "GET /posts?title=foo&author=bar" title = params['title'] author = params['author'] # uses title and author variables; # query is optional to the /posts route End
  • 13. Rou?ng:  Condi?onal  Matching   get '/', :host_name => /^admin./ do "Admin Area, Access denied!" end get '/', :provides => 'html' do haml :index end get '/', :provides => ['rss', 'atom', 'xml'] do builder :feed end
  • 14. Rou?ng:  Custom  Condi?ons   set(:probability) { |value| condition { rand <= value } } get '/win_a_car', :probability => 0.1 do "You won!" end get '/win_a_car' do "Sorry, you lost." End
  • 15. Returning  Results   # 1. String containing the body and default code of 200 get '/' do 'Hello world!’ end # 2. Response code + body get '/' do [200, 'Hello world!’] end # 3. Response code + headers + body get '/' do [200, {'Content-Type' => 'text/plain'}, 'Hello world!’] end
  • 17. Hello  World  with  Rack   # hello_world.rb require 'rack' require 'rack/server’ class HelloWorldApp def self.call(env) [200, {}, 'Hello World’] end end Rack::Server.start :app => HelloWorldApp
  • 18. Rack  env   # hello_world.rb require 'rack' require 'rack/server’ class HelloWorldApp def self.call(env) [200, {}, "Hello World. You said: #{env['QUERY_STRING']}"] end end Rack::Server.start :app => HelloWorldApp
  • 19. Typical  env   { "SERVER_SOFTWARE"=>"thin 1.4.1 codename Chromeo", "SERVER_NAME"=>"localhost", "rack.input"=>#<StringIO:0x007fa1bce039f8>, "rack.version"=>[1, 0], "rack.errors"=>#<IO:<STDERR>>, "rack.multithread"=>false, "rack.multiprocess"=>false, "rack.run_once"=>false, "REQUEST_METHOD"=>"GET", "REQUEST_PATH"=>"/favicon.ico", "PATH_INFO"=>"/favicon.ico", "REQUEST_URI"=>"/favicon.ico", "HTTP_VERSION"=>"HTTP/1.1", "HTTP_HOST"=>"localhost:8080", "HTTP_CONNECTION"=>"keep-alive", "HTTP_ACCEPT"=>"*/*”, ...
  • 20. Typical  env  (con’t)   ... "HTTP_USER_AGENT"=> "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47 Safari/536.11", "HTTP_ACCEPT_ENCODING"=>"gzip,deflate,sdch", "HTTP_ACCEPT_LANGUAGE"=>"en-US,en;q=0.8", "HTTP_ACCEPT_CHARSET"=>"ISO-8859-1,utf-8;q=0.7,*;q=0.3", "HTTP_COOKIE"=> "_gauges_unique_year=1; _gauges_unique_month=1", "GATEWAY_INTERFACE"=>"CGI/1.2", "SERVER_PORT"=>"8080", "QUERY_STRING"=>"", "SERVER_PROTOCOL"=>"HTTP/1.1", "rack.url_scheme"=>"http", "SCRIPT_NAME"=>"", "REMOTE_ADDR"=>"127.0.0.1", ... }
  • 21. The  Rack::Request  Wrapper   class HelloWorldApp def self.call(env) request = Rack::Request.new(env) request.params # contains the union of GET and POST params request.xhr? # requested with AJAX require.body # the incoming request IO stream if request.params['message'] [200, {}, request.params['message']] else [200, {}, 'Say something to me!'] end end end
  • 22. Rack  Middleware   u  Rack  allows  for  chaining  mul?ple  call()   methods   u  We  can  do  anything  we  want  within  each  call()   u  This  includes  separa?ng  behavior  into   reusable  classes  (e.g.  across  Sinatra  and  Rails)   u  SRP  (Single  Responsibility  Principle)   – Each  class  has  a  single  responsibility   – Our  app  is  composed  of  mul?ple  classes  that  each   do  one  thing  well  
  • 23. Rack::Builder  for  Middleware   # this returns an app that responds to call cascading down # the list of middlewares. app = Rack::Builder.new do use Rack::Etag # Add an ETag use Rack::ConditionalGet # Support Caching use Rack::Deflator # GZip run HelloWorldApp # Say Hello end Rack::Server.start :app => app # Resulting call tree: # Rack::Etag # Rack::ConditionalGet # Rack::Deflator # HelloWorldApp
  • 24. Using  the  Rackup  Command   u  Combines  all  of  these  concepts  into  a  config   u  Will  start  a  web  process  with  your  Rack  app   u  Central  loca?on  for  requires,  bootstrapping   u  Enables  middleware  to  be  configured  as  well   u  Default  filename  is  config.ru   u  Used  to  bootstrap  Rails  
  • 25. Using  Rackup   # config.ru # HelloWorldApp defintion # EnsureJsonResponse defintion # Timer definition use Timer use EnsureJsonResponse run HelloWorldApp $ rackup –p 4567
  • 26. Using  Mul?ple  Sinatra  Apps   u  Rackup  allows  for  moun?ng  mul?ple  Sinatra   Apps   u  This  allows  for  more  modular  APIs   u  Recommend  one  Sinatra  app  per  top-­‐level   resource  
  • 27. Moun?ng  Mul?ple  Sinatra  Apps   # config.ru require 'sinatra' require 'app/auth_api' require 'app/users_api' require 'app/organizations_api' map "/auth" do run AuthApi end map "/users" do run UsersApi end map "/organizations" do run OrganizationsApi end
  • 28. Important:  Require  !=  Automa?c   u  Must  manage  your  own  requires   u  No  free  ride  (like  with  Rails)   u  This  means  order  of  requires  is  important!  
  • 29. WHAT  IS  A  REST  API?  
  • 30. Mul?ple  API  Design  Choices   u  RPC-­‐based   – Uses  HTTP  for  transport  only   – Endpoints  are  not  unique,  only  the  payload   – No  HTTP  caching  available   – e.g.  POST  /getUserDetails,  POST  /createUser   u  Resource-­‐based   – Unique  URLs  for  resources  and  collec?ons   – HTTP  caching  available   – e.g.  GET  /users/{userId}  and  GET  /users  
  • 31. Hypermedia  REST   u  An  architectural  style,  with  constraints   u  A  set  of  constraints,  usually  on  top  of  HTTP   u  Not  a  standard;  builds  on  the  standard  of   HTTP   u  Mul?ple  content  types  (e.g.  JSON,  XML,  CSV)   u  The  response  is  a  representa?on  of  the   resource  state  (data)  plus  server-­‐side  state  in   the  form  of  ac<ons/transi<ons  (links)  
  • 32. BUILDING  AN  API  USING  SINATRA  
  • 33. Resource  Lifecycle  using  Sinatra   get '/users' do .. list a resource collection (and search) .. end get '/users/:id' do .. resource instance details .. end post '/users' do .. create new resource .. end put '/users/:id' do .. replace resource .. End delete ’/users/:id' do .. annihilate resource .. end
  • 34. List  Resources  Example   get '/users' do # 1. capture any search filters using params[] email_filter = params[:email] # 2. build query and fetch results from database if email_filter users = User.where( email: email_filter ).all else users = User.all # 3. marshal results to proper content type (e.g. JSON) [200, users.to_json] end
  • 35. List  Resources  Example   get '/users' do # 1. capture any search filters using params[] email_filter = params[:email] # 2. build query and fetch results from database if email_filter users = User.where( email: email_filter ).all else users = User.all # 3. marshal results to proper content type (e.g. JSON) [200, users.to_json] # Q: Which ORM should we use with Sinatra? # Q: Can we customize the results format easily? end
  • 37. Selec?ng  an  ORM   u  Ac?veRecord   u  DataMapper   u  Sequel  (my  favorite)   – Flexible  as  it  supports  Datasets  and  Models  
  • 38. Sequel  Datasets  Example   require 'sequel' DB = Sequel.sqlite # memory database DB.create_table :items do primary_key :id String :name Float :price end items = DB[:items] # Create a dataset items.insert(:name => 'abc', :price => rand * 100) items.insert(:name => 'def', :price => rand * 100) items.insert(:name => 'ghi', :price => rand * 100) puts "Item count: #{items.count}" puts "The average price is: #{items.avg(:price)}”
  • 39. Sequel  Model  Example   require 'sequel' DB = Sequel.sqlite # memory database class Post < Sequel::Model end post = Post[123] post = Post.new post.title = 'hello world' post.save
  • 40. Select  a  Marshaling  Library   u  Ac?veModel::Serializers  (AMS)     – Works  with  Kaminari  and  WillPaginate   – Supported  by  Rails  core  team   – One-­‐way  JSON  genera?on  only   u  Roar+Representable  (my  favorite)   – Works  with  and  without  Rails   – Bi-­‐direc?onal  marshaling   – Supports  JSON,  XML,  YAML,  hash  
  • 41. Representable   module SongRepresenter include Representable::JSON property :title property :track collection :composers end class Song < OpenStruct end song = Song.new(title: "Fallout", track: 1) song.extend(SongRepresenter).to_json > {"title":"Fallout","track":1} song = Song.new.extend(SongRepresenter).from_json(% { {"title":"Roxanne"} }) > #<Song title="Roxanne">
  • 42. Roar  +  Representable   module SongRepresenter include Roar::JSON include Roar::Hypermedia property :title property :track collection :composers link :self do "/songs/#{title}" end end song = Song.new(title: "Fallout", track: 1) song.extend(SongRepresenter).to_json > {"title":"Fallout","track":1,"links": [{"rel":"self","href":"/songs/Fallout"}]}"
  • 43. Tools  for  Tes?ng  Your  API   u  Unit  –  RSpec   – Models,  helpers   u  Integra?on  –  RSpec   – Make  HTTP  calls  to  a  running  Sinatra  process   – Controller-­‐focused   u  Acceptance/BDD  –  RSpec,  Cucumber   – Make  HTTP  calls  to  a  running  Sinatra  process   – Use-­‐case/story  focused  
  • 45. Addi?onal  Gems   u  faraday  –  HTTP  client  with  middleware  for   tes?ng  and  3rd  party  API  integra?on   u  xml-­‐simple  –  Easy  XML  parsing  and  genera?on   u  faker  –  Generates  fake  names,  addresses,  etc.   u  uuidtools  –  uuid  generator  when  incremen?ng   integers  aren’t  good  enough   u  bcrypt  –  Ruby  binding  for  OpenBSD  hashing   algorithm,  to  secure  data  at  rest  
  • 46. Addi?onal  Gems  (part  2)   u  rack-­‐conneg  –  Content  nego?a?on  support   get '/hello' do response = { :message => 'Hello, World!' } respond_to do |wants| wants.json { response.to_json } wants.xml { response.to_xml } wants.other { content_type 'text/plain' error 406, "Not Acceptable" } end end curl -H "Accept: application/json" http://localhost:4567/ hello
  • 47. Addi?onal  Gems  (part  3)   u  hirb  –  Console  formaing  of  data  from  CLI,   Rake  tasks   irb>> Tag.last +-----+-------------------------+-------------+ | id | created_at | description | +-----+-------------------------+-------------+ | 907 | 2009-03-06 21:10:41 UTC | blah | +-----+-------------------------+-------------+ 1 row in set
  • 48. Reloading  with  Shotgun  Gem   u  No  automa?c  reload  of  classes  with  Sinatra   u  Instead,  use  the  shotgun  gem:   u  Note:  Only  works  with  Ruby  MRI  where  fork()   is  available  (POSIX)   $ gem install shotgun $ shotgun config.ru
  • 49. Puma  +  JRuby   u  Ruby  MRI  is  geing  beCer   u  JVM  is  faster  (2-­‐5x),  very  mature  (since  1997)   u  High  performance  garbage  collectors,  na?ve   threading,  JMX  management  extensions   u  JDBC  libraries  very  mature  and  performant  for   SQL-­‐based  access   u  Puma  is  recommended  over  unicorn  for  JRuby    
  • 50. From  Sinatra  to  Padrino   u  Padrino  provides  Rails-­‐like  environment  for   Sinatra   u  Build  in  Sinatra,  move  to  Padrino  when   needed   u  Generators,  pluggable  modules,  admin   generator  
  • 51. Resources   u  Sinatra  Docs:     hCp://www.sinatrarb.com/intro.html     u  Introduc?on  to  Rack:   hCp://hawkins.io/2012/07/rack_from_the_beginning/     u  Sequel  Gem:   hCps://github.com/jeremyevans/sequel     u  Roar/Representable:   hCps://github.com/apotonick/roar     hCps://github.com/apotonick/representable    
  • 52. Thanks  Ya’ll   James  Higginbotham   james@launchany.com   hCp://launchany.com     @launchany     Design  Beau?ful  APIs:   hCp://TheApiDesignBook.com