HATEOAS and JSON API

Hi,

I’m trying to build a REST API using the JSON API spec, and am finding it difficult to properly make it discoverable what the client can and should do. My rule of thumb is that a REST API should make it possible to write a generic sandbox HTML client on top, that can be used by a human to interact with it. So all actions and how to perform them need to be discoverable, but the sandbox itself doesn’t have to understand what it all means, just facilitate the interaction.

My first problem is the following. The model is users and videos, users can like/dislike/unlike/undislike videos. If a video is at /videos/123 and the requesting user has NOT liked the video already, then it should include a relationship to /users/abc/relationships/likes in an included resource of type “viewer” (representing the users relationship with the video). I had to then add meta to the link with “allow”:[“POST”] so the client can know that it’s possible to post to this likes relationship.

So far so good. But how would a generic sandbox client be able to know that the target relationship is a many relationship, and not a to-one relationship, in order to send the correct JSON? Would you solve that with more metadata, or a profile, or something else?

The obvious workaround is to have the sandbox first do a get on the relationship, where it can find out it’s a many relationship, but it would be great if this can be done in one call instead of two.

This is the first problem I attempted to solve with regard to writes in the API, and it’s already a headache. Are there already solutions to these seemingly trivial issues documented anywhere?

Any insights would be most appreciated!

cheers, Rickard

1 Like

Looking into this some more, I feel like the biggest issue I have with writes (the read side is fine) is that it’s essentially treating the API as a database, not an application. For example, it is typical that a resource returns let’s say 20 attributes, 5 of which may be calculated, and a bunch more are inferred. They come from application logic, not a PATCH or similar. So in providing write capabilities I really need to have some kind of action/command system which 1) will tell the client when an action is possible (e.g. posting comments to a video might be entirely turned off, just for that user, or just for that video), and 2) exactly what the client needs to provide. Doing POST/PATCH calls just aint affordable enough to solve this.

So here’s my current experiment to get this to work. When accessing a resource it will return its fields as normal, along with a links section that might include actions. Actions are determined by a) having a ?profile=<> query parameter that points to an ALPS profile with machinereadable description of what is needed and b) the link has meta with “allow”:[“POST”,“GET”]. The client can either POST straight to that URL, or do a GET first in order to have field defaults populated. This solves both problems described above in a clear way, without treating the system as a database (which it is not).

Has anyone else tried creating a REST API using JSON API? Any other approaches to writes that handle 1 and 2 described above?

Thanks!

I have exactly the same problem, and I “solved” it in exactly the same way – with ‘actions’ in the links section of each response. It’s definitely not ideal, so I would love to hear about how anyone else has solved this. How did your experiment pan out @rickardoberg ?

@rickardoberg @kevinrutherford I am dealing with the same issues right now. But I am struggling to follow your solution solely from your words.

Is there any chance you could share some JSON, URL and HTTP examples to show exactly how you approached your solution?

I am also trying to understand the distinction you are making regarding not treating it like a database. I understand what you mean in abstract but I can’t envision the distinct approaches you are comparing and how one is like a DB and the other is not.

Thank you in advance.