Implementing a
RESTful API w/Ruby
“The Right Way”
Wednesday, September 21, 2011
Slide 2
Slide 2 text
metrics.librato.com
Increase service flexibility/utility
Free users’ data
Build business value
Why APIs?
Wednesday, September 21, 2011
Slide 3
Slide 3 text
metrics.librato.com
Consumes arbitrary time series data
Store it, visualize it, analyze it
Query it back out from API
Rich client interface
Librato Metrics
Wednesday, September 21, 2011
Slide 4
Slide 4 text
metrics.librato.com
Wednesday, September 21, 2011
Slide 5
Slide 5 text
metrics.librato.com
Requirements
Easy to implement and maintain
Performant and scalable
Easy to understand and use
Wednesday, September 21, 2011
Slide 6
Slide 6 text
metrics.librato.com
What is REST?
Wednesday, September 21, 2011
metrics.librato.com
L3 - REST
REpresentational
State Transfer
HATEOAS
Hypermedia
Constraint
Wednesday, September 21, 2011
Slide 10
Slide 10 text
metrics.librato.com
“[hypertext constraint is] most often
violated within so-called REST APIs ... adhere
to them or choose some other buzzword
for your API.”
- Roy Fielding
Wednesday, September 21, 2011
Slide 11
Slide 11 text
metrics.librato.com
CRUD API
Resources identified/addressed by URI
URI Templates
HTTP-based interactions
Wednesday, September 21, 2011
Slide 12
Slide 12 text
metrics.librato.com
Resources
Anything we expose to the Web
Resources have representations
JSON,XML,PNG
Services exchange representations
Wednesday, September 21, 2011
Slide 13
Slide 13 text
metrics.librato.com
URIs
Uniform Resource Identifier
Uniquely identifies a web resource
Makes it addressable
http://example.org/resource/123
Wednesday, September 21, 2011
Slide 14
Slide 14 text
metrics.librato.com
API Design Constraints
JSON output
JSON and x-form-urlencoded input
Basic HTTP Authentication over SSL
Wednesday, September 21, 2011
Slide 15
Slide 15 text
metrics.librato.com
Doc. Driven Design
URI template
Markdown file per-resource
URI, parameters, examples
Production ready before a single LOC!
Wednesday, September 21, 2011
Slide 16
Slide 16 text
metrics.librato.com
Wednesday, September 21, 2011
Slide 17
Slide 17 text
metrics.librato.com
Test Driven Dev.
Simulate requests against the API
Assert expectations about the response
test-unit + rack-test
Wednesday, September 21, 2011
Slide 18
Slide 18 text
metrics.librato.com
Test Driven Dev.
def test_create_gauge
params = {}
params[:name] = "my_gauge"
post "/gauges", params
assert_equal 201, last_response.status
assert last_response.original_headers["Location"] =~
/^\/v1\/gauges\/#{params[:name]}$/
end
Wednesday, September 21, 2011
Slide 19
Slide 19 text
metrics.librato.com
Wednesday, September 21, 2011
Slide 20
Slide 20 text
metrics.librato.com
Create Resource
POST /resource
Location:
201 - Created
def test_create
create_resource(
:name => "some_gauge",
:period => 60
)
create_resource(
:code => 400,
:name => "a" * 256
)
end
Wednesday, September 21, 2011
Slide 21
Slide 21 text
metrics.librato.com
Read Resource
GET /resource/:id
200 OK
def test_read
name = "my_gauge"
gauge =
read_resource(:id => name)
assert_equal(name,
gauge['name'])
end
Wednesday, September 21, 2011
Slide 22
Slide 22 text
metrics.librato.com
Update Resource
PUT /resource/:id
204 - No Content
def test_update
name = "my_gauge"
update_resource(:name => name,
:period => 300)
end
Wednesday, September 21, 2011
Slide 23
Slide 23 text
metrics.librato.com
Delete Resource
DELETE /resource/:id
204 No Content
def test_delete
name = "my_gauge"
delete_resource(:id => name)
read_resource(:code => 404,
:id => name)
end
Wednesday, September 21, 2011
Slide 24
Slide 24 text
metrics.librato.com
Implementation
Wednesday, September 21, 2011
Slide 25
Slide 25 text
metrics.librato.com
Implementation
CRUD API is a thin layer over your models
Sinatra + Sequel
Resource per file
to_hash method per-model
Wednesday, September 21, 2011
Slide 26
Slide 26 text
metrics.librato.com
Implementation
# CREATE
post "/gauges" do
unless params[:name]
abort_params({:name => ["Must specify gauge name"]})
end
if find_gauge(params[:name])
abort_unique({:name => ["Gauge name must be unique"]})
end
gauge = create_gauge()
halt_created("/gauges/#{gauge.name}")
end
Wednesday, September 21, 2011
Slide 27
Slide 27 text
metrics.librato.com
Wednesday, September 21, 2011
Slide 28
Slide 28 text
metrics.librato.com
Pagination Request
offset - starting index into found
length - # of resources requested
orderby - attribute to sort on
sort - ASC/DESC
Wednesday, September 21, 2011
Slide 29
Slide 29 text
metrics.librato.com
Pagination Response
total - # of resources
found - # of resources that match the query
offset - starting index into found
length - # of resources in response
Wednesday, September 21, 2011
Slide 30
Slide 30 text
metrics.librato.com
Authentication
Secure access through SSL/TLS
Block port 80 if possible
403 all HTTP requests otherwise
Basic Authentication
Wednesday, September 21, 2011
Slide 31
Slide 31 text
metrics.librato.com
API Versioning
URI templates are static
Prefer to maintain compatibility
Failing that prefer to version your entire API
URI? Media Type? Custom Header?
Wednesday, September 21, 2011
Slide 32
Slide 32 text
metrics.librato.com
URI
http://v1.example.org/resource/123
http://example.org/v1/resource/123
http://example.org/resource/123 ?v=1
Wednesday, September 21, 2011
Slide 33
Slide 33 text
metrics.librato.com
Media Type
Negotiate through Accept header
application/json;version=1
Wednesday, September 21, 2011
Slide 34
Slide 34 text
metrics.librato.com
Custom HTTP Header
X-Api-Version: 1
May not work with legacy clients
Don’t do this!
Wednesday, September 21, 2011
metrics.librato.com
HATEOAS
CRUD is great except when it isn’t
Hypermedia models state transitions
Inclusion of links in representation
Wednesday, September 21, 2011
Slide 37
Slide 37 text
metrics.librato.com
Hypermedia Formats
XHTML, ATOM, RSS
Domain-specific formats!
Add link elements to CRUD format
Wednesday, September 21, 2011
metrics.librato.com
Link Elements
uri attribute describes resource
rel attribute contains semantic markup
link elements can be added/removed from
representations
Wednesday, September 21, 2011
Slide 41
Slide 41 text
metrics.librato.com
GLory of REST
Single bookmarked URI
Next states are discovered inline
Series of representation exchanges transforms
application state
Wednesday, September 21, 2011
Slide 42
Slide 42 text
metrics.librato.com
Have an API and build it first
At least use CRUD
Docs -> Tests -> Code
Make it DRY
Dogfood It
Learn more about REST
Wednesday, September 21, 2011
Slide 43
Slide 43 text
metrics.librato.com
Wednesday, September 21, 2011
Slide 44
Slide 44 text
metrics.librato.com
Wednesday, September 21, 2011
Slide 45
Slide 45 text
metrics.librato.com
Wednesday, September 21, 2011
Slide 46
Slide 46 text
metrics.librato.com
“be conservative in what you do, be liberal
in what you accept from others”
- Postel’s Law
Wednesday, September 21, 2011
Slide 47
Slide 47 text
metrics.librato.com
Q&A
Wednesday, September 21, 2011