In order to improve the hypermedia-ness of my API, I’ve wanted to add links with custom relation types to my resources. It wasn’t until recently that I realised this isn’t actually allowed by the spec:
Unless otherwise noted, objects defined by this specification MUST NOT contain any additional members. Client and server implementations MUST ignore members not recognized by this specification.
While I didn’t think much of this at first, investigating issues on Github has made me realise this does in fact apply to links
objects too, so something like the following would be illegal:
{
"links": {
"avatar": "https://static.myapp.com/avatars/foo.png"
}
}
avatar
is not a registered link relation type, of course, but more importantly,- the spec does not define the
links.avatar
member, so it’s not allowed.
Reading through this issue I found a great clarification of why adding more links is important to me (emphasis mine):
Let me start with this part of the question: what is actually the core problem here. Discoverable actions, at least the way I suggest to implement them, do not pretend to solve the problem of building full hypermedia APIs, which need little to no documentation. It is assumed that the documentation on formats of specific requests is needed. The purpose of actions is to inform the client what is available for the given user on a given resource at a given moment of time – this is why actions should be returned dynamically, as part of a resource’s representation, and not via schema, docs, or in some other static way. So to me, the core problem is different from what you describe.
I’ve since combined two pieces of knowledge to decide on a course of action that will help me continue building useful features into my API for now, but also should remain spec-compliant as far as I can discern its future direction:
RFC8288 states that “extension relation types” can be used if they are URIs. URI syntax is defined in RFC3986, and here are some examples:
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
| _____________________|__
/ \ / \
urn:example:animal:ferret:nose
Colons are a necessary part of URIs.
Separately, JSON:API 1.1 extensions specify that extension members be namespaced using a :
.
O happy circumstance! I shall proceed, for now, by defining an extension type for myself and using it as part of my custom link relation URIs. For example,
{
"links": {
"mycompany:avatar": "https://static.myapp.com/avatars/foo.png"
}
}
I hope this isn’t too controversial, but I wanted to post it so that any fellow travelers following the same road I did will see what one weary API designer has done to reconcile the imperfections of messy APIs with the rectilinear world of specs.