Skip to content

Instantly share code, notes, and snippets.

@soofaloofa-zz
Last active October 14, 2023 07:23
Show Gist options
  • Save soofaloofa-zz/9350847 to your computer and use it in GitHub Desktop.
Save soofaloofa-zz/9350847 to your computer and use it in GitHub Desktop.
On choosing a hypermedia type for your API - HAL, JSON-LD, Collection+JSON, SIREN, Oh My!
A comparison of Collection+JSON, HAL, JSON-LD and SIREN media types.
Discussion at
http://sookocheff.com/posts/2014-03-11-on-choosing-a-hypermedia-format/
GET https://api.example.com/player/1234567890
{
"collection": {
"version": "1.0",
"href": "https://api.example.com/player",
"items": [
{
"href": "https://api.example.com/player/1234567890",
"data": [
{"name": "playerId", "value": "1234567890", "prompt": "Identifier"},
{"name": "name", "value": "Kevin Sookocheff", "prompt": "Full Name"},
{"name": "alternateName", "value": "soofaloofa", "prompt": "Alias"}
],
"links": [
{"rel": "image", "href": "https://api.example.com/player/1234567890/avatar.png", "prompt": "Avatar", "render": "image" },
{"rel": "friends", "href": "https://api.example.com/player/1234567890/friends", "prompt": "Friends" }
]
}
]
}
}
GET https://api.example.com/player/1234567890/friends
{
"collection":
{
"version": "1.0",
"href": "https://api.example.com/player/1234567890/friends",
"links": [
{"rel": "next", "href": "https://api.example.com/player/1234567890/friends?page=2"}
],
"items": [
{
"href": "https://api.example.com/player/1895638109",
"data": [
{"name": "playerId", "value": "1895638109", "prompt": "Identifier"},
{"name": "name", "value": "Sheldon Dong", "prompt": "Full Name"},
{"name": "alternateName", "value": "sdong", "prompt": "Alias"}
],
"links": [
{"rel": "image", "href": "https://api.example.com/player/1895638109/avatar.png", "prompt": "Avatar", "render": "image" },
{"rel": "friends", "href": "https://api.example.com/player/1895638109/friends", "prompt": "Friends" }
]
},
{
"href": "https://api.example.com/player/8371023509",
"data": [
{"name": "playerId", "value": "8371023509", "prompt": "Identifier"},
{"name": "name", "value": "Martin Liu", "prompt": "Full Name"},
{"name": "alternateName", "value": "mliu", "prompt": "Alias"}
],
"links": [
{"rel": "image", "href": "https://api.example.com/player/8371023509/avatar.png", "prompt": "Avatar", "render": "image" },
{"rel": "friends", "href": "https://api.example.com/player/8371023509/friends", "prompt": "Friends" }
]
}
],
"queries": [
{
"rel": "search", "href": "https://api.example.com/player/1234567890/friends/search", "prompt": "Search",
"data": [
{"name": "search", "value": ""}
]
}
],
"template": {
"data": [
{"name": "playerId", "value": "", "prompt": "Identifier" },
{"name": "name", "value": "", "prompt": "Full Name"},
{"name": "alternateName", "value": "", "prompt": "Alias"},
{"name": "image", "value": "", "prompt": "Avatar"}
]
}
}
}
GET https://api.example.com/player/1234567890
{
"_links": {
"self": { "href": "https://api.example.com/player/1234567890" },
"curies": [{ "name": "ex", "href": "https://api.example.com/docs/rels/{rel}", "templated": true }],
"ex:friends": { "href": "https://api.example.com/player/1234567890/friends" }
},
"playerId": "1234567890",
"name": "Kevin Sookocheff",
"alternateName": "soofaloofa",
"image": "https://api.example.com/player/1234567890/avatar.png"
}
GET https://api.example.com/player/1234567890/friends
{
"_links": {
"self": { "href": "https://api.example.com/player/1234567890/friends" },
"next": { "href": "https://api.example.com/player/1234567890/friends?page=2" }
},
"size": "2",
"_embedded": {
"player": [
{
"_links": {
"self": { "href": "https://api.example.com/player/1895638109" },
"friends": { "href": "https://api.example.com/player/1895638109/friends" }
},
"playerId": "1895638109",
"name": "Sheldon Dong",
"alternateName": "sdong",
"image": "https://api.example.com/player/1895638109/avatar.png"
},
{
"_links": {
"self": { "href": "https://api.example.com/player/8371023509" },
"friends": { "href": "https://api.example.com/player/8371023509/friends" }
},
"playerId": "8371023509",
"name": "Martin Liu",
"alternateName": "mliu",
"image": "https://api.example.com/player/8371023509/avatar.png"
}
]
}
}
GET https://api.example.com/player/1234567890
{
"@context": {
"@vocab": "https://schema.org/",
"image": { "@type": "@id" },
"friends": { "@type": "@id" }
},
"@id": "https://api.example.com/player/1234567890",
"playerId": "1234567890",
"name": "Kevin Sookocheff",
"alternateName": "soofaloofa",
"image": "https://api.example.com/player/1234567890/avatar.png",
"friends": "https://api.example.com/player/1234567890/friends"
}
GET https://api.example.com/player/1234567890/friends
{
"@context": [
"http://www.w3.org/ns/hydra/core",
{
"@vocab": "https://schema.org/",
"image": { "@type": "@id" },
"friends": { "@type": "@id" }
}
],
"@id": "https://api.example.com/player/1234567890/friends",
"operation": {
"@type": "BefriendAction",
"method": "POST",
"expects": {
"@id": "http://schema.org/Person",
"supportedProperty": [
{ "property": "name", "range": "Text" },
{ "property": "alternateName", "range": "Text" },
{ "property": "image", "range": "URL" }
]
}
},
"member": [
{
"@id": "https://api.example.com/player/1895638109",
"name": "Sheldon Dong",
"alternateName": "sdong",
"image": "https://api.example.com/player/1895638109/avatar.png",
"friends": "https://api.example.com/player/1895638109/friends"
},
{
"@id": "https://api.example.com/player/8371023509",
"name": "Martin Liu",
"alternateName": "mliu",
"image": "https://api.example.com/player/8371023509/avatar.png",
"friends": "https://api.example.com/player/8371023509/friends"
}
],
"nextPage": "https://api.example.com/player/1234567890/friends?page=2"
}
GET https://api.example.com/player/1234567890
{
"class": "player",
"links": [
{ "rel": [ "self" ], "href": "https://api.example.com/player/1234567890" },
{ "rel": [ "friends" ], "href": "https://api.example.com/player/1234567890/friends" }
],
"properties": {
"playerId": "1234567890",
"name": "Kevin Sookocheff",
"alternateName": "soofaloofa",
"image": "https://api.example.com/player/1234567890/avatar.png"
}
}
GET https://api.example.com/player/1234567890/friends
{
"class": "player",
"links": [
{"rel": [ "self" ], "href": "https://api.example.com/player/1234567890/friends"},
{"rel": [ "next" ], "href": "https://api.example.com/player/1234567890/friends?page=2"}
],
"actions": [{
"class": "add-friend",
"href": "https://api.example.com/player/1234567890/friends",
"method": "POST",
"fields": [
{"name": "name", "type": "string"},
{"name": "alternateName", "type": "string"},
{"name": "image", "type": "href"}
]
}],
"properties": {
"size": "2"
},
"entities": [
{
"links": [
{"rel": [ "self" ], "href": "https://api.example.com/player/1895638109"},
{"rel": [ "friends" ], "href": "https://api.example.com/player/1895638109/friends"}
],
"properties": {
"playerId": "1895638109",
"name": "Sheldon Dong",
"alternateName": "sdong",
"image": "https://api.example.com/player/1895638109/avatar.png"
}
},
{
"links": [
{"rel": [ "self" ], "href": "https://api.example.com/player/8371023509"},
{"rel": [ "friends" ], "href": "https://api.example.com/player/8371023509/friends" }
],
"properties": {
"playerId": "8371023509",
"name": "Martin Liu",
"alternateName": "mliu",
"image": "https://api.example.com/player/8371023509/avatar.png"
}
}
]
}
@lanthaler
Copy link

I've also added a JSON-LD + Hydra version of the Siren example: https://gist.github.com/lanthaler/9503927#file-json-ld-hydra

@franz-josef-kaiser
Copy link

@lanthaler You might want to edit this Gist and use the .json extension so there's a bit of code highlighting. Thanks for the great comparison!

@gtramontina
Copy link

Just wanted to share something that I put together some months ago: https://gtramontina.github.io/h-factors/
I built it because I wanted to visually compare the formats. Contributions are very welcome!

Cheers!

@geffgh
Copy link

geffgh commented May 10, 2023

Might want to update the

to point to this page?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment