ReST


Thanks Elkestein,org for explaining it like ReST fo Dummies (someone like me)! I read so much about it and people talked about it that sounded like a scary name to me, but this is like my baby kitty! :)

Like Web Services (e.g. SOAP & WSDL), REST offers no built-in security features, encryption, session management, QoS guarantees, etc. But also as with Web Services, these can be added by building on top of HTTP:

    * For security, username/password tokens are often used.
    * For encryption, REST can be used on top of HTTPS (secure sockets).
    * ... etc.

One thing that is not part of a good REST design is cookies: The "ST" in "REST" stands for "State Transfer", and indeed, in a good REST design operations are self-contained, and each request carries with it (transfers) all the information (state) that the server needs in order to complete it.

Sample phone book query with SOAP via user id
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope" soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:body pb="http://www.acme.com/phonebook">
<pb:GetUserDetails>
<pb:UserID>
12345
</pb:UserID>
</pb:GetUserDetails>
</soap:Body>
</soap:Envelope>

Equivalent in ReST terms is just a URL, this address itself should include everything e.g. user-id
http://www.acme.com/phonebook/UserDetails/12345

This can be achieved by simply configuring a web server to do URL Rewriting /UserDetails?id=12345

A nice analogy for REST vs. SOAP is mailing a letter: with SOAP, you're using an envelope; with REST, it's a postcard. Postcards are easier to handle (by the receiver), waste less paper (i.e., consume less bandwidth), and have a short content. (Of course, REST requests aren't really limited in length, esp. if they use POST rather than GET.)

But don't carry the analogy too far: unlike letters-vs.-postcards, REST is every bit as secure as SOAP. In particular, REST can be carried over secure sockets (using the HTTPS protocol), and content can be encrypted using any mechanism you see fit. Without encryption, REST and SOAP are both insecure; with proper encryption in place, both are equally secure.

RESTful applications use HTTP requests to post data (create and/or update), read data (e.g., make queries), and delete data. Thus, REST uses HTTP for all four CRUD (Create/Read/Update/Delete) operations.

While REST services might use XML in their responses (as one way of organizing structured data), REST requests rarely use XML. As shown above, in most cases, request parameters are simple, and there is no need for the overhead of XML.

    * One advantage of using XML is type safety. However, in a stateless system like REST, you should always verify the validity of your input, XML or otherwise!




some REST services:

(This is far from an exhaustive list.)

Here's a simple example: the following URL sends a REST request to Yahoo!'s web-search service: http://search.yahooapis.com/WebSearchService/V1/webSearch?appid=YahooDemo&query=rest. Click it, and observe the XML results, ready to be used directly, not wrapped in an SOAP "envelope" or other noise.

  • This REST request includes two parameters: "appid", used by Yahoo! to specify your application, and "query", which is the actual search query.
  • If you plan to make actual use of Yahoo!'s web-search service, make sure you create your own appid. See the documentation for details.
Another advantage of REST lies with performance: with better cache support (already built-in cache support at web server), lightweight requests and responses (no noise and extra headers), and easier response parsing (use which ever you like e.g. json, you are not bound to XML), REST allows for nimbler clients and servers, and reduces network traffic, too.


ReST in Java

public static String httpGet(String urlStr) throws IOException {
  URL url = new URL(urlStr);
  HttpURLConnection conn = (HttpURLConnection) url.openConnection();


  if (conn.getResponseCode() != 200) {
    throw new IOException(conn.getResponseMessage());
  }

  // Buffer the result into a string
  BufferedReader rd = new BufferedReader( new InputStreamReader(conn.getInputStream()));
  StringBuilder sb = new StringBuilder();
  String line;
  while ((line = rd.readLine()) != null) {
    sb.append(line);
  }
  rd.close();

  conn.disconnect();
  return sb.toString();
}

Remember that if the request URL includes parameters, they must be properly encoded (e.g., a space is %20, etc.). The class URLEncoder can be used to perform this encoding.

HTTP Post Encoding
public static String httpPost(String urlStr, String[] paramName, String[] paramVal) throws Exception {
  URL url = new URL(urlStr);
  HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  conn.setRequestMethod("POST");

  conn.setDoOutput(true);
  conn.setDoInput(true);
  conn.setUseCaches(false);
  conn.setAllowUserInteraction(false);
  conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

  // Create the form content
  OutputStream out = conn.getOutputStream();
  Writer writer = new OutputStreamWriter(out, "UTF-8");
  for (int i = 0; i < paramName.length; i++) {
    writer.write(paramName[i]);
    writer.write("=");
    writer.write(URLEncoder.encode(paramVal[i], "UTF-8"));
    writer.write("&");
  }
  writer.close();
  out.close();

  if (conn.getResponseCode() != 200) {
    throw new IOException(conn.getResponseMessage());
  }

  // Buffer the result into a string
  BufferedReader rd = new BufferedReader( new InputStreamReader(conn.getInputStream()));
  StringBuilder sb = new StringBuilder();
  String line;
  while ((line = rd.readLine()) != null) {
    sb.append(line);
  }
  rd.close();

  conn.disconnect();
  return sb.toString();
}

Java's support for handling web connections is pretty low-level.

A good solution can be found in the popular Apache Commons library, and in particular the httpclient set of packages. See Yahoo! guide to REST with Java for details and examples. The documentation covers several interesting extras, such as caching.


ReST in Javascript

//XMLHttpRequest: despite its name, neither the request nor the response has to involve XML.
function createRequest() {
  var result = null;
  if (window.XMLHttpRequest) {
    // FireFox, Safari, etc.
    result = new XMLHttpRequest();
    if (typeof xmlhttp.overrideMimeType != 'undefined') {
      result.overrideMimeType('text/xml'); // Or anything else
    }
  }
  else if (window.ActiveXObject) {
    // MSIE
    result = new ActiveXObject("Microsoft.XMLHTTP");
  }
  else {
    // No known mechanism -- consider aborting the application
  }
  return result;
}


var req = createRequest(); // defined above
// Create the callback:
req.onreadystatechange = function() {
  if (req.readyState != 4) return; // Not there yet
  if (req.status != 200) {
    // Handle request failure here...
    return;
  }
  // Request successful, read the response
  var resp = req.responseText;
  // ... and use it as needed by your app.
}

//Confusingly, you callback is actually invoked several times (up to four times, depending on the browser), during different stages of the client/server interaction. It is only the fourth and final stage that interests us; the readyState field can be used to test for the stage, as shown in the following code fragment
//if the response is an XML response (denoted by the server using MIME type text/xml), it can also be read using the responseXML property. This property contains an XML document, and can be used as such using JavaScript's DOM navigation facilities.
//Once we have created the request object and set up its callback function, it is time to issue the request:
req.open("GET", url, true);
req.send();
For POST requests, use:
req.open("POST", url, true);
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
req.send(form-encoded request body);

ReST in Perl
GET requests are pretty trivial with LWP, especially if you don't care much about setting headers in the request or reading headers in the response:
use LWP::Simple;

my $url = 'http://www.acme.com/products/3322';
          # ACME boomerang
my $response = get $url;
die 'Error getting $url' unless defined $response;

For more advanced features, you'll need to create a browser object, thus:
use LWP;
my $browser = LWP::UserAgent->new;
my $url = 'http://www.acme.com/products/3322';

# Issue request, with an HTTP header
my $response = $browser->get($url,
  'User-Agent' => 'Mozilla/4.0 (compatible; MSIE 7.0)',
);
die 'Error getting $url' unless $response->is_success;
print 'Content type is ', $response->content_type;
print 'Content is:';
print $response->content;

Issuing POST Requests
The same browser object defined above can be used to issue POST requests, too. Field names are directly mapped to values, thus:
my $response = $browser->post($url,
  [
   'firstName' = 'John',
   'lastName' = 'Doe'
  ],
);
die 'Error getting $url' unless $response->is_success;
Note that the UserAgent class allows you to easily set and read cookies, too, but these should be avoided in REST designs.