Currently browsing http


POST vs. PUT

Mon, 9 Nov 2009 16:07 UTC

This morning, Matthew writes about building RESTful services with the Zend Framework. I have a lot of thoughts on his post, and I might blog more about it later, but right now, I want to focus on David’s comment:

I think the next thing you should cover is how to retrieve put parameters and maybe even attempt to start a discussion on the different school of thoughts about POST vs PUT (Especially in the PHP world).

I know I’m even guilty of mentioning different schools of thought on POST vs. PUT in my talks, but the truth is that REST doesn’t specify what to use for what actions. These are defined by HTTP and not by REST.

Roy Fielding has this to say about the use of HTTP verbs in RESTful applications:

Some people think that REST suggests not to use POST for updates. Search my dissertation and you won’t find any mention of CRUD or POST. The only mention of PUT is in regard to HTTP’s lack of write-back caching. The main reason for my lack of specificity is because the methods defined by HTTP are part of the Web’s architecture definition, not the REST architectural style. Specific method definitions (aside from the retrieval:resource duality of GET) simply don’t matter to the REST architectural style, so it is difficult to have a style discussion about them. The only thing REST requires of methods is that they be uniformly defined for all resources (i.e., so that intermediaries don’t have to know the resource type in order to understand the meaning of the request). As long as the method is being used according to its own definition, REST doesn’t have much to say about it.

The POST vs. PUT debate, however, does rage on in different communities, and some protocols have defined their usage. For example, the Atom Publishing Protocol (RFC 5023) explicitly states in section 4.3 that “POST is used to create” and “PUT is used to edit.”

The important thing to note is that REST doesn’t care how the HTTP verbs are used, as long as they are used properly according to how they are defined in the protocol you are using.

For those interested, HTTP (RFC 2616) defines POST by saying:

The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line. […] The actual function performed by the POST method is determined by the server and is usually dependent on the Request-URI. The posted entity is subordinate to that URI in the same way that a file is subordinate to a directory containing it, a news article is subordinate to a newsgroup to which it is posted, or a record is subordinate to a database.

PUT is defined as:

The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.

With this line of thinking, you might come to the conclusion that POST is used for creation of a subordinate resource, while PUT could be used for both creation or modification of a resource. The important distinction is that POST identifies the resource for which the entity should be considered a subordinate; PUT does not.

Comments 10 Comments »  Permalink Permalink  Tags Tags: , , ,


php|tek 2009 Slides

Fri, 22 May 2009 21:39 UTC

Another php|tek come and gone. I’m saddened by leaving, but, as usually happens, I’m reinvigorated and reenergized to go back to work. It seems I need these events to get together with other developers to raise me up out of periods of burn-out. I’m sure the same goes for others.

I gave my talk this morning on “Making the Most of HTTP In Your Apps.” There was so much material to cover and so little time to cover it in, so I hope people found little nuggets of value in it for their own applications. I’ll be revising it in the future to show more actual code examples.

For your reference, I’ve provided the slides below for you to enjoy and download. Here’s the abstract of what the talk is about, and please don’t forget to rate my talk:

“200, 404, 302. Is it a lock combination? A phone number? No, they’re HTTP status codes! As we develop Web applications, we encounter these status codes and others, and often we make decisions about which ones to return without giving much thought to their meaning or context. It’s time to take a deeper look at HTTP. Knowing the methods, headers, and status codes, what they mean, and how to use them can help you develop richer Internet applications. Join Ben Ramsey as he takes you on a journey through RFC 2616 to discover some of the gems of HTTP.”

Comments 2 Comments »  Permalink Permalink  Tags Tags: , , , ,


Specifying rev=”canonical” With HTTP

Sun, 12 Apr 2009 6:15 UTC

It looks like there’s a lot of momentum behind rev=”canonical” now—and all built up within the span of about forty-eight hours. So, while I disagree with the use of “canonical” for semantic reasons and rev for the potential of mass misunderstanding and improper implementation, I think I’ll bite the bullet on this one for now, but time will tell what the community ultimately decides.

So, I’ve decided to eat my own dog food. Like Simon Willison, I bought my own short URL, and now all blog posts on my site include a link tag that covers all the bases similar to the following:

<link rev=”canonical” rel=”alternate shorter” href=”http://brtny.me/382” />

And all without any special WordPress plugin. For the ID, I’m simply using the WordPress post ID, which means that, if I change to another blogging tool in the future, I will need to maintain my indexes. Note that I’ve implemented it with both the popular rev=”canonical” and my preferred rel=”alternate shorter”.

Chris Shiflett posts about the need for an HTTP header. I think this is also a good idea, for the same reasons he mentions. Chris’s original recommendation is for an X-Rev-Canonical header, but Stephen Paul Weber mentions the Link header. I think the Link header is the right way to go about this, since it offers an HTTP analogue of the HTML link element.

Link is an IETF proposal by Mark Nottingham that is still in the Internet-Draft stage, going through the IETF process for standardization, but it’s current, which is a good thing. If the community chooses to use it, though, it’s interesting to note that that it states:

Applications that don’t merit a registered relation type may use an extension relation type. An extension relation type is a URI that, when dereferenced, SHOULD yield a document describing that relation type.

This means that one should not simply put rev=canonical as the value for rev. Instead, it would be more proper to use something like rev=”http://revcanonical.appspot.com/#canonical” until “canonical” is accepted as a registered IANA relation type. I wonder if the same is technically true of the rel and rev attributes in HTML.

For now, I’ve decided to cover all bases in my HTTP headers, as well, and you can see this by making a HEAD request to any blog post on my website, as seen in the following:

HEAD /archives/summarizing-my-revcanonical-argument/ HTTP/1.1
Host: benramsey.com

HTTP/1.1 200 OK
Date: Sun, 12 Apr 2009 05:24:34 GMT
Link: <http://brtny.me/382>; rev="http://revcanonical.appspot.com/#canonical"; rel="alternate http://revcanonical.appspot.com/#shorter"
X-Rev-Canonical: http://brtny.me/382
Content-Type: text/html; charset=utf-8

Comments 10 Comments »  Permalink Permalink  Tags Tags: , , , , , , , , ,


HTTP Status: 100 Continue Corrections

Mon, 16 Feb 2009 21:02 UTC

Last year, I wrote about the 100 Continue HTTP status code and the usage of the Expect header with the 100-continue expect value. However, I made a few erroneous statements, and a reader recently corrected me on them. So, I’m writing now to correct those statements so that I’m not misleading anymore readers.

The incorrect statements I made:

The service can then respond either “yes” (100 Continue) or “no” (417 Expectation Failed) with an explanation of why not.

Following that logic, I continued with:

Let’s say your service limits uploads to 100MB. In that case, you would return a 417 Expectation Failed including a reason for the failure in the body of the response.

This is incorrect behavior, and Glenn Maynard corrected it in his comments with:

This is incorrect. 417 means that an Expect you sent is unsupported; for example, if you send “Expect: bacon”, and the server doesn’t support that, then it responds with 417. Responding with 417 because the request was going to be too large badly violates the spec.

The purpose of 100-continue is to give the server a chance to give an error to the client before it sends the request body, rather than after. If doing that required that all of those detailed 4xx/5xx errors were turned into an opaque 417 and useless, plain language errors in the body, it would be useless.

Glenn is correct. What I missed in Section 14.20 of RFC 2616 was this: “The server MUST respond with a 417 (Expectation Failed) status if any of the expectations cannot be met or, if there are other problems with the request, some other 4xx status.” Furthermore, Section 8.2.3 states: “Upon receiving a request which includes an Expect request-header field with the ‘100-continue’ expectation, an origin server MUST either respond with 100 (Continue) status and continue to read from the input stream, or respond with a final status code.” (Emphasis added.)

My faulty logic occurred because I was using the “look-before-you-leap” (LBYL) concept presented in RESTful Web Services, in which Ruby and Richardson propose that a request including the Expect header can be made to determine whether the server will fulfill the request, given the headers present. They state, “if the answer is no, the server sends a status code of 417 (‘Expectation Failed’). The answer might be no because [...] 500 MB is just too big” (pg. 250). According to RFC 2616, this is wrong. If the server does not support the 100-continue expectation, then, and only then, should it send back the 417 Expectation Failed response. Otherwise, if, for example, the Content-Length is too big for the server to fulfill the response, then it would respond with a “final status code,” such as 413 Request Entity Too Large.

You may still use this approach to perform LBYL requests, but be sure to send back a proper 4xx status code, rather than a 417.

Furthermore, for another fallacy of mine, if you read the comments on the 100 Continue post, I also stated “be aware that the Content-Length header cannot be trusted.” Glenn also corrected me on this. I had assumed that I could spoof the Content-Length header, and that if the server only checked the Content-Length header to determine the size of the request entity, then it could be fooled, but this is not the case. Web servers use the Content-Length header to determine how much data to read from the entity body. If your Content-Length header is 50 MB and the entity body contains 100 MB, the server will read only the first 50 MB of the body and stop.

Comments 2 Comments »  Permalink Permalink  Tags Tags: , , ,


HTTP Status: Client Errors

Wed, 28 Jan 2009 4:27 UTC

The last post in my HTTP status code series was just over six months ago. I’m sorry for taking so long to revive the series, but I’m back with a discussion about the 4xx status codes. I hope you enjoy it!

The 4xx series of HTTP status codes is intended for client errors. That is, the server determines that there is an error occurring as a result of bad or missing data in the request from the client. The 404 Not Found status code is the most recognizable of these, and it’s the server’s way of telling the client that the requested URI is not available on the server. This is not the server’s fault, but, rather, it is the client’s, so the server responds saying, “Sorry, pal! I can’t find what you’re looking for.”

In an earlier post, I mentioned the 100 Continue status code. I mention it again here because the use of an Expect: 100-continue request header in a “look-before-you-leap” (LBYL) request can be useful to let you know of potential problems with your request before you receive any of these status code responses from the server.

Let’s use the same request from the 100 Continue post as an example:

POST /content/videos HTTP/1.1
Host: media.example.org
Content-Type: video/mp4
Content-Length: 105910000
Authorization: Basic bWFkZTp5b3VfbG9vaw==

...

Note that this request does not contain the Expect header, and it is assumed that the body of this request contains the full binary content of the video being posted.

For the sake of example, let’s assume that the server doesn’t allow POST requests to the /content/videos URI. If this is the case, then the server should return a 405 Method Not Allowed status code in response to this request. This is a condition that we could have checked for with the LBYL request prior to sending the full 105,910,000 bytes of the video, thus saving bandwidth, client resources, and server resources.

HTTP/1.1 405 Method Not Allowed
Date: Wed, 28 Jan 2009 03:04:25 GMT
Allow: GET,HEAD

In addition, to the 405 Method Not Allowed status, according to RFC 2616, the server must included an Allow header listing the valid methods for the requested resource. Sending the Allow header in response to HEAD requests (and all requests for that matter) can also help inform clients of acceptable methods.

If the server does allow POST requests at this URI but we fail to send the Authorization header with the request, then the server should respond with a 401 Unauthorized status, telling the client to resend the request with proper authorization. The server must include a WWW-Authenticate header in this response to indicate the expected authorization scheme. If the request, however, does include the Authorization header, as illustrated in the example, but the authentication fails for whatever reason, then the server should respond with a 403 Forbidden status and a description with the reason for the failure in the response body.

If the request doesn’t include the Content-Length header, then you might want the server to respond with a 411 Length Required status. Requiring the length and comparing it to the length of the actual request body is a good way to determine whether there was any loss of data. However, if the integrity of data is a concern, you might want to require clients to include the Content-MD5 header in the request. Since there is no status code to indicate Content-MD5 as a requirement, simply return a 400 Bad Request status stating your requirement of the Content-MD5 header in the response body.

The 400 Bad Request status code literally means that the “request could not be understood by the server due to malformed syntax,” but it is a generic enough response that it can be used for a variety of other client errors not covered by the other 4xx series status codes. For example, I have used 400 Bad Request as a way to indicate data validation failures in POST and PUT requests.

If the full request reaches the server, but the server determines that the 105,910,000 bytes of the video is beyond the acceptable limit—maybe we want to limit users to 50MB uploads—then respond with 413 Request Entity Too Large because the request body is larger than the server is willing to process. Again, the client could avoid this by using a LBYL request.

Likewise, if the server doesn’t want to support the video/mp4 media type, then it should respond with a 415 Unsupported Media Type status code. A LBYL request would have told us this, as well.

I’ve already discussed 416 Requested Range Not Satisfiable in a post about range requests and 417 Expectation Failed in a post about the 100 Continue status code.

Finally, we are all familiar with the 404 Not Found status code. I mentioned it earlier in this post. The 404 Not Found status, however, doesn’t tell the client whether the condition is temporary or permanent. It’s a pretty generic “I can’t find it” message. If you know that the resource is gone permanently, you may want to return a 410 Gone status code, instead, as a way of letting smart clients (like search engines) know that they should remove all links to the resource. If the resource has moved permanently, though, I recommend using a 301 Moved Permanently status, which will also tell these smart clients to update their links. How you choose to inform clients of the fate of your resources is up to you, but it’s in your best interest to tell them whether the data has moved or is gone and is no longer available.

I also mentioned the 404 Not Found and 410 Gone statuses when discussing the 201 Created and 202 Accepted status codes.

Comments 1 Comment »  Permalink Permalink  Tags Tags: , , ,


Welcome, New Year, and Other Miscellaneous Things

Sun, 25 Jan 2009 2:42 UTC

We’re well into the New Year—24 days to be exact—and I’ve long since been putting off this post, but it’s not really a single post. Instead, it’s a collection of things that I’ve been wanting to say but have been putting off, and it’s a look forward to things I’m working on, would like to see happen, or would like to be involved with this year. So, rather than the obligatory look back at what I did last year, this is a look forward at what I’m interested in for the coming year (in no particular order).

First of all, I would like to offer some congratulations to a handful of friends of mine. These congrats have been a long time coming from me and are already old news to many of you. In no particular order, I want to congratulate: Andrei Zmievski on being hired as an Open Source Fellow at Digg; Jon Tan on taking a role as the new Creative Director at OmniTI; Cal Evans, who moved to the Netherlands to be the Director of the PHP Centre of Expertise at Ibuildings; Marco Tabini and Keith Casey for launching Blue Parabola, and Matthew Turland for joining them; Eli White for accepting a position at Zend as the Zend Community Manager/Leader & DevZone Editor-In-Chief; and last, but not least, Brian DeShong for his promotion to Director of Technology at Schematic.

Next, I wanted to take a moment to mention and promote the writing I’ve been working on. I didn’t publish a single thing last year, and in 2007, I published only one article, so I resolved this year to get off my ass and remedy this. In February, php|architect will publish my article entitled “Grokking the REST Architectural Style.” This article attempts to explain what Representational State Transfer really is by going beyond peoples’ fascination with designing URLs, using XML, and focusing on HTTP methods. Instead, I’ll look at the real heart of REST with hopes that readers will fully understand what it means to build a RESTful application. A fellow web services aficionado said of the article, “I think you expressed very nicely what the concepts are all about—and without a URL or HTTP verb in sight!”

Following the REST article, in March php|architect will begin publishing my monthly column “From the Cloud.” In “From the Cloud,” I’ll be looking at practical web services you can use, as well as exploring trends that are transforming the way we use the Web. Here’s a quick blurb from the column that describes its focus:

As the Web matures and enters its third decade of life, many services are turning to cloud-based models of data storage. End users are becoming more and more comfortable with the notion that their data lives in the ether of the Internet rather than on their personal computers. Finding that data, retrieving it, manipulating it, and using it in meaningful ways are the challenges that face the era of the intelligent Web. I hope you’ll join me each month as we explore these services and technologies From the Cloud.

Finally, later this year, php|architect will publish another article I’m working on that will take a practical look at using HTTP in your applications in a RESTful way. There may also be a book idea or two in the works for me, but more on that later.

Oh, and I also had the privilege of being invited again to write a PHP Advent post during the month of December. I wrote a post entitled “Practice Safe & Idempotent Methods.”

Furthering my ramblings in this post, I also wanted to mention some community projects I’m working on this year. As always, I’d like to see PHPCommunity.org evolve and grow into a real website that offers real value to the PHP community, so that’s on my list of things to do. I’ll post more on that in the future. In addition, I have some plans for Atlanta PHP this year that include a new website, incorporation so we can accept donations, and an event to occur later in the year, but you’ll hear more from me about this as the details are finalized. Inspired by my own writings for the “From the Cloud” column, I’ll also be developing a PHP library of classes for interacting with various web services. This began with the Amazon Web Services library in PHP project, but I’ll be migrating that elsewhere to be part of a larger project in the near future, so be on the lookout for that.

Last, but not least, I wanted to mention the website that I built for my dad over the holidays. He recently launched his own business, Small Business Resource Associates, that provides services to small businesses and commercial real estate investors. I did all of the HTML/CSS and PHP programming for the website, while my aunt did the design work. It was an interesting project for me because I haven’t really touched front-end (client-side) web development in several years (I stick mainly to back-end, server-side development these days), and I was proud that I was able to make a website that validates successfully as XHTML 1.1. Another interesting part of the site is that it has a blog, something that I don’t believe many in the financial services industry are doing, so I think that’s one thing that sets apart Small Business Resource Associates from the competition. If your small business is looking for a loan, business plan, business consulting, SBA help, etc., please check it out.

Well, that’s a wrap. I’ve got a growing list of topics I want to blog about, so I hope that you’ll be hearing much more from me this year than you did last year.

Happy New Year!

Comments 1 Comment »  Permalink Permalink  Tags Tags: , , , , , ,


Slides from php|works & PyWorks

Wed, 3 Dec 2008 4:00 UTC

Here are the slides for my talk “You Look Like You Could Use Some REST!” given on the general track at php|works and PyWorks in Atlanta a few weeks ago. In my talk, I mentioned that I would be adding my notes from the talk to this blog post, but I’ve decided against doing that for the time being. However, I’ve been thinking about REST a lot lately, and I’ll use this blog in the near future to write some of these thoughts. I’m also working on a now overdue article on REST for php|architect, and I’m sure my editor would not like it if she knew I was blogging about REST instead of writing my article about it. I’ll announce that article here when it’s published so you can go snag a copy.

I will say this one thing, though: In my talk, I mentioned that the REST community doesn’t care much for content negotiation. I simplified the issue, though, because there are really two camps. On the one side, you have those who think content negotiation is the only way to go, and on the other side, you have those who prefer file extensions or query string parameters that denote the content type to return. There is actually an interesting discussion about a proposal to use a type attribute in the a tag in HTML 5 to tell the client what content-type to request for the resource identified by the URL in the href. It might look something like this:

<a type="text/html" href="/user/ramsey">Ben Ramsey</a>, 
<a type="application/pdf" href="/user/ramsey">Ben Ramsey (PDF)</a>

And with that, I leave you with the slides for my talk…

Representational State Transfer, or REST, has become the hip, new buzzword of Web 2.0. But what really makes an application RESTful? Is it pretty URLs? Or the use of XML over HTTP? Is it any web service that doesn’t use SOAP? In all of the hype, the definition of REST has become clouded and diluted.

It’s time to take a fresh look at REST. In this talk, Ben Ramsey reintroduces REST and its architectural style. He shows that REST is not only an architecture for web services but that it describes an architecture for the Web. Ramsey will demonstrate how statelessness, a resource-oriented architecture, atomicity of requests, and other traits of REST make the most of the Web’s architecture to provide scalable and simpler web services turning the Web into a platform by which rich clients can access and manipulate data.

Comments 1 Comment »  Permalink Permalink  Tags Tags: , , , ,


ZendCon 2008 Slides

Tue, 16 Sep 2008 23:25 UTC

See below for the slides from my Distribution and Publication With Atom Web Services talk given at the 2008 Zend PHP Conference and Expo in Santa Clara, CA.

As we move toward “Web 3.0,” the Web is slowly transforming into a platform upon which massively distributed applications run. Rich clients turn personal computers into thin clients, not storing or processing any data locally but, rather, connecting to a web service where the data resides. These services may target intranets, extranets, or the global Web community, but to work they need a common language. One such language is the Atom Publishing Protocol.

Since its inception as a draft recommendation in 2003, the Atom Syndication Format (RFC 4287) has been used as an alternative to Really Simple Syndication (RSS) feeds on blogs throughout the blogosphere. Most have understood Atom as just another feed format, but the publication of the Atom Publishing Protocol (RFC 5023) opens the door for far more uses of the Atom format as both a means for distribution of data, as well as publication.

Ben Ramsey will introduce the Atom Syndication Format and Atom Publishing Protocol, explaining in depth how these can form the foundation of any web service for publication and distribution of data in any environment, from the enterprise right down to the small business level. Ramsey will also discuss RESTful design principles as they relate to the Atom Publishing Protocol.

Comments 2 Comments »  Permalink Permalink  Tags Tags: , , , , , , , ,


HTTP Status: Redirection

Sun, 20 Jul 2008 22:58 UTC

I’ve been rather uninspired and, therefore, uninterested in blogging lately, which is why I’ve neglected to continue my series on HTTP status codes. However, while trying to figure out a quick and easy way to delete tons of received direct messages from my Twitter account, I stumbled across one of my HTTP pet peeves coupled with the odd use of a 3xx status code, which inspired me to launch into a short rant followed by a discussion on the redirection series of status codes.

First, the pet peeve: I cannot stand it when someone uses a GET request to modify information. I don’t care how secure it is because you’re checking my session and login details, sending a GET request to /direct_messages/destroy/30264861 should not do anything other that retrieve the resource located there. If using GET, the user agent thinks it’s a safe action and will not know that it should warn me that the action I’m about to take could modify information. CSRF anyone?

Come on, people! GET is a safe method. Client-side developers (among others) would do well to learn this.

Consequently, there is no resource at that location, and that also peeves me. Instead, I get a weird 302 Moved Temporarily HTTP redirect that also includes a Status: 302 Found header. WTF? Come on! It’s 2008. RFC 2616 has been out for nine years now. Is there anyone using Twitter on a user agent old enough that it only works for HTTP 1.0? (I’ll wager that I’ll get responses from people about how some mobile browsers only understand HTTP 1.0.)

This leads me to the second thing I want to discuss: HTTP redirections.

Historically (in HTTP 1.0), HTTP had two status codes for redirection: 301 Moved Permanently and 302 Moved Temporarily. However, 302 became misused and abused by user agents that didn’t follow the spec, which stated: “If the 302 status code is received in response to a request using the POST method, the user agent must not automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.” Instead, user agents would often simply use a GET request on the value of the Location header, redirecting the user without warning.

Take a moment now to think about this. Why would the user agent send a GET request for the value of the Location header without asking the user if it’s okay? Because the user agent thinks it’s safe to do so. Remember my earlier rant?

Nevertheless, the user agents weren’t supposed to be behaving this way, but developers used 302 Moved Temporarily as the common method for redirecting after POST actions, and following the spec would make for a cumbersome user experience, especially if I had to approve every single redirect that occurs after I POST something. (This actually happens on mobile browsers quite frequently, since the mobile browser—on my phone, at least (a RAZR)—properly implements the expected behavior, thus making a crappy experience for me.)

So, to rectify the situation, HTTP 1.1 introduced 303 See Other and then later 307 Temporary Redirect (changing the meaning of 302 to Found).

The 303 See Other status code unambiguously states that the value of the Location header “SHOULD be retrieved using a GET method” and that the “new URI is not a substitute reference for the originally requested resource.” That is, if the user agent originally used POST to send data, then the server can tell the user agent to safely redirect to another resource using GET, and the new resource should not be expected to act on the data sent in the original POST request.

Likewise, the 307 Temporary Redirect status code unambiguously states that if it is “received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.” So, if I POST a form to a server that sends back a 307 Temporary Redirect, then the user agent should ask me whether I want to proceed. If I say “yes,” then the user agent will proceed to POST the data to the URI identified by the Location header.

So, a couple rules of thumb: 302 Found is still the de-facto redirection method, though it may not mean what you want it to mean or behave properly on all user agents. If you want to process a POST request and then safely redirect the user agent using GET, use 303 See Other. If you want to redirect a POST request (that is, send the posted data to a different location), use 307 Temporary Redirect. If the original request was GET or HEAD, and you simply want to redirect the user agent, then either 302 Found or 307 Temporary Redirect are proper, though I prefer the 307.

To explicitly tell user agents (and particularly search engines and proxies) that something has moved permanently and that they should update their links, use 301 Moved Permanently .

Comments 6 Comments »  Permalink Permalink  Tags Tags: , , ,


HTTP Status: 204 No Content and 205 Reset Content

Wed, 7 May 2008 2:08 UTC

The 200 range of HTTP status codes represents successful requests. I’ve already covered 201 Created and 202 Accepted and 206 Partial Content. Today, I’ll wrap up my discussion of the 200 range by talking about 204 No Content and 205 Reset Content. The 200 OK response is probably the status with which most are familiar, and I’ll discuss it later when covering the HTTP verbs.

The 204 No Content response is useful in a web service when you want to return a success message but do not want to return a message in the body or do not have a body to return. In my personal experience, I use this when DELETE requests are sent to an Atom web service. If the resource is successfully deleted, the service returns a 204 No Content status message. This tells the client that the deletion was successful, and that’s really all the client needs to know. There’s nothing to return because it was deleted.

However, even outside of the web services realm, the 204 No Content status actually means something to a user agent (browser). The HTTP specification (RFC 2616) states the following about the 204 No Content status code:

If the client is a user agent, it SHOULD NOT change its document view from that which caused the request to be sent. This response is primarily intended to allow input for actions to take place without causing a change to the user agent’s active document view, although any new or updated metainformation SHOULD be applied to the document currently in the user agent’s active view.

This means that, if I have an HTML form and submit it, then, if the server returns a 204 status code, the browser should not refresh the form or take me to another page. The document view does not change, and I remain at the form. All of the data I entered remains unchanged. All browsers I tested support this, but, in practice, it is not very useful since there’s no indication to a user that anything happened on the server side.

However, consider the use of 204 No Content in an Ajax application. If the Ajax library used simply looks for a success message of 204 in response to the requests it sends, then it can present a success message to the user without changing any of the UI elements, as this response intends. This is also useful because the service doesn’t need to send back any data; it needs only tell the client that the request was successful.

On the other hand, with a 205 Reset Content response, the intent is to tell the client to clear the content from the form or to refresh the UI. That is, I could fill out a form, click the submit button, and the form I am currently working on would refresh to its default values if the client receives a 205 response. According to the HTTP spec, a 205 response means:

The server has fulfilled the request and the user agent SHOULD reset the document view which caused the request to be sent. This response is primarily intended to allow input for actions to take place via user input, followed by a clearing of the form in which the input is given so that the user can easily initiate another input action.

The problem is that I have not found a browser yet that supports this behavior. Browsers either treat a 205 like it’s a 204, or they simply treat it as a 200. This does not mean, though, that Ajax applications cannot properly respect a 205 response. In an Ajax application, if the client receives a 205 response (instead of a 204 response), then the UI elements should change back to their default state.

In RESTful Web Services, Richardson and Ruby make this distinction between 204 and 205:

In data entry terms: 204 is good for making a series of edits to a single record; 205 is good for entering a series of records in succession.

In my simple browser test to see what browsers supported 204 and 205 on forms (without using any Ajax), here’s what I found:

Firefox 2.0.0.14
  - 204 - supported
  - 205 - treated like 204

Safari 3.1.1
  - 204 - supported
  - 205 - treated like 200

Opera 9.27
  - 204 - supported
  - 205 - treated like 200

Internet Explorer 7 (7.0.5730.13)
  - 204 - supported
  - 205 - treated like 200

Internet Explorer 8 beta 1 (8.0.6001.17184)
  - 204 - supported
  - 205 - treated like 200

Firefox 3 beta 5
  - 204 - supported
  - 205 - treated like 204

Since I know I’ll be asked this question, to send back a 204 or 205 response with PHP, see the PHP manual on the use of the header() function. :-)

Comments 6 Comments »  Permalink Permalink  Tags Tags: , , ,