Hey,
2018-01-08 2:11 GMT+08:00 Arun Nair <
arun...@gmail.com>:
> Hi,
> I was thinking of how to make a RESTFul API more intention revealing. .
> A common patter I see around various blogs on this is
> that conventional REST API results in
>
> Ban a Player -> POST /players.
>
> But I were to change to a Command , I could use
>
> Ban a Player -> POST /players/{ id }/banPlayer
>
> The second one I feel is more intention revealing.
>
> The common objection I get from the team is that the second one does not
> comply with start REST style.
>
> Would like to hear your opinion on this.
Great question! My system uses a REST API with backend implemented
using CQRS/EventSourcing using EventStore. The objection you note is
probably because none of them have actually read the REST thesis
(
https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm), and
Roy's clarifications on his blog regarding HATEOAS (it's mandatory).
As Greg notes, you really gotta use hypermedia to get it right, and
the first style makes that really hard to do.
The rule of thumb is this: a good REST API is just an ugly website.
Meaning, there's a starting URL and from there clients can a) click
links or b) submit forms. Those are the only two actions. Hypermedia
tells what the URLs are, and also what method to use
(GET/POST/PUT/etc.). Just like using a web browser.
Given that, here's what I would do, guessing a bit about your domain.
/ (the API root) has a link to /players. On /players there's a search
form, which you can submit using id, or email, or username, or
whatever identifying info you want to use. Or one form for each, that
is ok too. If submitting that form yields only one result, then
redirect to it, meaning /players/{id}. On that page you would have the
information about the player, as well as links to all valid actions.
If a player is already banned, then there is no link for that. If the
player is not banned, then the page includes a link to a form for
banning that player. Client clicks that link, let's say, and get to,
for example: /players/1234?action=ban. This returns a form with all
the fields needed to ban a player, maybe a comment from the admin on
reason for banning, references to evidence, etc. The form would say
whether it's a POST or PUT, probably a POST, and the client can then
fill in the form and submit it. If form data is invalid return 400 and
show form again. If ban succeeds then do a redirect back to the player
at /players/1234.
That's how you would do it on a website, and since a REST API is just
an ugly website, that's a reasonable way to do it. You can vary some
of the details above, but that's the gist of it.
The reason I like /players/1234?action=ban rather than
/players/1234/ban is only because I prefer using hierarchies for
entity hierarchies only. Allows me to for example do
/players/1234/account and /players/1234/history, which would then not
clash with the forms I can do to perform changes on /players/1234.
REST URLs are opaque, so a perfectly valid way to do it as well is
this: ?type=player&id=1234 rather than /players/1234. From a REST
point of view that is completely arbitrary.
I've built my system according to the above, and it works really well
and is easy to change and evolve. We have changed URL structures
completely a bunch of times, with no changes to clients (like mobile
apps), because all they do is follow links and submit forms, so as
long as rels and form id's are stable, they are ok.
For content type, you can't use application/json obviously since it
has no support for links and forms (it would be like trying to use
text/plain for a website, doesn't really work). We went with
Collection+JSON, which so far has worked really well, and allows
clients to behave exactly as described above (follow links, submit
forms).
YMMV, but that's my take on building REST APIs with CQRS and
EventSourcing. There are some extra steps to consider because of the
eventual consistency of submitting forms that perform changes, but
nothing too complicated.
regards, Rickard