Get a JSON instance
GET https://example.com/book/12345
200 OK
Content-Type: application/json
Link: <https://example.com/schemas/book>; rel="describedby"
{
"title": "Mobby-Dick",
"authorId": 100,
...
}
Get the schema that describes the instance using the "describedby" Link header.
GET https://example.com/schemas/book
200 OK
Content-Type: application/schema+json
{
"links": [
{
"href": "/author/{authorId}",
"rel": "author",
"templateRequired": ["authorId"]
}
]
}
Use the LDO combined with the instance to construct a link to get information about the author.
GET https://example.com/author/100
200 OK
Content-Type: application/json
Link: <https://example.com/schemas/author>; rel="describedby"
{
"name": "Herman Melville",
...
}
Keep following links to discover more content.
Using a link to construct a URI from user input. (Analogous to <form method="get">
)
{
"links": [
{
"href": "/books{?title}{?author}"
"rel": "search",
"hrefSchema": {
"properties": {
"title": { "type": "string" },
"author": { "type": "integer" },
...
}
}
}
]
}
GET https://example.com/books?title=Moby-Dick
200 OK
Content-Type: application/json
Link: <https://example.com/schemas/books>; rel="describedby"
[
{
"title": "Mobby-Dick",
"authorId": 100,
...
}
]
Using a link to submit user input. (Analogous to <form method="post">
)
{
"links": [
{
"href": "/books"
"rel": "collection",
"submissionSchema": {
"type": "object",
"properties": {
"title": { "type": "string" },
"authorId": { "type": "integer" },
...
},
"required": ["title", "authorId", ...]
}
}
]
}
POST https://example.com/books
Content-Type: application/json
{
"title": "Moby-Dick",
"authorId": 100,
...
}
204 No Content
You can also make submission will media types other than JSON.
{
"links": [
{
"href": "/books"
"rel": "collection",
"submissionMediaType": "application/xml",
"submissionSchema": {
"type": "object",
"properties": {
"title": { "type": "string" },
"authorId": { "type": "integer" },
...
},
"required": ["title", "authorId", ...]
}
}
]
}
POST https://example.com/books
Content-Type: application/xml
<Book>
<title>Moby-Dick<title>
<authorId>100</authorId>
...
</Book>
204 No Content
{
"links": [
{
"href": "https://example.com/authors/100",
"rel": "author"
}
]
}
{
"links": [
{
"href": "https://example.com/review/6789",
"rel": "https://example.com/relations/review"
}
]
}
{
"links": [
{
"href": "https://example.com/reviews",
"rel": ["collection", "https://example.com/relations/reviews"]
}
]
}
A base URI is used to resolve relative URIs.
By default, the base URI for relative URIs in LDOs is the URI used to retrieve the resource
GET https://example.com/books/1
{
"links": [
{
"href": "/author/1",
"rel": "author"
}
]
}
Link Target: https://example.com/author/1
base
can be used to alter the base URI. It is a URI Template and can be relative.
GET https://example.com/myapi/v3/books/1
{
"base": "/myapi/v3/",
"links": [
{
"href": "author/1",
"rel": "author"
}
]
}
Link Target: https://example.com/myapi/v3/author/1
A link is a connection between two resources. The source of the link is called the "anchor" and the destination is called the "target. The "anchor" usually doesn't need to be specified because it's understood to be the resource the link appears in. anchor
allows you to change the link's "anchor" to something other than the resource it appears in.
When anchor
appears in an LDO, it becomes the base URI for resolving href
.
(NOTE: I don't have an example because I can't think of any reason someone would want to do this. It's an anti-pattern at best. It might be best to just leave anchor
and anchorPointer
undocumented.)
href
, base
, and anchor
are URI Templates.
{
"type": "object",
"properties": {
"documentation": {
"links": [
{
"href": "/docs",
"rel": "about"
}
]
}
}
}
{
}
about: N/A
Note: Links are annotations, which means they're attached to a location in the JSON instance. If the location of the link doesn't exist in the JSON instance, the link doesn't apply.
{
"documentation": true
}
about: https://example.com/docs
{
"links": [
{
"href": "/books?page={next}{&perPage}",
"rel": "next",
"templateRequired": ["next"]
},
{
"href": "/books?page={previous}{&perPage}",
"rel": "previous",
"templateRequired": ["previous"]
}
]
}
{
"list": [
{ ... book 1 ... },
{ ... book 2 ... },
{ ... book 3 ... }
],
"page": 0,
"next": 1
}
next: https://example.com/books?page=1
previous: N/A
Note: previous
doesn't apply because the required property "previous" is not present.
Note: perPage
is an optional variable. The next
link still applies even though there is no "perPage" property.
{
"list": [
{ ... book 1 ... },
{ ... book 2 ... }
],
"metaData": {
"page": 0,
"next": 1,
"perPage": 2
}
}
next: https://example.com/books?page=1&perPage=2
previous: N/A
Note: Optional variable perPage
is present and included in the link.
{
"links": [
{
"href": "/{a}",
"rel": "https://example.com/relations/a"
}
]
}
{ "a": true }
https://example.com/relations/a
: https://example.com/true
{ "a": false }
https://example.com/relations/a
: https://example.com/false
{ "a": null }
https://example.com/relations/a
: https://example.com/null
{ "a": 42 }
https://example.com/relations/a
: https://example.com/42
Expand a variable from a different object.
{
"type": "object",
"properties": {
"cartItems": {
"type": "array",
"items": {
"links": [
{
"href": "cart-item/{cartId}/{cartItemId}",
"rel": "https://example.com/relations/cart-item",
"templateRequired": ["cartId", "cartItemId"],
"templatePointer": {
"cartId": "/cartId"
}
}
]
}
}
}
}
{
"cartId": 100,
"cartItems": [
{
"cartItemId": 200,
...
}
],
...
}
https://example.com/relations/cart-item
: https://example.com/cart-item/100/200
Example using Relative JSON Pointer instead of JSON Pointer.
{
"type": "object",
"properties": {
"cartItems": {
"type": "array",
"items": {
"links": [
{
"href": "cart-item/{cartId}/{cartItemId}",
"rel": "https://example.com/relations/cart-item",
"templateRequired": ["cartId", "cartItemId"],
"templatePointer": {
"cartId": "2/cartId"
}
}
]
}
}
}
}
https://example.com/relations/cart-item
: https://example.com/cart-item/100/200
- PUT and DELETE
title
description
targetMediaType
targetSchema
targetHints
headerSchema
- Special case relations:
collection
/item
,root
,self
Change log: