Live data from Hacker News

It's time to put REST to rest

sollecitom.github.io

61–70 of 85 posts

Re: It's time to put REST to rest

#61
What the author seems to miss is that a "resource" in the REST sense (in practical usage at least. I'll leave the official recommendation pedantry to those who care for it more strongly than I do) doesn't need to reflect a data structure.

It's definitely easier to link data structures to REST commands--I imagine REST was created with them in mind--but the recommended "commands" can still be thought of as resources. Not every REST verb applies to them, true, but that's not really impactful or relevant. The point is that you can continue structuring your API in typical REST fashion, but with the addition of command-oriented RESTful paths that implement the appropriate verbs for that command.

The author's own suggestion, `POST on /commands/{command-type}/version/{command-version}`, is still effectively REST as far as I'm concerned, with the identifier being a string ('command-type') instead of a number or UUID. The structure of the API hasn't changed, we just broadened our definition of a resource. Purists might disagree there, but from a day-to-day practicality perspective, nothing significant changed in our API development. The article is arguing semantics rather than actually criticizing REST as it's used in practice.

That said, the author does seem to have listed a few things I disagree with:

> So when the server receives a PATCH /schools/{school-ID}/students/234 { "lastname": "Luthor" } request, it needs to understand that a student has requested for their lastname to be changed, and it then needs to decide what to do about it. What if some fields cannot be changed? What if the value of some fields is constrained by the value of some other fields? By allowing an arbitrary PATCH operation, these concepts are hard to model and validate requests against.

I'm not sure what difficulty they're seeing here. If some of the values can't be changed, it's a failed request, return the errors without any updates. The "arbitrary" parts feel like they derive more from their own API implementations than anything practically REST-ful. Or maybe it's in the official REST spec, which, as comments here demonstrate on repeat, holds very little ground.

> This also sucks, because HTTP status codes are about the HTTP protocol, not your business semantics. The 404 Not Found status code indicates that a path doesn’t exist. If you use it to say that a student doesn’t exist, these two get mixed up. If a client invokes the wrong path by mistake, there’s no telling whether it’s due to a protocol error or to a nonexistent student.

If there's no student with the ID 4, then the path `/students/4` doesn't exist. It's not saying that `/students/` doesn't exist, because the path-with-variable only exists as a theoretical construct, not an actual path. So I'm not quite seeing their argument here (unless, again, they're arguing against the semantics of the official recommendation, which I've never seen implemented in a straight fashion anywhere). And if there's user error in invoking the wrong path, then that's hardly on the API design.

Re: It's time to put REST to rest

#62
post #57

The article is good, and I get the point. However, from experience, this: > POST on /queries/enlisted-students-on-joining-date/version/1 { "date": "2023-09-22" } to retrieve all students that joined on a given date. always ends up in a complete and absolute mess, where every possible query gets it's own random name, different parameters, ending up with duplicates all over the place. Also, while it can be possible to…

I like the convention: - 404 if resource requested by id - 200 with empty list of results if it was a 'search' type request with params (not referring directly to an id)

this is the standard we have company-wide and it works pretty well, unless you make a mistake in the uri (like picking up the wrong api version). however, all apis will return some info on their root, so it's easy to distinguish and troubleshoot

Re: It's time to put REST to rest

#64
I'll have to add a client API to one of my projects soon and I've been thinking about this particular problem lately.

The one API I worked with a lot is that of VKontakte. It's as unRESTful as they come. You send requests to URLs like api.vk.com/method/users.get. The HTTP method doesn't matter at all, how you pass parameters doesn't matter at all (can be a combination of query and form-data for all it cares), the version is just `v` parameter, the access token is also just a parameter, and errors come with 200 OK. That is kinda not well thought out. But only kinda.

The one I'm contemplating is somewhere in between the two. The endpoints are still "methods", but the HTTP method does have a meaning: GET is for retrieving something, and POST is for active actions. The access token will have to be passed in Authorization header. The version will still be a `v` parameter. There will not be any IDs in the paths because of how awkward that is. The errors will set the HTTP status code.

Any opinions on this?

Re: It's time to put REST to rest

#65
post #15

As a REST enthusiast I was excited to read this and learn a new perspective but this section > The “benefits” REST is supposed to introduce Is one of the more egregious straw men I’ve seen in a while. Never once in my twenty years have I heard anyone say it’s nice because “you don’t have to read the docs” or “it works in a browser” REST helps with lots from thinking through clean data models to helping ensure consist…

[deleted]

Re: It's time to put REST to rest

#66

The article is good, and I get the point. However, from experience, this: > POST on /queries/enlisted-students-on-joining-date/version/1 { "date": "2023-09-22" } to retrieve all students that joined on a given date. always ends up in a complete and absolute mess, where every possible query gets it's own random name, different parameters, ending up with duplicates all over the place. Also, while it can be possible to…

404 means that there is no resource at the requested URI. But in the case you're discussing, there is a resource at the requested URI; it's just a resource that says there's no user there, instead of a resource that gives data for a user.

In other words, using 404 the way you describe conflates two different things: an invalid user URI (maybe the range of possible user IDs is restricted, or you typed in the URI wrong) and a valid user URI that just doesn't have a user there at the time you made your request. But you probably don't want those two things to be conflated; you want them to be distinguished. That's the article's point.

Re: It's time to put REST to rest

#67

OK OK OK, OK OK, stay calm, Carson, stay calm... I'd like to just leave a few links on REST here for the reader's consideration: https://htmx.org/essays/how-did-rest-come-to-mean-the-opposi... https://intercoolerjs.org/2016/01/18/rescuing-rest.html https://htmx.org/essays/two-approaches-to-decoupling/ https://htmx.org/essays/hypermedia-apis-vs-data-apis/ https://htmx.org/essays/hypermedia-clients/ https://intercooler…

This is fair, what I think ended up happening in the 2010s is that REST was pushed similar to XML, a solution for all application problems (it wasn’t like Fielding was not pushing this view either), and realistically the useful scope of REST and Hypermedia is quite limited.

Re: It's time to put REST to rest

#68
post #18

I agree with some of this - I've never found value in the different PUT/PATCH/etc verbs, and I think the lack of examples of good "pure" REST APIs indicates that pure REST doesn't work easily for most projects. I do think this throws away some pieces that are really valuable though: 1. URLs for concepts are a good idea 2. Distinguishing between read-only operations (which can be cached) and write operations using GET…

Yep, this is pretty much what I've settled on myself.

GET for read, POST for write. And a url made of a slash-terminated "resource" followed by an "action" verb. user 123 + edit = "/user/123/edit" ; user 123 + default(show) = "/user/123/" ; list of users = "/user/list" ; etc.

When applied to web pages, it means you can have and the "action" attribute of the form directly matches the "action" of the backend/router/API. I like that, it makes me feel warm and fuzzy. :-)

Re: It's time to put REST to rest

#69
The author has almost perfectly described the pattern behind GraphQL mutations!

That is, a command on the server that represents a user action, takes input, and returns the updated data that has changed. While many people dislike the whole GraphQL stack (I love it, it solves all the problems the author has with REST), I think we can all agree with the usefullness of the pattern that mutations are built upon.

Re: It's time to put REST to rest

#70
A few really appealing points and ideas here!

Versioned "commands" are an improvement I'd like to see more of (it could even be useful in existing REST-lite APIs - I've used similar concepts to this in some prior work)

And the key point around business logic being misrepresented is definitely worth a ponder.

Notable that a lot of this sounds like a reinvention of DDD (Domain Driven Design) concepts - or at least if the author is applying DDD they make no mention of it. Which I wholeheartedly support..

Seems like two problems being conflated though:

1. Low level interactions - generally between systems. Sometimes I _want_ my API not to hold any high level business logic. It'll do basic verification of individual entity events (changes) to avoid epically stupid mistakes, but otherwise is a dumb resource used by other, more high level controllers.

Often this scenario is basically a thin wrapper over storage mechanisms, or a single abstraction atop a collection of other APIs In this scenario, REST or other "non-business-aligned" options are perfectly fine - if they were any higher level then I'd be constraining the possible actions to what's implemented in a single place.

But by keeping it granular, and aligned explicitly to direct interaction with specific models (in a bounded context) then those changes _should_ be isolated.

2. Intent based APIs which perform high level actions that are aligned to ubiquitous language.

These would be a great fit for the proposed method in the article - and I'd posit that many of us already use some form of this in our APIs, whether through naughty blurring of what "REST" is supposed to mean, using GraphQL, or other similar alternatives.

Generally these are user facing, or at least are at the boundary.

Personally I'd maintain these as a separate thing (or at a separate top level route) which leverages the lower level interfaces to perform more complex, potentially multi-modal activities.

---

*TLDR* what the article proposes seems useful, but (IMO) more as a good reminder to be clear about your APIs' purposes: are they an interface to a bounded context, a model, or an aggregate?

Post reply on HN