Hacker News new | ask | show | jobs
by noblethrasher 2183 days ago
HTTP is one particular implementation of REST that happens to have nine verbs. Another implementation might only have two or three. But no RESTful architecture will have much more than nine.

Why?

Because your application is going to have thousands of nominal states, and each one is going to need to support all of the verbs because of the uniform interface constraint.

Why a uniform interface?

A lot to say about this, but basically, the set of verbs is an abstraction of the state machine that is your application. If you have a million states and a million verbs, then you have no abstraction. If you have ten states and a hundred verbs then you have too much abstraction (i.e. you ran afoul of YAGNI). A good degree abstraction is somewhere in between, but if you care about scale (which is the raison d'être for REST), then the size of set of verbs is going to have a logarithmic relation to the size of the set of nominal states.

2 comments

Most applications will have more "states" than there are molecules in the known universe. Number of states is meaningless, and doesn't play into anything.

If I need to delete users I want a function called "deleteUser" (for example) and it will use an HTTP post to send up info, and it will stream back the response. Period, full stop.

An HTTP "post" is your 'backbone'. Nothing else about HTTP needs to creep into your actual domain specific API language of method names in your RPC vocabulary of verbs.

Also if non-HTTP REST can exist, that's fine, but I'm writing web apps so I will be doing HTTP-posts because, as Fielding himself would say, why redesign something that works.

I didn't say "states", I said "nominal states". These are the states that you would bother to name. They'll correspond to classes in an OOP language or discriminated unions in an ML-stye FP language.

Using your example, you'd have two states: `PrepareDeleteUser` and `DeleteUser` where the latter is only reachable from the former. PrepareDeleteUser will check that the all preconditions are satisfied (e.g. that the current operator has permission to delete the user). Now, you may not choose to reify these states so directly (i.e. you'll just have a deleteUser function that does a check for the preconditions), but they must exist in a robust application nonetheless.

In REST we name our states so we can drive the state machine by using the names (following hyperlinks). Why? Because, among other things, this keeps the client decoupled from the server by letting the client be in control of when to effect a state transition, but keeps the server in charge of what transitions are possible.

I need to attend to some real-life concerns at the moment, but I hope to get back to this discussion soon.

Cheers!

There's nothing wrong with having a "PrepareDeleteUser" to pre-check if a user can be deleted. That's a legit design that you mention, but that does't validate these two silly criteria built into REST:

1) Everything is a noun. 2) You have a finite set of pre-defined verbs.

In my opinion, everything is not noun, and I don't want any verbs pre-defined by the stack.

I will always continue to use HTTP POST as the 'transport mechanism' to send a JSON request up and get a JSON response back. It's the simple and obvious way to do things, and after fully understanding REST (trust me I do get it, fully) my opinions remain unchanged.

There's a reason "functional programming" model dominates all software architectures, while state machines are rarely used in API design. All of the reasons functional programming is good on the same machine STILL APPLY even if the machine you're calling is remote.

And just because you're riding on top of HTTP over the web is no reason to intermingle your application layer code into HTTP-related stuff. Your API should remain unchanged even if HTTP were replaced by something else. Nothing about HTTP should affect one single verb or noun (function or object) in your entire application API...and if it does it's because you've been brainwashed by the REST cult. :)

> A lot to say about this

I'd like to read more about this way of thinking about it. Do you have any recommended resources?

Most of what I have to say comes from Fielding’s dissertation, along with spending the past several years trying to take it as seriously as possible. Other good sources are McCarthy’s Situation Calculus and all of the stuff that Lamport has written on on TLA+ (especially Specifying Systems[1]).

The big idea behind scalability (IMO) is that we want the pain of maintaining a system to grow logarithmically with respect to the size of the system. Now, size can mean many things (number of customers, lines of code, etc.), but pain is almost always complexity. A potent cure for complexity is symmetry, because every time that we discover a new symmetry, half of the complexity goes away. One way of finding symmetry is to look for invariants.

Roughly speaking (very roughly), having lots of possible states is good (the more states, the more powerful/featureful the system), but having lots of state transitions is bad (especially with respect to security). REST “verbs” help to control complexity by imposing invariants on state transitions. For instance, one good invariant to enforce is that a GET transition mean that a state can always be a start state, whereas a POST must always have an antecedent state. Thus, a REST verb is just label for a set of invariants, and we’re free to choose whatever set of invariants we want. Obviously, the more invariants you have, the weaker they are since an invariant is supposed to be unchanging; i.e. if the size of set of invariants is close to the size of the set of states, then you effectively have no invariants.

[1] https://lamport.azurewebsites.net/tla/book-02-08-08.pdf