Skip to content

Instantly share code, notes, and snippets.

@skalnik
Created February 14, 2012 23:42
Show Gist options
  • Save skalnik/1831703 to your computer and use it in GitHub Desktop.
Save skalnik/1831703 to your computer and use it in GitHub Desktop.

WTF is this REST thing?

  • REpresentational State Transfer
  • Introduced by Roy Fielding in 2000
  • Lets focus on APIs.
  • Lets talk about the Richardson Maturity Model

Credit: Martin Fowler

Level 0: The Swamp of Pox (Plain ol' XML)

  • You're using HTTP as an RPC (Remote procedure call)
  • It's a start

What meetings exist?

POST /meetingsList

HTTP/1.1 200 OK
<other headers>
[
  {
    'title'        : 'Meeting - Backbone.js',
    'date'         : '02-07-2012',
    'organization' : 'WIT',
    'id'           : 'meeting00'
  }
]

Cool, we need a new one

POST /createMeetingPlease
{
'title'        : 'Weekly Meeting - REST',
'date'         : '02-14-2012',
'organization' : 'WIT'
}

HTTP/1.1 200 OK
<other headers>
{
  'title'        : 'Meeting - REST',
  'date'         : '02-14-2012',
  'organization' : 'WIT',
  'id'           : 'meeting01'
}

And let me check in

POST /checkInToMeeting
{
  'name'      : 'Mike Skalnik',
  'meetingId' : 'meeting01'
}

HTTP/1.1 200 OK
<other headers>
{
  'name'      : 'Mike Skalnik',
  'meetingId' : 'meeting01',
  'id'        : 'checkin01'
}

Level 1: Resources

  • RESTful URIs.
  • Represent objects in your URIs

What meetings exist?

POST /meetings/list

HTTP/1.1 200 OK
<other headers>
[{
  'title'        : 'Meeting - Backbone.js',
  'date'         : '02-07-2012',
  'organization' : 'WIT',
  'id'           : 0
}]

Cool, we need a new one

POST /orgs/WIT/meetings/create
{
  'title' : 'Weekly Meeting - REST',
  'date'  : '02-14-2012'
}

HTTP/1.1 200 OK
<other headers>
{
  'title'        : 'Meeting - REST',
  'date'         : '02-14-2012',
  'organization' : 'WIT',
  id             : 1
}

And lets check in

POST /meetings/meeting01/checkins/create
{
  'name' : 'Mike Skalnik'
}

HTTP/1.1 200 OK
<other headers>
{
  'name' : 'Mike Skalnik',
  'id'   : 1
}

Level 2: HTTP Verbs

  • Use HTTP verbs on those resources
  • GET/POST/PUT/DELETE

What meetings exist?

GET /meetings

HTTP/1.1 200 OK
<other headers>
{
  'title'        : 'Meeting - Backbone.js',
  'date'         : '02-07-2012',
  'organization' : 'WIT',
  'id'           : 0
}

Cool, we need a new one

POST /orgs/WIT/meetings
{
  'title' : 'Weekly Meeting - RSET',
  'date'  : '02-14-2012'
}

HTTP/1.1 201 Created
<other headers>
{
  'title'        : 'Meeting - RSET',
  'date'         : '02-14-2012',
  'organization' : 'WIT',
  'id'           : 1
}

Oh no, I typo'd the title. Lets update it

PUT /meetings/1
{
  'title' : 'Meeting - REST'
}

HTTP/1.1 200 OK
<other headers>
{
  'title'        : 'Meeting - REST',
  'date'         : '02-14-2012',
  'organization' : 'WIT',
  'id'           : 1
}

Eh, lets just delete

DELETE /meetings/1

HTTP/1.1 200 OK
<other headers>

Level 3: Hypermedia Controls

Content Negotiation

I want JSON!

GET /meetings
Accept: application/json

HTTP/1.1 200 OK
Content-Type: application/json
[
  {
    'title' : 'Weekly Meeting - Backbone.js'
    'id'    : 0
  }
]

Actually, XML!

GET /meetings
Accept: application/xml

HTTP/1.1 200 OK
Content-Type: application/xml
<meetings>
  <meeting id="0">
    <title>Weekly Meeting - Backbone.js</title>
  </meeting>
</meetings>

Custom MIME Types

  • This is pretty damn cool. You can use custom MIME types to version our APIs
  • People normally start shoving versions in their URL, not so RESTful

API V1 in JSON:

GET /meetings
Accept: application/vnc.ccorgs-v1+json

V2 in JSON:

GET /meetings
Accept: application/vnc.ccorgs-v2+json

V1 in XML:

GET /meetings
Accept: application/vnc.ccorgs-v1+xml

Hypertext As The Engine Of Application State - HATEOAS

  • My interest recently
  • APIs serve links, like the links you click on
  • REST is all about state. Your web app is a state machine!
  • Hypertext being XML, but you can do this with the HTTP Link header for non-hypertext.

Tell me about the first meeting

GET /meetings/0
Accept: application/json

HTTP/1.1 200 OK
Content-Type: application/json
Link: </meetings>; rel="up", </meetings/0/checkins>; rel="checkins", \
</meetings?page=2>; rel="next", </meetings?page=100>; rel="last"
<other headers>
  [
    {
      'title'        : 'Meeting - Backbone.js',
      'date'         : '02-07-2012',
      'organization' : 'WIT',
      'id'           : 0
    }
  ]

Cool, lets make a new meeting

POST /meetings
{
  'title' : 'Weekly Meeting - REST',
  'date'  : '02-14-2012'
}

HTTP/1.1 201 Created
Content-Type: application/json
Location: /meetings/1
Link: </meetings/1/checkins>; rel="checkins"
<other headers>
{
  'title'        : 'Meeting - RSET',
  'date'         : '02-14-2012',
  'organization' : 'WIT',
  'id'           : 1
}

Lets check if anyone has checked in yet. I'll just follow that link.

GET /meetings/1/checkins

HTTP/1.1 200 OK
Link: </meetings/1>; rel="up"
<other headers>
[
  {
    'name'      : 'Mike Skalnik',
    'timestamp' : '1329262247'
  },
  {
    'name'      : 'Ankit Shankar'
    'timestamp' : '1329262534'
  }
]

http://blog.kevburnsjr.com/self-descriptive-hypermedia-in-riak is cool. I can't wait for http://getsomere.st/

@skalnik
Copy link
Author

skalnik commented Feb 22, 2012

Level 3 has two parts, content negotiation and HATEOAS. HATEOAS is can be tricky to implement if content negotiation hasn't been done and you want to support multiple content types :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment