Hacker News new | past | comments | ask | show | jobs | submit login
[dupe] Tesla Model S JSON API (apiary.io)
80 points by daenz on June 30, 2014 | hide | past | favorite | 84 comments



While this is clearly not REST-ful, the fact that the comments here can spend so many words philosophizing over whether this ought to be PUT vs. POST vs. PATCH illustrates why REST is not my favorite technology.

It's like XML all over again. Should it be an attribute or a child node? Should the parameter go in the header, or in the body, or in the URL? Should it be part of the URL path, or a URL parameter? Should the error be indicated in the HTTP status code or just in the body? Did we get it right, or do we need to find a Roy Fielding quotation illustrating the principle we violated?

Normally this wouldn't bother me, since I generally have faith that the "free market", so-to-speak, will favor the best technologies in the long run. But HTTP and REST have an artificial boost in that they are the only way to get through many firewalls, so in essence everyone has to go along with REST whether they want to or not (or at least tunnel over it). And of course everything can be made to work with REST, so everyone eventually converges on it, even if it's not the best fit, and its dominance grows.


Some of this is pedantic. But mostly, it's calling out, without much grace, that this API is a failure of a design. Not because it's not [insert buzzword] but because:

1. what happens if you visit a control panel page in chrome? Does chrome spider ahead, eagerly caching the links on the page assuming that visiting a page has no side effects? Have fun silencing your horn and windshield wipers from simply visiting your control page.

2. what happens if chrome then has that "get" url very strongly cached? After spending 10 minutes trying to silence your car from your first visit to the page, the "honk horn" button now does nothing but load the word "true" from the browser cache.

3. what if any of the above happens while you are on the road ? what if some wise guy down the line decides that a car should be designed API first, and your dashboard, pedals and wheel are just one of many potential API clients? Can you really now tolerate using the GET method in ways that it is explicitly documented to not be used?

This isn't just philosophical or quibbling over definitions. Getting this wrong means things actually break in the real world.


Will the browser cache XMLHTTPRequest GET requests? I hadn't realized it would do that.

I agree that if anything between you and the server is going to cache requests then you need well-specified behavior around that. But that particular problem can be solved by a specification much, much simpler than all of HTTP.

I also see that it's useful to know that certain requests will not be state-changing for purposes of pre-fetch. But while I agree this is important for the browser, I question how important it is for APIs. API calls are usually constructed programmatically -- V8 isn't going to start just randomly guessing what XMLHTTPRequests you might come up with next and start fetching them. This is where I think that browser-based paradigms with a human user diverge from programmatic ones.


It costs nothing to switch those GETs to POSTs (or fucking whatever method best describes the kind of side effect you're doing). why are we making excuses for doing the obviously wrong thing?

I get what you're saying about the API… but if you're going over HTTP why not play by HTTPs rules. Presumably it's an app that is the primary consumer of the API so they could use any sort of protocol. Why decide to use HTTP but not conform to the standard in a way that ruins any benefit you might have got out of using HTTP instead of say:: OSC or.. basically anything OTHER than http would be better.

If we're talking about using HTTP to bust through a firewall, then that stuff is DEFINITELY going to break unless you use HTTP in as dull and ordinary a way as possible, and GET requests will always be cached by god knows how many different machines between you and the car.

If it's not an app, then we've decided to put a webserver on the car so that we can serve a website with some javascript that does XHR calls to make things happen. I would not put it past google to make a future version of chrome that prefetches JSON api requests. But regardless, yes, XHR calls do go via the browser cache. and the proxy cache. and the firewall. and any other machine that makes basic assumptions about what those methods mean.


> why are we making excuses for doing the obviously wrong thing?

Sorry if I was unclear -- I wasn't advocating a mis-designed API, I am suggesting that HTTP is way more complicated and subtle than it needs to be for the purposes of remote APIs.

I concede that providing enough information to know what is cacheable (and what the caching key is, etc) is justified complexity. But I think that the other 95% of semantics that "pure" REST demands you follow are pretty useless and pedantic.


Sometimes you just need to call a procedure, remotely.


YES! (though I'd quibble with s/sometimes/usually/)

To reply to my siblings:

HTTP is in practice a great transport protocol, because of the world we live in. That's an affront to ivory tower engineering (my favorite kind), but it's a lot better than failure to ship (or shipping something that only works under non-existent conditions).

And RPC needs some kind of container protocol, and SOAP is one possibility, sure. Keep it the hell away from ME, but it's one option. The sane option is to do just what all these so-called RESTful services actually do (modulo not using GET when you should POST), with pleasant-but-not-dogmatic URIs, and JSON, and so forth, and just stop calling it REST, because it's not REST at all. Or call it whatever you like, but get used to endless trolling from pedants like me.

Aside from the bad HTTP verb choice, isn't TFA a pretty reasonable API implementation?

Of course, as sillysaurus noted.... TFA doesn't call it RESTful at all... that was just the HN headline. Oh how we've been trolled.


If HTTP is a bad fit for RPC interfaces, is there something that is a better fit?


Isn't that what SOAP is for?


And SOAP works over which protocol?


Any! It's transport layer independent!

</sarcasm>


If the only flaw here is the mis-use of the term "REST", I'd say it could be worse: they could actually try to make it a RESTful API!

I too am not very fond of REST, but for slightly different reasons. While I acknowledge its benefits, I'm afraid REST will go the way of OOP in terms of fad-chasing, resulting in massively over-architected and contrived systems.


I went through that madness when trying to figure out Hypermedia APIs. Supposedly you're not RESTful without hypermedia, but the whole thing seems crazy when you get into it.

Perhaps, just as JSON became a more functional and popular format than XML we can build a new REST spec that simplifies all this.


I (really do) hate posting this but I swear every single "REST" or "RESTful" or "REST-ful" API post I see, there's always that guy that chides it for not being pure or REST or "-ful" or something. Do we really care that much? Does the API work? If so, move on...


If every Java program was called functional programming people would probably care as much. It works, so move on...

The main problem is that it's not just a small deviation from REST, but the absolute opposite of it. That's hard to ignore.


The main issue with the quoted example is that GET is intended for non-destructive interaction with no side-effects. Whether you use PUT or POST is a much smaller argument than whether to use GET or something else.

To most people, honking the car's horn is an unwanted side effect.

As has already been pointed out, some browsers will fetch-ahead to ensure that pages appear to load instantly. If you open a page which is a bunch of buttons which do stuff like honk the horn, lock the door, raise the window or open the charging port door, there will be unwanted side effects.

So yes, we do care that much.


If it doesn't follow the design pattern in some form that it states it does, then it should be referred to as the technological interface it's offered through - in this case a web service.


I would love an answer for this. How can we describe an api without just calling it a generic 'web service' - where that may be misinterpreted as being a SOAP web service. And it's not strictly a REST web service.

http://stackoverflow.com/questions/24482179/whats-the-best-a...


> This is unofficial documentation of the Tesla Model S REST API

Very few concepts have been so hugely corrupted to mean exactly the opposite of what they mean as REST. This is probably the least REST API in existence.


(Project owner here)

My fault for calling it that. It's REST-ish, but not RESTful. Tesla never called it that (they don't even officially acknowledge the API), so it shouldn't be misconstrued as them not knowing what REST is. This is their internal API for the mobile apps, so they're free to design it however they like.


How is it REST-ish, even?


True. This always comes up whenever it gets posted here or on Reddit, so I just renamed it to the "Model S JSON API" to stop that argument from coming up again.


I use this API daily. I agree with some of the others. It works. I don't really care if it's REST or not.

Of course, if the API is going to be growing, you may want to organize it in a guessable format...also, if it's going to be growing, I wouldn't mind helping/testing. :D


Most people use REST as a synonym for "API you can call over HTTP".

I've never liked the dogmatic aspect of REST anyway, saying that API's should only ever be REST-ful is like saying that you should never call functions in your programs and only ever use getters and setters.


Here's Roy Fielding's summary:

http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hyperte...

After reading this I cringe whenever I see any API claiming to be "REST(ful)".


> A REST API must not define fixed resource names or hierarchies (an obvious coupling of client and server). Servers must have the freedom to control their own namespace. Instead, allow servers to instruct clients on how to construct appropriate URIs, such as is done in HTML forms and URI templates, by defining those instructions within media types and link relations. [Failure here implies that clients are assuming a resource structure due to out-of band information, such as a domain-specific standard, which is the data-oriented equivalent to RPC's functional coupling].

I don't even know how I'd write a client against a server that arbitrarily changes endpoint URIs. I honestly don't see a benefit of RESTful if REST requires complete decoupling of the server and client. REST isn't SOA. There is no discovery API for REST. If I don't get to hardcode /api/vehicle/, then how else can I write a functional client?


As with a lot of things in REST, the answer lies...in your browser. How did you know how to answer that last comment? You clicked a link for it. Not everything about REST can be answered by "just look at your browser", but a lot of things can.

If you follow a link you don't care what the URL is. You never needed to type out "/reply" to use Hacker News, you don't need to do it to use an API. That's what the article is about.

The actual URL is unimportant, you just need to know what the link for "/api/vehicle" returns to do something useful with it. Like you knew that "/reply" would give you a form with a place to type out a reply.

> I don't even know how I'd write a client against a server that arbitrarily changes endpoint URIs.

The thing is, you don't have to. I can write one for you and you'll never need to write another one again. You could use it and just have to implement the part that matters to your application, the semantic of it. You wouldn't need to hardcode anything, or even handle URIs at all.

You could use it for Tesla's API, Twitter's, Facebook's, whatever. If they used links you could use the exact same client for anyone, just needing to re-write the logic part (like creating a post on Facebook, a tweet on Twitter, etc).

Problem is hardly anyone actually implements links so you can't do that. It sounds like utopia but it's just the product of extreme decoupling. It's not really any different than browsers.


Thanks for the post. I still don't completely follow your example of the client you could write for me. Can you recommend any articles that go into more detail on this with examples? The level of abstraction in Roy's article was difficult to follow.


It's not a simple thing, so don't worry. It took me a little while to understand and it wasn't without some head scratchers.

Best places to be are at discussion groups (api-craft, rest-discuss). Steve Klabnik has a good book on REST that explains it in more layman's term. Fielding's a PhD (REST was his thesis) so his writing is intended for an academic audience, it's indeed hard to follow without previous introduction.

I actually "understood" it on api-craft. The real-life examples it has are very helpful.


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?


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.


> Very few concepts have been so hugely corrupted to mean exactly the opposite of what they mean as REST. This is probably the least REST API in existence.

This is the first time I've seen URL APIs not being referred to as RESTful. What makes it non-RESTful?


It's not according to both RESTs:

Fielding's REST says absolutely nothing about URLs or their structure.

Everyone else's REST (and, the HTTP spec) says that you shouldn't use GET to cause a side effect.


Wait. GET's can unlock my doors and honk my horn and stuff? Don't let anything spider that page of links!


Right, since it has side effects this should be a POST action.


I'd humbly submit that PUT is the better choice. POST is to create the resource, PUT would be better to change its state. I don't want to make a new horn, just honk the one thats there. (PUT is also usually considered idempotent, honk as much as you want!)

  PUT /vehicles/{id}/horn

  {
  "command": "honk"
  }


POST doesn't have to create a resource; it can also be used to annotate existing resources.

The main problem with using PUT is that PUT is supposed to be idempotent; the result of two PUTs with the same content should be the same as the result of a single PUT with that content. But two PUTs to honk the horn would honk the horn twice, not once.

Since we're all being pedantic about HTTP methods here, we should have a link to RFC 2616 :)

http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html


Ahh. Good point. I was considering PUTting the horn into the honking state vs POSTing horn honks for execution. In the first case, 2 PUT honks would just result in a honking car, in the second, 2 POSTs would get you 2 "honks" whatever those are defined to be.

I guess I was thinking of the idempotent "panic" button on my cars key fob.


the idempotent "panic" button on my cars key fob

Hmmm, mine actually isn't--one hit turns panic mode on, the second turns it off.


There's a reasonable argument for a custom verb.

But pragmatically, given the problems customs verbs cause I'd probably go for POST.



POST is for anything that isn't actually CRUD, too.

http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-1...

PUT can be creation (not only POST), if you know the URI of the resource in question, but PUT implies that the submitted data should create or replace the resource at that URI, and in the case of a physical horn, this is impossible. I don't think you should ever be able to PUT to something that it's impossible, even in theory, to create with a PUT.


I humbly submit that using PUT is wrong. Argument follows, citing wording at

http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

First of all, we're not "enclosing" an "entity" to be "stored" or "accepted", so neither HTTP verb is strictly appropriate.

PUT requests are for uploading a resource, and the uploader specifies the desired final URL. So PUT is only appropriate for creating a new horn. Relevant quotation:

    In contrast [with POST], the URI in a PUT 
    request identifies the entity enclosed with 
    the request -- the user agent knows what URI 
    is intended and the server MUST NOT attempt 
    to apply the request to some other resource. 
    If the server desires that the request be 
    applied to a different URI, it MUST send a 
    301 (Moved Permanently) response; the user 
    agent MAY then make its own decision 
    regarding whether or not to redirect the request. 
POST requests, by contrast, are sent to a handling resource, which decides what to do. POST is appropriate for several purposes, including "annotating existing resources" and "providing ... data ... to a data-handling process". Seems like a better fit.

But either way, REST is for documents (understood broadly), and I don't think I know how to understand "document" broadly enough to cover a horn. So it's gonna be a rough stretch, and in general, I'm skeptical about the value of applying REST semantics.


>But either way, REST is for documents (understood broadly), and I don't think I know how to understand "document" broadly enough to cover a horn. So it's gonna be a rough stretch, and in general, I'm skeptical about the value of applying REST semantics.

That's probably about the wisest thing that's going to be posted on the subject tonight. I did a large enunciator panel project and we ended up being "rest-ish", using the idempotent PUT to put hardware dodads into various states, and reserving POST for adding things to execution queues. Being clear and consistent is probably the silver pearl in any implementation. Hardware control always degrades to some kind of RPC scheme, even if you dress it in a REST outfit.


> I'm skeptical about the value of applying REST semantics.

One must at least take the basic protocol promises into account. And there is no certainty that a GET will reach its destination, nor that it (or a PUT) will reach destination only once.


I agree absolutely; if you're using HTTP, you must take into account HTTP semantics. Exactly as you said.

But HTTP is not REST (note that SOAP usually layers over HTTP, although the SOAP-vs-REST is an unhelpful dichotomy).

As some other commenters (including an uncle of this comment) have said, what one often wants is simply RPC, and one must pick (or roll) an RPC format. JSON-or-whatever over HTTP seems good to me, and yes one must be respectful of HTTP semantics.

In fact, aside from the very-troubling choice of GET for commands, the API linked seems entirely reasonable. And it's not RESTful at all (in ways far deeper than verb choice). And that's a good thing.


Doesn't it depend on the level of abstraction you see? The URI of the horn is known. The document is { remainingDuration: 1 }.


You don't want to make a new horn, but you want to make a new 'honk'


or a PUT rather ;P


Works with a cookie though.

Still, I'm gonna bet that someone's gonna find a way to abuse this in a hillarious way.


I think its worse than that. This invites accidental hilarious fails much more.


Let's talk bout the real reason this was posted: YOU CAN HONK THE HORN VIA A REMOTE API!


If anyone ever manages to penetrate the central VPN server which Tesla uses for its cars, this will be total mayhem.

Also, which server are they using? That alone is an interesting fact, as it has to support tens of thousands of simultaneous connections...


Nothing special about Tesla

Many of the other car manufacturers provide remote access to cars. See GM's OnStar, Ford's Sync Services, etc... One of those companies used to advertise on TV you calling them and having them unlock your car remotely and IIRC starting the engine.


The difference is that those services are optional and often opt-in, whereas with the Tesla it appears to be mandatory.

Personally, I'm not too fond of my car being accessible remotely unless it's me who has control over that access.


I doubt they're really opt-in, in the face of a hack. Having your car still connect to the network means that they can activate a new account instantaneously and without user intervention. It means they could potentially sell non-subscribers on a car unlock right on the spot, rather than saying, "tough luck, you should have subscribed to our service, after you get a locksmith to unlock your door, call us back and we can help stop it from happening again."

I would bet five Zimbabwe dollars that most systems of this type can be used to control the cars of non-subscribers if taken over.


The app server was Thin last I checked. It's a Ruby app, though probably not Rails (hopefully not, at least). The streaming stuff is a node.js server. I assume they have a load balancer in front of it all.

Keep in mind this isn't for the telematics, which are an entirely different system. This just gives you a view into some parts of that system. This is primarily used by the mobile apps, so the activity level is likely much lower than that.


It's good to know that cars can now be remotely controlled via CSRF attacks.


A company has an API FOR A CAR, and discussion devolves immediately into which characters should be at the start of the HTTP request.


How do these commands get invoked, and how do the commands get delivered to the individual cars? Is this something that people can invoke on the official Tesla web site after authenticating to it in some way, or is it something that people invoke on a web server running on their individual car?


The URL includes the car's ID number, strongly implying that this is a centralized service running in a data center, not a server running on the car's computer.


I can't wait for somebody to hack this and make every Tesla on the planet start honking at the same time. (Presuming there's a 3G hookup of some kind going on here)


Pretty sure this be a POST request.


Other discussion on this topic here: https://news.ycombinator.com/item?id=7961944


This API documentation has already been posted here twice today [1].

I remarked how non-RESTful this API is, which may have been the motivation for the title of this submission [2].

[1] https://news.ycombinator.com/item?id=7961944

[2] https://news.ycombinator.com/item?id=7962260


How should one RESTify methods? If my 'state' is represented as objects, and I want to execute a method on one of those [remote/server-side] object, what's the RESTful way of calling that method? I don't even know what RPC over HTTP should look like, let alone whether mixing it with REST would even be acceptable.


> let alone whether mixing it with REST would even be acceptable

Why wouldn't it be acceptable? Can you think about any reason? Because I can't. (And you could reach some very nice API independence by carrying RPC metadata at the REST API.)

The only thing I see here that I think is wrong is that the API uses GET when it should use other verbs. But lots of people already pointed that.


Holy fucking pedantics, It's too bad people are focusing on REST.

This API makes me want to have a Tesla. There are so many interesting apps/utilities that can be made with this!


Hm.. wondering if:

/vehicles/{id}/snooplion/hydraulics/bounce

is idempotent or not?


Watch Dogs anyone?


shouldn't this be a POST ?


imagine if this was stuck on loop. hopefully some rate limiting is already built in.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: