Only has two types of resources:
- Collection
- Instance
- Create clean, short, simple uris.
http://www.foo.com/dev/service/rest/api/
vshttp://api.foo.com/
- Always use nouns and no verbs.
- Every resource should have a unique uri/url
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.
If PUT, PATCH, DELETE is not supported use a meta-property
POST /team/avengers?_method=DELETE
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.
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 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
Always include the href
path.
Use ISO-8601 (UTC-timecode)
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}
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"
}
}
For getting only a few properties of the resource
GET {URL}/{RESOURCE}/{ID}?fields={FIELDA},{FIELDB},{FIELDC}
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"
}
}
GET {URL}/{RESOURCE}
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"
}
]
}
Just an extra instance of a separated resource which links to other instances
GET {URL}/{RESOURCEMANYTOMANY}/{ID}
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"
}
}
Be descriptive as possible without giving away security.
Wrong: 'Your password didn't match username' Right: 'Authentication failed'
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"
}