Joost Cassee
joost@cassee.net
@jcassee
jcassee.com
Dutch API Community Meetup #2
8 June 2016
Painless Software
GET /page2 HTTP/1.1 Host: example.com Referer: http://example.com/page1
Internal code
External code
APIs
Oh crap!
Shiny!
Oops!
SalesForce
Twilio
GitHub
Azure
/services/data/v20.0/sobjects/Account
/2010-04-01/Account/
/me?v=1.0 → /v2.0/me
Accept: application/vnd.github.v3+json
X-MS-Version: 2015-04-05
URI
http://example.com/ship/9334026
"An entity"
{
"name": "VOS PROMINENCE",
"imo": 9334026,
"type": "supply"
}
Media Type
application/json
Profile
http://example.com/profiles/ship
"It is a ship"
The resource identified by http://example.com/ship/9334026
{
"name": "VOS PROMINENCE",
"imo": 9334026,
"type": "cargo"
}
and is represented as application/json by
has profile http://example.com/profiles/ship
A resource identified by a http/https URL
can be manipulated using HTTP methods
GET
PUT
DELETE
PATCH
POST
Retreive a representation
Store a representation
Delete a resource
Update a resource
"Process" a representation
Model business logic as state manipulation
href
http://example.com/company/3342
"That entity over there"
{
"name": "VOS PROMINENCE",
"imo": 9334026,
"type": "supply",
"ownerHref": "http://example.com/company/3342"
}
"That is the owner"
(semantics described by the profile)
Relation
http://example.com/relations/owner
"The entity has an owner"
The resource identified by http://example.com/ship/9334026
to the resource identified by http://example.com/company/3342
has relation http://example.com/relations/owner
(Looks a bit like an RDF triple)
Hypermedia Application Language
application/hal+json
{
"name": "VOS PROMINENCE",
"imo": 9334026,
"type": "supply",
...
{
"name": "VOS PROMINENCE",
"imo": 9334026,
"type": "supply",
"_links": {
"self": {
"href": "http://example.com/ship/9334026"
},
"profile": {
"href": "http://example.com/profiles/ship"
},
"http://example.com/relations/owner": {
"href": "http://example.com/company/3342"
}
},
...
{
...
"_embedded": {
"http://example.com/relations/owner": {
"name": "Vroon B.V.",
"_links": {
"self": {
"href": "http://example.com/company/3342"
},
"profile": {
"href": "http://example.com/profiles/company"
}
}
}
}
}
Hypertext As The Engine Of Application State
"Use links to traverse the API"
One or more media types
A set of relations
A set of profiles
The URI of the root resource
It's a protocol!
know about media types, profiles, relations and root URI
treat URIs as opaque
let links drive interactions
{
"name": "VOS PROMINENCE",
"imo": 9334026,
"type": "supply"
}
{
"name": "VOS PROMINENCE",
"imo": 9334026,
"type": "supply",
"flag": "nl"
}
Missing properties are set to the previous value
or
the default value
Removing or changing the meaning of properties
is not allowed
GET
application/hal+json
1.
{
"name": "VOS PROMINENCE",
"imo": 9334026,
"type": "supply",
"_links": {
"self": {
"href": "..."
},
...
}
application/json
PUT
Links can be added and removed
2.
{
"name": "VOS PROMINENCE",
"_links": {
"owner": {
"href": "..."
},
"prev-owner": {
"href": "..."
}
}
{
"name": "VOS PROMINENCE",
"_links": {
"owner": {
"href": "..."
},
"builder" {
"href": "..."
}
}
Part of resource state
Defined by profile
Mutable by client
Removal is backward-incompatible
Part of API wiring
Defined by relation
Not mutable by client
Can be removed
{
"_links": {
"rel": { "href": "uri" }
}
}
{
"property": "uri"
}
On the client, log the use of deprecated relations
{
"name": "VOS PROMINENCE",
"_links": {
"http://example.com/relations/prev-owner": {
"href": "http://example.com/company/177",
"deprecation": "http://example.com/docs/deprecated/prev-owner.html"
}
}
{
"name": "VOS PROMINENCE",
"imo": 9334026,
"_links": {
"self": {
"href": "..."
},
"owner": {
"href": "..."
}
}
{
"name": "VOS PROMINENCE",
"imo": 9334026,
"flag": "nl",
"_links": {
"self": {
"href": "..."
},
"owner": {
"href": "..."
},
"builder": {
"href": "..."
}
}
{
"_links": {
"http://example.com/relations/owner": {
"href": "http://example.com/company/3342"
}
}
{
"_links": {
"http://example.com/relations/owner": {
"href": "http://companies.example.com/3342"
}
}
{
"_links" : {
"http://example.com/relations/owner" : {
"href" : "http://example.com/company/3342",
"deprecation": "http://example.com/docs/deprecated/owner.html"
},
"http://example.com/relations/ownership" : {
"href" : "http://example.com/ship/9334026/ownership/3"
}
}
}
Feature:
Scenario:
Getting information about companies that own ships
Get a ship's owner
Given
And
When
And
Then
a company named "Joost Shipping"
ship named "Providence" owned by "Joost Shipping"
you get the ship "Providence"
you follow the relation "ship-owner"
the response contains
{
"name": "Joost Shipping"
}
joost@cassee.net
@jcassee
jcassee.com
Slides can be found at
Check out the example project at
https://github.com/jcassee/registronavale