This document outlines best practices for Siren API servers and clients. It does not intend to alter or usurp the original specification.
- Specify Entity's Type
- Prefer Primitive Properties
- Follow Relation Type Standards
- Provide Type Hint to Entity Links
- Distinguish Links to Non-Siren Resources
- Include
self
Links - Link to API Documentation
- Resolve Relative URIs
- Appendix A: API Documentation
As the server, include one or more type identifiers in the entity class
array. A type identifier indicates which set of properties
, action name
s, and link and sub-entity relation types (rel
) might be present in the entity.
Type identifiers can be anything from a simple string to a fully-qualified class name (e.g., order
, com.example.Order
). Be consistent in type identifier naming conventions, and document them.
{
"class": ["Person"],
"links": [
{
"rel": ["profile"],
"href": "https://schema.org/Person"
},
{
"rel": ["https://schema.org/knows"],
"href": "https://example.com/hermione",
"class": ["Person"]
}
],
"properties": {
"givenName": "Neville",
"familyName": "Longbottom",
"birthDate": "1980-07-30"
}
}
Prefer primitives (string, number, boolean, or null) or arrays of primitives as the values of an entity's properties
object. An object or object array property value is typically a sign that another entity/resource is more appropriate and should be hyperlinked in the context entity.
Links' and embedded links' relation types conform to Section 3.3 of RFC 8288, which obsoletes the RFC mentioned in the spec. Thus rel
values are either a name from the IANA link relations registry, a name in your API documentation, or an absolute URI. When using the latter, use a URL that points to documentation describing the link relation type.
{
"links": [
{
"rel": ["self"],
"href": "/orders/69"
},
{
"rel": ["https://schema.org/customer"],
"href": "/people/42"
}
],
"entities": [
{
"rel": ["https://api.example.com/about#order-items"],
"href": "/orders/69/items"
}
]
}
When a link or embedded link reference another Siren entity, match the link's class
property with the target entity's class
property.
{
"rel": ["author"],
"href": "/people/42",
"class": ["Person"]
}
GET /people/42 HTTP/1.1
Host: api.example.com
HTTP/1.1 200 OK
Content-Type: application/vnd.siren+json
{
"class": ["Person"],
"links": [
{ "rel": ["self"], "href": "/people/42" }
]
}
When a link points to a non-Siren resource, specify the target's default media type in the type
property.
{
"rel": ["icon"],
"href": "https://api.example.com/images/icon",
"type": "image/png"
}
Note that
type
is only a hint; for example, it does not override theContent-Type
header field of a HTTP response obtained by actually following the link. [RFC 8288, Section 3.4.1]
Include a self
link for every entity. An entity represents a resource, which is identified by a URL, and therefore has a self
link.
{
"rel": ["self"],
"href": "/orders/21"
}
Include a profile
link [RFC6906] for every entity. The link points to relevant documentation describing the semantics of the resource.
{
"rel": ["profile"],
"href": "https://api.example.com/about#Person",
"type": "application/xhtml+xml"
}
When a link's or embedded link's href
is a relative URI, resolve the reference by establishing a base URI as follows:
- Base URI Embedded in Content. This is the context entity's
self
link'shref
. - Base URI from the Encapsulating Entity. If the context entity has no
self
link with an absolute URI and it is a sub-entity, then traverse the entity graph up from the context, searching for aself
link with an absolute URI at each level, and stopping when one is found or the graph is exhausted. Thehref
of that link, if found, is the base URI. - Base URI from the Retrieval URI. If no
self
link is found in the entity graph, then the URI used to retrieve the entity is the base URI.
Let's work through an example. Consider the following Order
entity:
{
"class": ["Order"],
"links": [
{
"rel": ["self"],
"href": "https://api.example.com/orders/69"
}
],
"entities": [
{
"rel": ["https://schema.org/orderedItem"],
"class": ["OrderItem"],
"links": [
{
"rel": ["self"],
"href": "https://api.eg.io/orders/69/items/1"
}
],
"entities": [
{
"rel": ["https://schema.org/seller"],
"class": ["Organization"],
"links": [
{
"rel": ["self"],
"href": "https://example.org"
}
],
"entities": [
{
"rel": ["https://schema.org/member"],
"class": ["Person"],
"href": "/people/42"
}
]
}
]
}
]
}
In order to resolve the https://schema.org/member
Person
sub-entity, we need to first resolve its href
. We start by checking the context Organization
entity for a self
link. Since one is present, we use it's href
as the base URI, making the Person
sub-entity's URI https://example.org/people/42
.
If however the Organization
entity had no self
link or it was itself relative, we would move up the entity graph once and check again for a self
link. In that case, we would use the OrderItem
entity's self
link's href
as the base URI, and the Person
sub-entity's URI then becomes https://api.eg.io/people/42
.
Similarly, had the OrderItem
entity's self
link been missing, we would once again traverse and search the entity graph. This time we fine the Order
entity's self
link and thus our Person
sub-entity's URI is https://api.example.com/people/42
.
Finally, if no self
links had been present, the URI used to retrieve the entity would be the base URI since we have exhausted the entity graph.
At minimum, Siren API documentation describes the following:
class
values- Names of
properties
name
s ofactions
andfields
- Custom
rel
values
Documenting IANA link relations is optional, but it may be worthwhile to mention which ones are used, especially for users new to web linking.
The exact format of Siren API documentation is beyond the scope of this document. Consider using a format designed for documenting APIs like ALPS or XMDP.