Let’s say we have two relationship related links here: /authors/3/books and /authors/3/billing_plan. Does /authors/3/books have the same feature as a collection (filtering, inclusion, sorting, sparse fieldsets) and /authors/3/billing_plan have the same feature as a resource (inclusion, sparse fieldsets)?
It is easier to understand why /authors/3/books would support pagination. Probably because representing the response in a series is something largely deploy on the Web.
It is easier to understand why a server would not allow PATCH or DELETE on /authors/3/billing_plan. Probably because the resource should only have one address and that the canonical URL should be used instead.
On one side supporting inclusion, filtering or sorting on a relationship related link seems awkward because there is no way to know if a relationship is a to-one or to-many, compared to when you know you have a collection or a resource URL. On another side, not allowing inclusion on a related link seems to go against the properties json:api want to bring forward (less fetching).
Another thing worth mentioning is that I think that strictly for a to-many relationship, the related link could have been /books?filter=author.id eq 3 instead of /authors/3/books. Since it is using the collection URL, then it would naturally support inclusion, sorting and filtering.
What design decisions would you make considering all this?
If books is a to-many relationship, how would the related link not refer to a collection? It may not be a collection of all books, but it is a collection of the related books, right?
As I’m reading the JSON:API specification, something is a collection because the primary data returned by a GET request is a list of resource objects; there’s nothing else to it.
The examples included in the specification use a consistent and straightforard URL mapping, but that mapping is neither defined not implied by the specification. Completely different URL mappings are possible and would be equally compliant.
My struggle was with to-one relationship. But you make me realized I had to take I step back and look more clearly. So thanks for that. I think my struggles was that I saw /billing_plans purpose as strictly being a collection of billing plans. But nothing prevents me to use something like /billing_plans?filter=author.id eq 3&first=1 to return the resource document or a null data document for the related resource in a to-one relationship.
The purpose of /billing_plans is in fact to serve as authority for billing plans. As simple as that. Using first=1 in the query is simply a non hierarchical way to represent the related billing plan. I think this is the design decision that resolve the problem.
If /billing_plans is a collection, then using a query parameter (first=1) to turn it into a resource is a bit odd. Getting null for the primary data is specific to empty to-one relationships through their related link. Note also that the related link isn’t supposed to change when the target of the relationship changes, though that doesn’t mean it can’t be implemented as a redirect to a canonical URL for the target resource.
That’s specific to your application and the URL mapping you’re using, though, and isn’t defined or constrained by JSON:API. The examples used are consistent, but reflect a fairly simple model; this may or may not make sense for your application. It’s important to keep in mind that the structure of the URLs has nothing to do with JSON:API.