Skip to content

Instantly share code, notes, and snippets.

@philharvey
Created September 22, 2012 17:14
Show Gist options
  • Save philharvey/3766847 to your computer and use it in GitHub Desktop.
Save philharvey/3766847 to your computer and use it in GitHub Desktop.
REST & Hypermedia - "RESTDesk" Examples - Ruby Hoedown 2012

RESTDesk: First version

Business use case:

  • Allow app users for our single iPhone app to report bugs/feature requests via a native, in app help desk UI.
  • Users can report issues for our development team to address.

Non-hypermedia version

POST http://api.restdesk.biz/tickets
Content-Type: application/json
{
  "title": "Feature request",
  "desc": "It would be really great if you could...",
  "user": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "jsmith@gmail.com"
  }
}
HTTP/1.1 201 Created
Content-Location: http://api.restdesk.biz/tickets/123
GET http://api.restdesk.biz/tickets/123
{
  "status": "open",
  "title": "Feature request",
  "desc": "It would be really great if you could...",
  "user": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "jsmith@gmail.com"
  }
}

Closing the ticket

POST http://api.restdesk.biz/tickets/123/status
Content-Type: application/json
{ "status": "closed" }

With Hypermedia

GET http://api.restdesk.biz/
{
  "links": {
    {
      "rel": "tickets",
      "href": "http://api.restdesk.biz/tickets/"
    }
  }
}
GET http://api.restdesk.biz/tickets/
{
  "links": {
    {
      "rel": "create_ticket",
      "href": "http://api.restdesk.biz/tickets/"
    }
  }
}
POST http://api.restdesk.biz/tickets/
Content-Type: application/vnd.restdesk.ticket+json
{
  "title": "Feature request",
  "desc": "It would be really great if you could...",
  "user": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "jsmith@gmail.com"
  }
}
HTTP/1.1 201 Created
Content-Location: http://api.restdesk.biz/tickets/123
GET http://api.restdesk.biz/tickets/123
{
  "links": {
    {
      "rel": "close_ticket",
      "href": "http://api.restdesk.biz/tickets/123/status"
    }
  }
  "status": "open",
  "title": "Feature request",
  "desc": "It would be really great if you could...",
  "user": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "jsmith@gmail.com"
  }
}

Closing the ticket

  • Step 1: Follow "close_ticket" link
  • Step 2:
POST http://api.restdesk.biz/tickets/123/status
Content-Type: application/vnd.restdesk.ticket.status+json
{ "status": "closed" }

RESTDesk: Second version (add support for multiple apps)

Business is booming. We build new apps, and the business wants to add the help desk feature to all of the news apps. This was not anticipated in the original design.

Non-hypermedia approach

POST http://api.restdesk.biz/apps/#{appname}/tickets
Content-Type: application/json
{
  "title": "Feature request",
  "desc": "It would be really great if you could...",
  "user": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "jsmith@gmail.com"
  }
}

(New Clients POST directly to http://api.restdesk.biz/apps/#{appname}/tickets/) (Old Clients still POST directly to http://api.restdesk.biz/tickets/. We have to sniff User Agent header for app name in order to "magicly" place their tickets under the correct app name resource)

HTTP/1.1 201 Created
Content-Location: http://api.restdesk.biz/apps/foo/tickets/123
GET http://api.restdesk.biz/apps/foo/tickets/123
{
  "status": "open",
  "title": "Feature request",
  "desc": "It would be really great if you could...",
  "user": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "jsmith@gmail.com"
  }
}

(Old Clients still using GET http://api.restdesk.biz/tickets/)

With Hypermedia

GET http://api.restdesk.biz/
{
  "links": {
    {
      "rel": "tickets",
      "href": "http://api.restdesk.biz/apps/foo/tickets/"
    }
  }
}
GET http://api.restdesk.biz/apps/foo/tickets/
{
  "links": {
    {
      "rel": "create_ticket",
      "href": "http://api.restdesk.biz/apps/foo/tickets/"
    }
  }
}
POST http://api.restdesk.biz/apps/foo/tickets/
Content-Type: application/vnd.restdesk.ticket+json
{
  "title": "Feature request",
  "desc": "It would be really great if you could...",
  "user": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "jsmith@gmail.com"
  }
}
HTTP/1.1 201 Created
Content-Location: http://api.restdesk.biz/apps/foo/tickets/123
GET http://api.restdesk.biz/apps/foo/tickets/123
{
  "links": {
    {
      "rel": "close_ticket",
      "href": "http://api.restdesk.biz/apps/foo/tickets/123/status"
    }
  }
  "status": "open",
  "title": "Feature request",
  "desc": "It would be really great if you could...",
  "user": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "jsmith@gmail.com"
  }
}

Closing a ticket

  • Step 1: Follow "close_ticket" link
  • Step 2:
POST http://api.restdesk.biz/apps/foo/tickets/123/status
Content-Type: application/vnd.restdesk.ticket.status+json
{ "status": "closed" }

RESTDesk: Third version

New use case:

  • Users cannot close tickets until they have been assigned to one of our developers

Non-hypermedia approach

GET http://api.restdesk.biz/apps/foo/tickets/123
{
  "assignee": null,
  "status": "open",
  "title": "Feature request",
  "desc": "It would be really great if you could...",
  "user": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "jsmith@gmail.com"
  }
}

Original Clients (the ones built against example one's non-hypermedia API version)

POST http://api.restdesk.biz/tickets/123/status
Content-Type: application/json
{ "status": "closed" }
HTTP/1.1 405 Method Not Allowed

New Clients

POST http://api.restdesk.biz/apps/foo/123/status
Content-Type: application/json
{ "status": "closed" }
HTTP/1.1 405 Method Not Allowed

With Hypermedia

GET http://api.restdesk.biz/apps/foo/tickets/123
{
  "links": {
    /* Machine Client: what, no close link? oh well, gray out the close button for now... */
  }
  "assignee": null,
  "status": "open",
  "title": "Feature request",
  "desc": "It would be really great if you could...",
  "user": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "jsmith@gmail.com"
  }
}

OK, now, we've assigned a developer to the ticket...

GET http://api.restdesk.biz/apps/foo/tickets/123
{
  "links": {
    { "rel": "close_ticket", "href": "http://api.restdesk.biz/apps/foo/tickets/123/status" }
  }
  "assignee": null,
  "status": "open",
  "title": "Feature request",
  "desc": "It would be really great if you could...",
  "user": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "jsmith@gmail.com"
  }
}

Now that it is available in the representation, you can follow the close_ticket link:

POST http://api.restdesk.biz/apps/foo/tickets/123/status
Content-Type: application/vnd.restdesk.ticket.status+json
{ "status": "closed" }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment