Enterprise Integration Zone is brought to you in partnership with:

My name is Konrad Garus and I solve problems for a living. I am crazy about quality of code and life, zealous learner and believer in constant refinement and improvement. I fight stubborn ignorance and “good enough” with passion. Personally I also am a husband, father, passionate reader and music fan. Konrad is a DZone MVB and is not an employee of DZone and has posted 28 posts at DZone. You can read more from them at their website. View Full User Profile

"Beautiful REST + JSON APIs" by Les Hazlewood

11.08.2013
| 17505 views |
  • submit to reddit

Here’s a summary of a few interesting technical details from a very good presentation on designing REST APIs by Les Hazlewood. Many interesting, elegant and not so obvious solutions here.

  • Keep resources coarse-grained, especially if you’re designing a public API and you don’t know the use cases.
  • Resources are either collections or single instances. They’re always an object, a noun. Don’t mix the URLs with behavior. /getAccount and /createDirectory can easily explode to /getAllAccounts, /searchAccounts, /createLdapDirectory…
  • Collection is at /accounts, instance at /accounts/a1b2c3. Create, read, update and delete with GET/POST/PUT/PATCH/DELETE… Everyone knows, but anyway.
  • Media types:
    • application/json – regular JSON.
    • application/foo+json – JSON of type foo. In my understanding, roughly corresponding to XML schema or DTD.
    • application/foo+json;application – JSON of type foo, where the response type (entity format?) is application.
    • application/json, text/plain – JSON prefered, text acceptable.
  • Versioning:
    • https://api.foo.com/v1
    • Media-Type application/json+foo;application&v=1
  • HREF:
    • Use instead of IDs
    • Sample use:
      GET /accounts/a11b223
      200 OK
      {
        "href": "https://api.foo.com/v1/accounts/a11b223",
        "givenName": "Tony",
        "surname": "Stark",
        "directory": {
          // Instance reference
          "href": "https://api.foo.com/v1/directories/ffb554"
        },
        "groups": {
          // Collection reference
          "href": "https://api.foo.com/v1/accounts/a11b223/groups"
        }
      }
      
    • Reference (link) expansion:
      GET /accounts/a11b223?expand=directory
      {
        "href": "https://api.foo.com/v1/accounts/a11b223",
        "givenName": "Tony",
        "surname": "Stark",
        "directory": {
          "href": "https://api.foo.com/v1/directories/ffb554",
          "name": "Avengers",
          "creationDate": "2013-08-08T14:55:12Z"
        }  
      }
      
    • Partial representations:
      GET /accounts/a11b223?fields=givenName,surname,directory(name)
      
    • Pagination:
      GET .../applications?offset=50&limit=25
      {
        "href": ".../applications",
        "offset": 50,
        "limit": 25,
        "first": { 
          "href": ".../applications?offset=0"
        },
        "prev": {
          "href": ".../applications?offset=25"
        },
        "items": [
          {"href": "..."},
          {"href": "..."}
        ]
      
  • Many-to-many – represent as another, special resource, e.g. /groupMembership. Not so obvious potential benefits: If you make it a resource, it’s easy to reference from either end of the association. If you want, you can easily add data to the association (e.g. creation date, responsible user, whatever).
  • Error handling – credit to Twilio.
    POST /directories
    409 Conflict
    {
      "status": 409,
      "code": 40924, // because HTTP has too few codes
      "property": "name",
      // Ready-to-use user-friendly message:
      "message": "A directory named Avengers already exists",
      // Dev-friendly message, can be stacktrace etc.
      "developerMessage": "A directory named Avengers already 
        exists. If you have a stale local cache, please expire
        it now.",
      "moreInfo": "http://foo.com/docs/api/errors/40924"
    }
    
  • Security – many interesting points here, but one particularly valuable. Authorize on content, not URL. URLs can change and may diverge from security configuration…

It’s too bad that the presenter doesn’t really leave the happy CRUD path. I’d really like to hear his recommendation or examples on more action-oriented use cases (validate or reset user password, approve order, what have we).

The entire presentation is a bit longer than that. I talks quite a lot about why you would want to use REST and JSON, as well as security, caching and other issues.

Published at DZone with permission of Konrad Garus, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Shreyas Dube replied on Wed, 2013/11/13 - 11:53am

Nice recap.

I've started using Hypertext Application Language (HAL) to enrich the simple "href"s in the resource representation. This enables you to implement HATEOAS quite elegantly.

I'd like to see recommendations and examples on action-oriented use cases as well.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.