REST – Can You do More than Spell It? Part 4
In the previous parts of this series, you learned what REST is, how to develop a RESTful application, and how to consume RESTful services. We’re getting close to the end now, and the only thing remaining is to discuss a little more about the protocol you’ll most likely use in any RESTful application that you write. Because HTTP is so often used with REST, that’s the protocol I’d like to focus on.
HTTP Header Fundamentals
In a generic sense, I usually envision a single entity when I hear the word “header”, usually around 780 characters in length with about 50 parameters embedded in it where if you screw up one them up then whole thing doesn’t work. I also think of a header as being something that is set and proscribed by a standard. The standard specifies what values are sent with the header and you don’t have much control over the values or formatting. And there is generally only one header per transaction. But HTTP headers aren’t really like all of that.
Format of a Header
First, they tend to be very short.
Second, every HTTP header contains only one characteristic (which is why they tend to be short).
Third, you will have multiple header lines, exactly how many depend on how much information you want to pass along with the request.
In its simplest form, each header consists of two main things components: an identifier or characteristic, and a value, with a colon separating the two so there’s no hanky panky going on. There’s no semicolon to end the header but, as you’ll see in a few paragraphs, if you have more than one value for the identifier then the different values are separated by a semi-colon.
Here’s a couple of very simple HTTP headers to get your feet wet:
User-Agent: Safari 5.2 Accept: */*
The first header one identifies the user agent (typically a web browser) that is making a request. The second indicates that when data is returned from the server, the user agent will accept all types of content. In both cases the specific characteristic is identified, followed by a colon, followed by the value you want it to have.
There are plethora of different headers that can be sent and received, and specifically which ones that will be used will depend on what your requirements are. Perhaps you will be the one who decides exactly which headers will be sent and what values will be attached to those headers… or perhaps you won’t care, much like the millions of people each day using a web browser.
But remember how I said “in its simplest form”? That should have been a very clear warning that things can get more complicated (or flexible), and indeed that is the case for most real-world usage.
Sometimes you may not want to just specify a single value for a characteristic. For example, consider the language a resource can be returned in. Maybe you prefer American English, but you’re a tolerant fellow accepting British English as well, and maybe Italian.
If you just wanted American English, then the
Accept-Language header would be simple:
To also accept British English and Italian, you use more complex notation, namely:
Accept-Language: en-us; en-gb,q=0.8; it,q=0.3
As I’ve already said, the colon separates the characteristic from its value. The semicolon separates multiple values from each other. Here
q is a preference value that can ranging between 0 and 1 to give the server some sort of indication of how strongly you prefer one value over another. In the above example you’re requesting American English. But, if that is not available, you are willing to accept British English or Italian, but with a greater preference of British English over Italian if both are available.
The “Status” Header
There is always at least one header that will be present in a response, and that’s the status header. But unlike the format of the headers I’ve just explained, the status header is unique.
The status line consists of three pieces of information; the version of HTTP that was used, The three digit status code of the request, and a short description of what that status code means. For example,
HTTP/1.1 200 OK
There are quite a few values for the status code and a full set can be seen on Wikipedia. The basic breakdown of values however falls into the following classes.
- 1XX – Informational
- 2XX – Success
- 3XX – Redirection
- 4XX – Client Error
- 5XX – Server Error
Obviously, you want to keep a close eye on the status code and not just assume that everything is going to come back OK, just as you would check the return code on any program IO.
There are a large number of different headers that you can use, most with it’s own characteristic verbiage. For a full list of what these are, you can again check out Wikipedia which breaks them down into Request headers and Response headers. For even more detail, look at the HTTP 1.1 Standard. Some of the most common headers, as listed in the book PHP Master: Write Cutting-edge Code are:
Accept– the format the client wants the response to be in.
Accept-Language– languages that are acceptable for the response.
Accept-Encoding– which encoding the client supports.
Content-Type– format of the response.
Content-Encoding– encoding of the response.
Content-Language– language of the response.
Content-Length– the size of the response.
Set-Cookie– cookie data included in the response for use later.
Cookie– cookie data from an earlier request being sent with this one.
Expires– when content will no longer be available.
Authorization– access information for protected resources.
While you’ll probably never use most of the headers, you should still familiarize yourself with the entire list. Sometimes knowledge is it’s own reward.
Headers with PHP
So what does all this have to do with PHP? Well, if you plan on doing anything worthwhile with REST using HTTP, you’ll probably want to be able to send and receive headers. First, let’s start with an outbound response from PHP.
It is imperative that headers be sent before the actual response. The reason is that headers are just plain text and there is no magic that would differentiate between the headers and response body if they were mingled. Its a gentlemen’s agreement that headers will be sent first and all but creatures with the blackest of hearts abide by this rule.
To send a header from PHP to the user agent you use the
header() function. For example:
<?php header("Content-Language: en-AU");
It really is that simple, mate! The header is enclosed in quotes because it’s a string and slapped into the function’s parenthesis zone. Oh, and since its a PHP statement, there is a semicolon at the end.
You can send whatever headers you feel like for whatever you want to tell the user agent that is getting back the response. Want to set a date/time after which the response should be treated as stale? Use an
Expire header. Want to have the user agent interpret the response as a PNG image? Send a
Content-Type header. You can send whatever and however many headers you like, just before to send them before the response body.
The headers you send with a request can be used to tell the server more about the resource you are looking for. Let’s take the following example: we have a RESTful resource,
example.com/user/42 that contains basic information on someone. But do you want information returned as an XML document? Or maybe you want just the profile picture of the individual it represents? The
Accept header can further refine the representation details of the resource.
<?php $uri = "http://example.com/user/42"; $ch = curl_init(); // request XML representation of user curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/xml")); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_GET, true); $xml = curl_exec ($ch); // request image representation of user curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: image/jpg")); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_GET, true); $jpg = curl_exec ($ch);
The advantage that such headers give us is that we can create one resource, such as
example.com/user/42, but have multiple ways to represent it without having to define multiple resources for each type (such as
example.com/user/42.html). This is a nice, RESTful approach that keeps the URI pure and takes full advantage of the protocol used.
Custom HTTP Headers
As you’ve seen, there are many HTTP headers already defined. And you would think that would be enough. But no, no amount of headers is ever enough for some people, and so HTTP also allows you to define your own custom headers.
What kind of thing might you put in a custom header? It could be almost anything. Maybe you want the location of the server to be returned to the client. To be honest, figuring out what you want that is not already in a standard header seems to be more your problem than mine. It’s almost midnight here and I think you really need to take some initiative here!
One thing you’ll want to keep in mind though is that you’ll still need to define the custom header within the context you are working in. That is, a custom header is in a sense like a local variable and will have meaning only within a certain space. Both the web server and the client need to agree its meaning in relation to the request.
Custom headers seem to be a bit controversial with some developers concerned about their proliferation because there are no real standard for them. Some people prefer prefixing the verbiage with “x-”, and others think it’s not a good idea in case such a custom header were to ever find its way into the standard.
So, custom headers are bad, right? Well, not necessarily. As it turns out some of the big players like Google and Oracle, have defined a set of their own customer headers that can be used with their REST APIs. So, maybe they aren’t the devil after all.
As you can see, HTTP headers are swell, providing a great deal of information both to and from the server, and doing so in a simple format that is right to the point. And, these headers are easy to set up and use in PHP.
You see, I told you everything would work out for the best. Although, now that I think of it, I actually never said that. And, based on my life so far, the idea of everything working out for the best seems just plain silly. But no matter how you slice it, REST is a solid alternative for much of your web application building needs, and something that you owe it to yourself to understand. Thanks for joining me in this four-part series, and I hope now you know more about REST than just how to spell it.