Unfortunately URLs are not encrypted when using HTTPS. There are cases when a GET request will have potentially sensitive information such as a filter with an email address or unique identifier in it. In this case it is best to use one of the other verbs that can have body like POST and put the filter in the body. I like the standard definition of a REST API but sometimes it does not match the real world.
There is no such thing as encrypted URLs. Encrypted parameter values, maybe.. I believe you're referring to SSL, which is the underlying transport protocol.
You may be referring to URLs being stored in unencrypted media such as logs. Yes never put sensitive data in a URL. But as others said, HTTPS encrypts everything going over it (except the host name in sni)
The hostname may not be encrypted: the DNS lookup probably isn't, and if you have an SNI capable user-agent, the hostname is sent over the channel in the clear so that the server can give you the matching cert; but the path and query aren't sent until SSL/TLS are finished.
It is still bad practice since the unencrypted URL can be stored in server logs which could be problematic depending on the application, security requirements, compliance requirements, etc. Unencrypted URLs are also stored in the browser history which would not matter unless the API is being called in the browser.
I'd rather go with 205 in cases where a resource is created/changed/deleted, it instructs the agent to reset its view of the resource which the request originated from.
And also I'd avoid 400 for invalid input in general, since it's meant to reject request entities with bad syntax, or incoming data that simply isn't HTTP.
IMO 422 is a better match, it indicates semantic errors.
The PATCH verb seems underspecified and warty to
me. Why not instead accept, on a PUT request, a Range header [1] whose byte-range-spec defines the range to be replaced in the document? Along with an entity consisting
of the partial content to use in the replacement, this seems to provide everything the PATCH verb does, plus a
complete absence of the ambiguity involved in "[description of changes]".
Say maybe thus:
GET /users/123 HTTP/1.1
Host: www.example.com
Connection: keep-alive
HTTP/1.1 200 OK
Content-Type: text/json
Content-Length: 41
{"name":"Joe","email":"joe@example.com"}
PUT /users/123 HTTP/1.1
Host: www.example.com
Connection: keep-alive
Range: 24-27
j.random.hacker
HTTP/1.1 200 OK
Content-Type: text/json; charset=ISO-8859-1
Content-Length: 53
{"name":"Joe","email":"j.random.hacker@example.com"}
How would you patch multiple fields? Using json to patch json is more reliable. Also, if somebody changes the email before your request, your request will modify the document into an invalid json.
You could handle multiple fields with Content-Type: multipart/byteranges and multiple byte-range-specs in the Range: header.
The versioning problem can be trivially handled by means of the entity tag mechanism [1]. Our notional RFC need only specify that servers supporting partial PUT requests must include an ETag header [2] in every GET response, and that a client issuing a partial PUT request on a given resource must include an If-Match header [3] with the entity tag it received in its most recent GET response.
The server can then compare the request's If-Match value with the current entity tag for the resource. If they match, the server updates the entity and responds with 204 No Content; otherwise, the server responds with 409 Conflict, whose response body is the complete entity and whose headers include the matching ETag, so that the UA can identify the conflict and present it to the user for resolution in whatever fashion it sees fit.
Your point regarding blind byte-range modification of structured data ("Using json to patch json is more reliable") is not without merit, but belongs at a higher level of abstraction than that at which HTTP operates. If you want to take the JSON document through a thaw-edit-freeze cycle, you can do it on the client and just PUT the result as a complete entity.
Byte-ranges aren't idempotent like complete documents and key/value pairs are. You would need a vector-clock reference as well as the byte-range to let the server resolve ambiguity in your byte-range.
This is where REST just breaks down. In any app I've written it always gets to the stage where I'm left with the choice of breaking away from a truly restful api, or firing off multiple requests. Sometimes REST wins, sometimes efficiency wins, but they really shouldn't be mutually exclusive choices.
This chart, for POST, has it returning the new user.
Strictly speaking, why would a POST return something other than status info and a URL for the created resource (if successful)?
The spec says:
If a resource has been created on the origin server, the response SHOULD be 201 (Created) and contain an entity which describes the status of the request and refers to the new resource, and a Location header (see section 14.30).
Is it assumed that the client will automatically follow that Location header and GET this resource? That would make some sense (perhaps most of the time) but that's different from having the POST request itself return the resource directly which is what's suggested by this chart.
An entity representing the state of the created resource does describe the status of the request, though its a particular verbose way of doing it in most cases.
It's potentially, with a large resource, a lot of wasted bits if all the client wants is status confirmation, but, in a strict request/response setup, it saves you a server roundtrip.
In SPDY / HTTP/2.0 it might make sense to send a smaller request that really is just a status response while pushing the actual resource to a client willing to accept it: in cases where the followup action would be to fetch the request, you won't need an extra roundtrip (though you will get a few extra bits of bandwidth for the intermediate response.)
Is there a good reason why so many API's avoid using PUT and DELETE? Take the Twitter API for example, they use POST /lists/destroy instead of DELETE. They are smart guys and clearly know how to design a RESTful API. What's their rationale?
Although this is a possible explanation, do you consume APIs using HTML forms? Probably not. And if you desperately have to consume APIs in the browser, you'd end up writing some JavaScript.
Although this is a possible explanation, do you consume APIs using HTML forms? Probably not. And if you desperately have to consume APIs in the browser, you'd end up writing some JavaScript.
Sure you can, although you need to do it via Ajax.
The W3C FORM element is specified with only 'get' and 'post' as permissible values for 'method', which I can only regard as a screwup on W3C's part, but I know of no similar restriction on the methods available to an XMLHttpRequest object; indeed at least one extremely well-regarded Stack Overflow answer [1] confirms that PUT and DELETE work as expected as of five years ago.
Imagine trying to fit a vault in a cubbyhole meant for shoes. That's what RESTful APIs end up fighting with. I would gander that because DELETE refers to permanent deletion, whereas destroy is reversible, they chose to use the less confusing verb.
The real problem with trying to conform to REST is that there's no rigorous definition, and this leads to the same verb being used for slightly different purposes among APIs.
There is a rigorous definition of REST; it's called RFC 2616. [1] That probably most people who implement it don't pay as much attention to it as they should doesn't make it any less existent.
How do you guys deal with "actions" in your API's that are not CRUD? Something like reserving an airline seat where you just want to pass in an id of a seat and a user id. I guess that's what PATCH would be for? I was unaware of this verb until today.
What I'm struggling with is that REST does not seem to fit with how we use the web today. These HTTP verbs were designed for a document centric era of the web, not for the complex processes we're modeling today. I'm not really seeing REST being easier to design or consume than RPC style web api's--isn't that the whole point?
I mean if you were designing an API to be consumed internally in Ruby/JAVA/C# etc, would you design it like REST? I wouldn't. Why have we all become convinced we need to do this for a web api?
So I'd have to POST an object that represents a process? It seems like you end up cluttering your code with objects to represent every process? Which in OO programming would just be a method call...
The point is to avoid implicit state. By treating the change in state as a first class citizen you can be explicit about the change. In my experience, managing state is very difficult in large applications. Most of the bugs I've dealt with have been the result of our design not being explicit enough.
What's so bad about implementing RPC via HTTP using Json or similar? Sticking to just REST "verbs" seems ridiculous to me... unless you're making yet another CRUD app, then I suppose it works out fine.
That doesn't diagram using HTTP verbs correctly, it diagrams using HTTP response codes.
And it's also wrong viewed in light of RFC 2616 (HTTP/1.1), at least with regard to PUT (particularly, it doesn't address the case where the spec indicates the server must use a 301 for a PUT.)
48 comments
[ 2.0 ms ] story [ 93.0 ms ] threadYour remark that "URLs are not encrypted when using HTTPS" does not match the real world.
It is still bad practice since the unencrypted URL can be stored in server logs which could be problematic depending on the application, security requirements, compliance requirements, etc. Unencrypted URLs are also stored in the browser history which would not matter unless the API is being called in the browser.
http://stackoverflow.com/questions/499591/are-https-urls-enc...
The status codes are:
/api/users:
GET 200 OK
POST 201 Created (or 205 thanks lgierth)
PUT 204 No Content
DELETE 405 Method Not Allowed
PATCH 204 No Content
/api/users/123:
GET 200 OK
POST 405 Method Not Allowed
PUT 200 OK
DELETE 204 No Content
PATCH 200 OK
return 404 if resource not found, or 410 Gone if you know it once existed
return 400 (or 422) and list of errors on invalid input.
return 401 if need to login.
return 403 if logged in but not allowed to do something.
return 409 Conflict on currency control issue.
I wish there was a BATCH keyword with some 10x/20x codes to enable pipelined HTTP methods. SPDY/HTTP2 should help with some of that.
http://httpstatus.es/205
IMO 422 is a better match, it indicates semantic errors.
http://httpstatus.es/400 http://httpstatus.es/422
Say maybe thus:
[1] http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14...The versioning problem can be trivially handled by means of the entity tag mechanism [1]. Our notional RFC need only specify that servers supporting partial PUT requests must include an ETag header [2] in every GET response, and that a client issuing a partial PUT request on a given resource must include an If-Match header [3] with the entity tag it received in its most recent GET response.
The server can then compare the request's If-Match value with the current entity tag for the resource. If they match, the server updates the entity and responds with 204 No Content; otherwise, the server responds with 409 Conflict, whose response body is the complete entity and whose headers include the matching ETag, so that the UA can identify the conflict and present it to the user for resolution in whatever fashion it sees fit.
Your point regarding blind byte-range modification of structured data ("Using json to patch json is more reliable") is not without merit, but belongs at a higher level of abstraction than that at which HTTP operates. If you want to take the JSON document through a thaw-edit-freeze cycle, you can do it on the client and just PUT the result as a complete entity.
[1] http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.1...
[2] http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14...
[3] http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14...
[1] https://news.ycombinator.com/item?id=6494134
DELETE /client/acme_inc/users
Strictly speaking, why would a POST return something other than status info and a URL for the created resource (if successful)?
The spec says:
If a resource has been created on the origin server, the response SHOULD be 201 (Created) and contain an entity which describes the status of the request and refers to the new resource, and a Location header (see section 14.30).
Is it assumed that the client will automatically follow that Location header and GET this resource? That would make some sense (perhaps most of the time) but that's different from having the POST request itself return the resource directly which is what's suggested by this chart.
But if we take that route at what point do we start telling people they're doing it wrong or that they're API isn't _really_ RESTful?
I'm inclined to think the answer is "never" and just encourage people to create APIs that are appropriate for the actual circumstances.
There are generally practical reasons to be RESTy, but "a foolish consistency" and all that comes into play as well.
It's potentially, with a large resource, a lot of wasted bits if all the client wants is status confirmation, but, in a strict request/response setup, it saves you a server roundtrip.
In SPDY / HTTP/2.0 it might make sense to send a smaller request that really is just a status response while pushing the actual resource to a client willing to accept it: in cases where the followup action would be to fetch the request, you won't need an extra roundtrip (though you will get a few extra bits of bandwidth for the intermediate response.)
The W3C FORM element is specified with only 'get' and 'post' as permissible values for 'method', which I can only regard as a screwup on W3C's part, but I know of no similar restriction on the methods available to an XMLHttpRequest object; indeed at least one extremely well-regarded Stack Overflow answer [1] confirms that PUT and DELETE work as expected as of five years ago.
[1] http://stackoverflow.com/a/166501/1713079
The real problem with trying to conform to REST is that there's no rigorous definition, and this leads to the same verb being used for slightly different purposes among APIs.
[1] http://www.w3.org/Protocols/rfc2616/rfc2616.html
POST is not - so possibly it's considered safer to use among muggles.
I also think PUT and DELETE are not cacheable, while POST is (given the right set of headers).
caveat: I might be completely wrong about my interpretation.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
What I'm struggling with is that REST does not seem to fit with how we use the web today. These HTTP verbs were designed for a document centric era of the web, not for the complex processes we're modeling today. I'm not really seeing REST being easier to design or consume than RPC style web api's--isn't that the whole point?
I mean if you were designing an API to be consumed internally in Ruby/JAVA/C# etc, would you design it like REST? I wouldn't. Why have we all become convinced we need to do this for a web api?
And it's also wrong viewed in light of RFC 2616 (HTTP/1.1), at least with regard to PUT (particularly, it doesn't address the case where the spec indicates the server must use a 301 for a PUT.)