Slide 1

Slide 1 text

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

Slide 7

Slide 7 text

metrics.librato.com Wednesday, September 21, 2011

Slide 8

Slide 8 text

metrics.librato.com L2 - CRUD URIs HTTP Methods Wednesday, September 21, 2011

Slide 9

Slide 9 text

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

Slide 35

Slide 35 text

metrics.librato.com Partial Updates PATCH - RFC5789 PATCH /resource/:id Wednesday, September 21, 2011

Slide 36

Slide 36 text

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

Slide 38

Slide 38 text

metrics.librato.com CRUD Pagination { "query":{ "total":128, "found":128, "offset":0, "length":100 }, "gauges":[ { "name":"gauge1" }, { "name":"gauge2" }, ... ] } Wednesday, September 21, 2011

Slide 39

Slide 39 text

metrics.librato.com REST Pagination { "next":{ "uri":"http://api.librato.com/gauges?offset=100”, "rel":"http://relations.librato.com/paginate", "media_type":"application/vnd.librato+json" }, "gauges":[ { "name":"gauge1" }, { "name":"gauge2" }, ... ] } Wednesday, September 21, 2011

Slide 40

Slide 40 text

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