ChatGPT解决这个技术问题 Extra ChatGPT

REST API - why use PUT DELETE POST GET?

So, I was looking through some articles on creating REST API's. And some of them suggest using all types of HTTP requests: like PUT DELETE POST GET. We would create for example index.php and write API this way:

$method = $_SERVER['REQUEST_METHOD'];
$request = split("/", substr(@$_SERVER['PATH_INFO'], 1));

switch ($method) {
  case 'PUT':
    ....some put action.... 
    break;
  case 'POST':
    ....some post action.... 
    break;
  case 'GET':
    ....some get action.... 
    break;
  case 'DELETE':
    ....some delete action.... 
    break;
}

OK, granted - I don't know much about web services (yet). But, wouldn't it be easier to just accept JSON object through regular POST or GET (that would contain method name and all parameters) and then respond in JSON as well. We can easily serialize/deserialize via PHP's json_encode() and json_decode() and do whatever we want with that data without having to deal with different HTTP request methods.

Am I missing something?

UPDATE 1:

Ok - after digging through various API's and learning a lot about XML-RPC, JSON-RPC, SOAP, REST I came to a conclusion that this type of API is sound. Actually stack exchange is pretty much using this approach on their sites and I do think that these people know what they are doing Stack Exchange API.

Why force a JSON payload? What if there's no JSON, and it's a plain old GET?

j
jere

The idea of REpresentational State Transfer is not about accessing data in the simplest way possible.

You suggested using post requests to access JSON, which is a perfectly valid way to access/manipulate data.

REST is a methodology for meaningful access of data. When you see a request in REST, it should immediately be apparant what is happening with the data.

For example:

GET: /cars/make/chevrolet

is likely going to return a list of chevy cars. A good REST api might even incorporate some output options in the querystring like ?output=json or ?output=html which would allow the accessor to decide what format the information should be encoded in.

After a bit of thinking about how to reasonably incorporate data typing into a REST API, I've concluded that the best way to specify the type of data explicitly would be via the already existing file extension such as .js, .json, .html, or .xml. A missing file extension would default to whatever format is default (such as JSON); a file extension that's not supported could return a 501 Not Implemented status code.

Another example:

POST: /cars/
{ make:chevrolet, model:malibu, colors:[red, green, blue, grey] }

is likely going to create a new chevy malibu in the db with the associated colors. I say likely as the REST api does not need to be directly related to the database structure. It is just a masking interface so that the true data is protected (think of it like accessors and mutators for a database structure).

Now we need to move onto the issue of idempotence. Usually REST implements CRUD over HTTP. HTTP uses GET, PUT, POST and DELETE for the requests.

A very simplistic implementation of REST could use the following CRUD mapping:

Create -> Post
Read   -> Get
Update -> Put
Delete -> Delete

There is an issue with this implementation: Post is defined as a non-idempotent method. This means that subsequent calls of the same Post method will result in different server states. Get, Put, and Delete, are idempotent; which means that calling them multiple times should result in an identical server state.

This means that a request such as:

Delete: /cars/oldest

could actually be implemented as:

Post: /cars/oldest?action=delete

Whereas

Delete: /cars/id/123456

will result in the same server state if you call it once, or if you call it 1000 times.

A better way of handling the removal of the oldest item would be to request:

Get: /cars/oldest

and use the ID from the resulting data to make a delete request:

Delete: /cars/id/[oldest id]

An issue with this method would be if another /cars item was added between when /oldest was requested and when the delete was issued.


@Andre it's a combination of a number of reasons: Following the HTTP guidelines means that you'll (probably) have fewer backwards compatibility issues when things change; using an html form via POST will warn the user for multiple submissions of the same data (this is to prevent a non-idempotent transaction); following a well-defined best practice is, well..best practice. Rest isn't defined with a specific implementation in mind, which allows you to use it as you see fit. I'd suggest taking advantage of all of HTTP's error codes and request methods, but you're allowed to do it however you want
So the problem with this answer (it is a decent answer, but not complete) is that it doesn't address the main question he asked: Why you'd use HTTP verbs and the URI rather than custom JSON data (maybe some sort of JSON-based API invocation syntax). You can make your custom JSON syntax so that it is "immediately ... apparant what is happening with the data". What you can't do is easily use built-in facilities and network layerings on top of HTTP like you can with an API that follows all of the REST conventions. Not that my answer is perfect, of course ;)
@Andre: The examples the wiki entry uses are authentication, caching and content type negotiation. Now that I am thinking more about it, you may be able to use these with RPC style interfaces, but the temptation will often be to implement your own system from scratch, or code up an integration to an existing system. With REST you can use the built-in integration, and administrate it on the web server. This means looser coupling, which means you have to implement less, and means your app is way more flexible to change options in the future with lesser code and test impact.
Instead of DELETE: /cars/oldest, how about GET: /cars/oldest followed by a DELETE? That way, you have two separately idempotent commands.
+1; I agree this is a good answer (I'm going over it again for fun and profit). POST: /cars/oldest being a replacement for a DELETE doesn't make a lot of sense. Something like - POST: /cars/oldest/delete might, tho I think I like Neil's solution better. The only advantage a direct delete gives over his get-id-delete-id solution is atomicity. I'd want a clear business justification with a non-contrived scenario before I'd implement such a thing. You don't need to support all verbs on all objects/urls.
M
Mike DeSimone

This is a security and maintainability question.

safe methods

Whenever possible, you should use 'safe' (unidirectional) methods such as GET and HEAD in order to limit potential vulnerability.

idempotent methods

Whenever possible, you should use 'idempotent' methods such as GET, HEAD, PUT and DELETE, which can't have side effects and are therefore less error prone/easier to control.

Source


Sorry, but how are PUT and DELETE idempotent methods? They affect the state of the server and its data!
@Computer: Doing the same PUT or the same DELETE results in the same final state. That is what "idempotent" means.
For more clarification: an operation F is idempotent, if its single application and its several consequent applications both return the same result. More precisely F is idempotent if and only if F(x)=F(F(x)). For example, Delete is idempotent, because when you delete an item once, or delete it several times, the result is the same: the item is deleted just once with the delete first application and nothing happens in the delete second or third application.
But in terms of creation, when you create a new record with a create command, and issue the same command again, two record is (probably) created (though both reflecting the same information).
qartal -- your functional definition for idempotent should be 'F(X) = F(X)F(X)'. Nice way to phrase it though.
N
Neil

In short, REST emphasizes nouns over verbs. As your API becomes more complex, you add more things, rather than more commands.


I had a bit of trouble getting my head round this. This post (lornajane.net/posts/2013/…) that the verb should be coming from the HTTP request so that the URI should then only contain nouns cleared it up a tad for me
M
Merlyn Morgan-Graham

You asked:

wouldn't it be easier to just accept JSON object through normal $_POST and then respond in JSON as well

From the Wikipedia on REST:

RESTful applications maximize the use of the pre-existing, well-defined interface and other built-in capabilities provided by the chosen network protocol, and minimize the addition of new application-specific features on top of it

From what (little) I've seen, I believe this is usually accomplished by maximizing the use of existing HTTP verbs, and designing a URL scheme for your service that is as powerful and self-evident as possible.

Custom data protocols (even if they are built on top of standard ones, such as SOAP or JSON) are discouraged, and should be minimized to best conform to the REST ideology.

SOAP RPC over HTTP, on the other hand, encourages each application designer to define a new and arbitrary vocabulary of nouns and verbs (for example getUsers(), savePurchaseOrder(...)), usually overlaid onto the HTTP 'POST' verb. This disregards many of HTTP's existing capabilities such as authentication, caching and content type negotiation, and may leave the application designer re-inventing many of these features within the new vocabulary.

The actual objects you are working with can be in any format. The idea is to reuse as much of HTTP as possible to expose your operations the user wants to perform on those resource (queries, state management/mutation, deletion).

You asked:

Am I missing something?

There is a lot more to know about REST and the URI syntax/HTTP verbs themselves. For example, some of the verbs are idempotent, others aren't. I didn't see anything about this in your question, so I didn't bother trying to dive into it. The other answers and Wikipedia both have a lot of good information.

Also, there is a lot to learn about the various network technologies built on top of HTTP that you can take advantage of if you're using a truly restful API. I'd start with authentication.


P
Pawel Cioch

In regards to using extension to define data type. I noticed that MailChimp API is doing it, but I don't think this is a good idea.

GET /zzz/cars.json/1

GET /zzz/cars.xml/1

My sound like a good idea, but I think "older" approach is better - using HTTP headers

GET /xxx/cars/1
Accept: application/json

Also HTTP headers are much better for cross data type communication (if ever someone would need it)

POST /zzz/cars
Content-Type: application/xml     <--- indicates we sent XML to server
Accept: application/json          <--- indicates we want get data back in JSON format  

C
Community

Am I missing something?

Yes. ;-)

This phenomenon exists because of the uniform interface constraint. REST likes using already existing standards instead of reinventing the wheel. The HTTP standard has already proven to be highly scalable (the web is working for a while). Why should we fix something which is not broken?!

note: The uniform interface constraint is important if you want to decouple the clients from the service. It is similar to defining interfaces for classes in order to decouple them from each other. Ofc. in here the uniform interface consists of standards like HTTP, MIME types, URI, RDF, linked data vocabs, hydra vocab, etc...


H
HumbleWebDev

Good Semantics is important in programming.

Utilizing more methods besides GET/POST will be helpful because it will increase the readability of your code and make it easier to maintain.

Why?

Because you know GET will retrieve data from your api. You know POST will add new data to your system. You know PUT will make updates. DELETE will delete rows etc, etc,

I normally structure my RESTFUL Web Services so that I have a function callback named the same thing as the method.

I use PHP, so I use function_exists (I think its called). If the function doesn't exist, I throw a 405 (METHOD NOT ALLOWED).


B
Bimal Das

Bill Venners: In your blog post entitled "Why REST Failed," you said that we need all four HTTP verbs—GET, POST, PUT, and DELETE— and lamented that browser vendors only GET and POST." Why do we need all four verbs? Why aren't GET and POST enough?

Elliotte Rusty Harold: There are four basic methods in HTTP: GET, POST, PUT, and DELETE. GET is used most of the time. It is used for anything that's safe, that doesn't cause any side effects. GET is able to be bookmarked, cached, linked to, passed through a proxy server. It is a very powerful operation, a very useful operation.

POST by contrast is perhaps the most powerful operation. It can do anything. There are no limits as to what can happen, and as a result, you have to be very careful with it. You don't bookmark it. You don't cache it. You don't pre-fetch it. You don't do anything with a POST without asking the user. Do you want to do this? If the user presses the button, you can POST some content. But you're not going to look at all the buttons on a page, and start randomly pressing them. By contrast browsers might look at all the links on the page and pre-fetch them, or pre-fetch the ones they think are most likely to be followed next. And in fact some browsers and Firefox extensions and various other tools have tried to do that at one point or another.

PUT and DELETE are in the middle between GET and POST. The difference between PUT or DELETE and POST is that PUT and DELETE are *idempotent, whereas POST is not. PUT and DELETE can be repeated if necessary. Let's say you're trying to upload a new page to a site. Say you want to create a new page at http://www.example.com/foo.html, so you type your content and you PUT it at that URL. The server creates that page at that URL that you supply. Now, let's suppose for some reason your network connection goes down. You aren't sure, did the request get through or not? Maybe the network is slow. Maybe there was a proxy server problem. So it's perfectly OK to try it again, or again—as many times as you like. Because PUTTING the same document to the same URL ten times won't be any different than putting it once. The same is true for DELETE. You can DELETE something ten times, and that's the same as deleting it once.

By contrast, POST, may cause something different to happen each time. Imagine you are checking out of an online store by pressing the buy button. If you send that POST request again, you could end up buying everything in your cart a second time. If you send it again, you've bought it a third time. That's why browsers have to be very careful about repeating POST operations without explicit user consent, because POST may cause two things to happen if you do it twice, three things if you do it three times. With PUT and DELETE, there's a big difference between zero requests and one, but there's no difference between one request and ten.

Please visit the url for more details. http://www.artima.com/lejava/articles/why_put_and_delete.html

Update:

Idempotent methods An idempotent HTTP method is a HTTP method that can be called many times without different outcomes. It would not matter if the method is called only once, or ten times over. The result should be the same. Again, this only applies to the result, not the resource itself. This still can be manipulated (like an update-timestamp, provided this information is not shared in the (current) resource representation.

Consider the following examples:

a = 4; a++;

The first example is idempotent: no matter how many times we execute this statement, a will always be 4. The second example is not idempotent. Executing this 10 times will result in a different outcome as when running 5 times. Since both examples are changing the value of a, both are non-safe methods.


About the example of a new page, shouldn't POST be used in that manner, while PUT for an update? Creating a new page is a process that yelds a new result every time, while the same edit may be rePUTted any amount of times, yelding the same result every time. Nice phrasing and explanation, though.
M
M-A-X

Basically REST is (wiki):

Client–server architecture Statelessness Cacheability Layered system Code on demand (optional) Uniform interface

REST is not protocol, it is principles. Different uris and methods - somebody so called best practices.