Skip to content

Instantly share code, notes, and snippets.

@Krettis
Last active August 29, 2015 14:16
Show Gist options
  • Save Krettis/79f5233cea5f76f14643 to your computer and use it in GitHub Desktop.
Save Krettis/79f5233cea5f76f14643 to your computer and use it in GitHub Desktop.
REST-api convention

Represential State Transfer - api

Only has two types of resources:

  • Collection
  • Instance

URLS

  • Create clean, short, simple uris. http://www.foo.com/dev/service/rest/api/ vs http://api.foo.com/
  • Always use nouns and no verbs.
  • Every resource should have a unique uri/url

Methods

These methods are (or at least should be) allowed: POST, GET, PUT, PATCH, DELETE CRUD is not one on one on POST, GET, PUT, DELETE. You can use PUT to create instances and POST to update instances.

HTTP Method overrides

If PUT, PATCH, DELETE is not supported use a meta-property

POST /team/avengers?_method=DELETE

Media-types & Header requests

Use standard mediatypes but actually in most cases your media-type is not standard although it is good to start with.

Start with a normal header contenttype

Content-type: application/json

In the end each resource is an own media-type so this would be eventually more appropiate

Content-type: application/foo+json

And eventually mention the resource

Content-type: application/foo+json;accounts

Use camelcase.

Acceptance of content

Mention it in the headers

Accept: application/json, text/plain

Order of accept determines preference.
Or mention it in the uri, this always overrides

{URL}/{RESOURCE}/{ID}.json
{URL}/{RESOURCE}/{ID}.csv

Versioning

Versioning is only allowed in integers. Best way to mention this up to date would be ;

`http://api.foo.com/v1`

Also can be specified in the header but takes more effort

Content-type: application/json;v=1 

Json output

Properties

Always include the href path.

Timestamp

Use ISO-8601 (UTC-timecode)

Instance expansion

When trying to not only get some data from the instance but the directory or other resources it is linked to, you can use expand

{URL}/{RESOURCE}/{ID}?expand={EXPAND}

JSON Example

GET http://api.foo.com/v1/accounts/tony?expand=team

returns

{
    "href" : "http://api.foo.com/v1/accounts/tony",
    "account" : "tony",
    "surName" : "Stark",
    "givenName : "Tony",
    "fullName" : "Tony Stark",
    "power" : "robot suit",
    "doesPowerFly" : "true",
    "doesPowerKill" : "true",
    "useSpandex" : "false",
    "isIdentityExposed" : "true,
    "creationDate" : "2014-09-23T00:59:26.92Z", 
    "updateDate" : "2014-09-23T00:59:26.92Z"
    
    "team" : {
        "href" : "http://api.foo.com/v1/teams/avengers",
        "name" : "Avengers",
        "creationDate" : "2014-09-23T00:59:26.92Z", 
        "updateDate" : "2014-09-23T00:59:26.92Z"
    }
}

Instance contraction

For getting only a few properties of the resource GET {URL}/{RESOURCE}/{ID}?fields={FIELDA},{FIELDB},{FIELDC}

JSON Example

GET http://api.foo.com/v1/accounts/tony?fields=account,power,use-spandex,team(name)

This will return

{
    "href" : "http://api.foo.com/v1/accounts/tony",
    "account" : "tony",
    "power" : "robot suit",
    "useSpandex" : "false",
    
    "team" : {
        "href" : "http://api.foo.com/v1/teams/avengers",
        "name" : "Avengers"
    }
}

Collection

GET {URL}/{RESOURCE}

JSON Example

GET http://api.foo.com/v1/accounts/

Will return a default set of items

{
  "href": "http://api.foo.com/v1/accounts/"
  "offset": 0,
  "limit": 10,
  "size" : 241,
  "first" :  "http://api.foo.com/v1/accounts?offset=0&limit=10",
  "last" : "http://api.foo.com/v1/accounts?offset=240&limit=10",
  "next" :  "http://api.foo.com/v1/accounts?offset=10&limit=10",
  "prev" : null,
  
  "items" : [
    {
      "ID" : "abeil"
      "href" : "http://api.foo.com/v1/accounts/abeil"
    },
    ...,
    {
      "ID" : "tony"
      "href" : "http://api.foo.com/v1/accounts/tony"
    }
  ]
}

Many to Many

Just an extra instance of a separated resource which links to other instances GET {URL}/{RESOURCEMANYTOMANY}/{ID}

JSON Example

GET http://api.foo.com/v1/superteamships/129e

Returns

{
    "href" : "http://api.foo.com/v1/superteamships/129e",
    "account" : {
        "href" : "http://api.foo.com/v1/accounts/tony"
    },
    "team" : {
        "href" : "http://api.foo.com/v1/teams/avengers"
    }

}

Handling Errors

Be descriptive as possible without giving away security.

Wrong: 'Your password didn't match username' Right: 'Authentication failed'

JSON Example

POST /team

Can return

409 conflict
{
    "status" : 409,
    "code" : 40912,
    "property" : "name",
    "message" : "A team named `Avengers` already exists.",
    "devMessage" : "A team named `Avengers` already exists. If you have a stale cache, please expire it now.",
    "moreInfo" : "http://www.foo.com/docs/api/errors/40912"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment