Hacker News new | ask | show | jobs
by gregory144 4380 days ago
I agree with you, but I have trouble understanding the right way to implement "commands" like this - I must be thinking about it in the wrong way. How would you design a "real" REST interface for a command like this? What's the advantage a "real" REST interface gives you in this case?
6 comments

Right. REST is about Transfering the State's REpresentation. In this case, we want to transfer an event ("honk!"). You could argue that we want to transfer a state transition ("begin honking"), and let some other process (the car) handle the next transition ("cease honking") independently, but that's forced, and in any case it's not RESTful either.

As far as I can tell, REST is appropriate in very few cases.... although it IS appropriate for more cases than it might first appear.

I don't know the whole state of the vehicle. I don't want to. So I'll use PATCH. I know I want the horn to be in a honking state and remain in that state for 1 second. The implementation is responsible for doing what it needs to do in order to get the resource into the state (or differential state in this case) I told it to take.

I'm not usually in favor of nested API design, but complex resources like cars make sense, so:

PATCH /vehicles/{id}/horn { "enabled": true, "timeRemaining": 1000 }

My initial thought would be that a request for a "honk action" is not idempotent, so it should be a POST.

You could do it as a PUT or PATCH, but you'd have to do it differently from in your example in order to preserve idempotence, due to the complications of working with time.

Remember, if the request successfully goes through twice that should have the same effect as if only the first succeeded. One way to accomplish that would be to give an absolute start and end time for honk to be on. e.g.,

PUT /vehicles/{id}/horn { "enabled": true, "time_start": "2014-04-12T20:12:36.1", "time_end": "2014-04-12T20:12:36.6"}

for a half-second honk.

There are some ways, I'm just thinking off the top of my head for one here.

If the resources of the car were mapped and had states it could work fine with a full REST interface. You could change the state of the horn like you change the state of a switch. You'd change the horn to be "on", not call some "turn it on" procedure.

They have some indications of that. There's a URL that returns the state of the vehicle (driving and position). That's something that could be mapped as a first-class citizen and someone could mess with it with the semantics of the verbs.

Commands are a much more RPC area though, REST doesn't map perfectly. You can almost always make a command into something of a resource state change, it just isn't always simpler. REST wouldn't give them much in this case as it's hard to imagine they'd make use of any of REST advantages. Not that there wouldn't be any technically (being able to evolve APIs without breaking clients is a pretty big advantage, plus plenty of other things), but that for their business it doesn't matter (they control every client).

You change the state of the horn to be on, but I'd imagine you might want the horn to automatically sound for a predefined length of time. Then the mapping is less obvious. Agreed that it doesn't really matter much in Tesla's case anyway.
You're still changing its state. If you have one horn you can do whatever you want with it, just like a normal person would. What the client does with a resource is only limited by the API, REST doesn't care what the messages contain. The semantic of the message is up to the API to resolve, you could encode that "stay on for 10 seconds" however you wanted.
(That said, they should definitely use POST here!)
Exactly -- where does something that is designed for "state transfer" get you when the goal is to only temporarily modify a state/send a command that modifies internal state for X amount of time, not really "transfer" one at all? REST maps very nicely to CRUD operations, but not to this.
Sure, but maybe you could think of POSTing to /honks as "creating a honk."

This would make sense if you wanted to GET /honks and see a collection of previous honks. (Modifying an existing honk doesn't make sense, so we wouldn't have to worry about it.)

I think this interpretation is the best fit. Similarly PUT would be appropriate for requests where you are specifying the time that the honk should occur, which would make them idempotent.
I wouldn't mind performing GET /vehicle/{id}/honks?since={time}&limit=1000 to see an indicator of how aggressively my car has been driven. Especially if somebody else is driving it.
You would use RPC.
This. While this API is not RESTful at all, that's just a nomenclature problem; it's totally fine as an API [1]. RPC is perfectly appropriate for a wide range of problems and there's no need to shoehorn every application into REST just because people say It's the Thing to Do. I could imagine a RESTful API for this, as people have above, and it might work well. But it isn't some sort of obvious best practice.

[1] Except that it really ought to use POST.