Implementing our GET handlers

Let's begin by implementing basic GET methods for our resources. You may recall that we mentioned before that a good REST API should at least implement two of them—GET by ID and GET all. Since we like to be standards-compliant, that is what we will use here.

Implementing a router

Our first order of business is to provide a way for our Node.js instance to differentiate between the different URLs that it receives requests for. Until now, our server only had to handle requests to its root URL (http://localhost:8080/), but in order to do something more interesting, we want to be able to generate custom responses for more specific URLs, such as http://localhost:8080/api/products.

Fortunately, Node.js again provides an out-of-the-box way to achieve this—the URL module.

Add the following just after the var http = require('http'); line:

var URL = require('URL');

This will import the URL module. We can now use it to break down the incoming requests and take action depending on how their URLs are structured.

Modify the http.createServer() call to look like this:

var server = http.createServer(function (req, res) {

  // Break down the incoming URL into its components
  var parsedURL = URL.parse(req.URL, true);

  // Determine a response based on the URL
  switch (parsedURL.pathname) {
    case '/api/products':
    // Find and return the product with the given id
    if (parsedURL.query.id) {
      findProductById(id, req, res);
    }
    // There is no id specified, return all products
    else {
      findAllProducts(req, res);
    }
    break;
    default:
    res.end('You shall not pass!');
  }
});

Note that we introduced two new methods, findAllProducts and findProductById. These are utility methods, which we will define separately. Along with them, we will define some generic helper methods to help make data access less cumbersome for us. Go ahead and add the following before the createServer() call:

// Generic find methods (GET)

function findAllResources(resourceName, req, res) {
  database.find('OrderBase', resourceName, {}, function (err, resources) {
  res.writeHead(200, {'Content-Type': 'application/json'});
  res.end(JSON.stringify(resources));
  });
};

var findResourceById = function (resourceName, id, req, res) {
  database.find('OrderBase', resourceName, {'_id': id}, function (err, resource) {
  res.writeHead(200, {'Content-Type': 'application/json'});
  res.end(JSON.stringify(resource));
  });
};

// Product methods

var findAllProducts = function (req, res) {
  findAllResources('Products', req, res);
};

var findProductById = function (id, req, res) {
  findResourceById('Products', id, req, res);
};

The generic methods are straightforward. They simply make use of the MongoDB interface that we created in Chapter 2, Configuring Persistence with MongoDB, in order to retrieve either all the documents from a specific collection, or just a single document by its ID. The specific product methods make use of these generic methods in order to find products in this fashion.

For the sake of brevity, we do not implement similar methods for the customer and order here; they are identical to the ones used for the product. Just change the name of the resource and add appropriate paths inside the createServer() method. You can see the complete example in the source code accompanying the book.

Implementing our POST handlers

We will now move on to adding handlers to create new instances of a resource. To do so, we need to distinguish not only between the URLs, but also between the request types. Modify your createServer() invocation so that it looks like the following:

var server = http.createServer(function (req, res) {

  // breaks down the incoming URL into its components
  var parsedURL = URL.parse(req.URL, true);

  // determine a response based on the URL
  switch (parsedURL.pathname) {
    case '/api/products':
    if (req.method === 'GET') {
      // Find and return the product with the given id
      if (parsedURL.query.id) {
        findProductById(id, req, res)
      }
      // There is no id specified, return all products
      else {
        findAllProducts(req, res);
      }
    }
    else if (req.method === 'POST') {

      //Extract the data stored in the POST body
      var body = '';
      req.on('data', function (dataChunk) {
        body += dataChunk;
      });
      req.on('end', function () {
        // Done pulling data from the POST body.
        // Turn it into JSON and proceed to store it in the database.
        var postJSON = JSON.parse(body);
        insertProduct(postJSON, req, res);
      });
    }
    break;
    default:
    res.end('You shall not pass!');
  }
});

Note that we have introduced another handler method, insertProduct(). We define it, along with its corresponding generic method, like we did before:

// Generic insert/update methods (POST, PUT)

var insertResource = function (resourceName, resource, req, res) {
  database.insert('OrderBase', resourceName, resource, function (err, resource) {
  res.writeHead(200, {'Content-Type': 'application/json'});
  res.end(JSON.stringify(resource));
  });
};

// Product methods

var insertProduct = function (product, req, res) {
  insertResource('OrderBase', 'Product', product, function (err, result) {
  res.writeHead(200, {'Content-Type': 'application/json'});
  res.end(JSON.stringify(result));
  });
};

Again, the implementation of this functionality for the other resources is the same, with the exception of the name. We do not replicate them here.

Implementing the DELETE and PUT handlers

Handling DELETE and PUT is analogous to handling a GET and POST request respectively, with the exception of the method being changed. Thus, we recommend that you refer to the accompanying source code to see the full implementation.

Testing the API

Until now, we have used a normal browser to poke at our API and see what it returns. However, this is far from optimal. Most browsers only make it easy to send GET requests, whereas an HTML form or something similar to it is needed in order to send POST requests. Let's not even get started with the DELETE and PUT requests.

To test the REST API, it is a much better idea to use a dedicated REST client, which will give you more options, make it easier to send requests, and thoroughly analyze responses. A very popular (and free) tool is Postman, which is a Chrome extension. It runs on all major operating systems. You can download it for free from https://www.getpostman.com/. The install process is very straightforward, and it will not be covered here.

Once you have installed Postman, start it up. Let's post away at our API. First, let's try asking the backend to send us all the products that it currently stores. Enter the products' root URL in Postman's URL field, make sure that GET is selected among the methods in the combobox to the right, and then click on the Send button. You should get something that looks like the following screenshot:

Testing the API

Now, let's try to POST a new product to the backend. Keep the same URL, but change the method to POST in the combobox to the right. Next, add some data before sending; select Raw from the button group under the URL field and enter the following:

Testing the API

Click on Send to fire off the request (note how much easier this is than using a plain browser). Finally, let's pull all the products again in order to make sure that the new product was indeed added:

Testing the API

That's it! Our API is working, and we are ready to start moving towards some serious usage.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.186.167