Thursday, 16 June 2016

How to build a REST Web API on a Raspberry PI in JavaScript

One of the most useful reasons for providing your Raspberry Pi with a REST API is to expose its inputs and outputs to a web client (on any iPhone, laptop or desktop PC anywhere in the world) for remote monitoring and/or control. This is part 1 of a 2 part blog showing how to implement a REST API in JavaScript.

What’s REST ?

In recent years, the Web has turned from a network of webservers serving mainly static pages to web browsers…

Web 1.0 – How the Internet was
…into a full client-server architecture, where single-page client web apps use AJAX principles to communicate with server-side applications, increasingly via simple but powerful RESTful APIs.

The Web as a client-server application framework

REST, AJAX and JAVASCRIPT

With REST, the idea is that, rather than using complex mechanisms such as CORBA, RPC or SOAP to connect between clients and servers, simple HTTP queries are used. RESTful applications use HTTP requests to POST data (create and/or update data), GET data (make queries), and delete data on the server. Thus, REST uses HTTP for all four CRUD (Create/Read/Update/Delete) operations.
AJAX is a popular web development technique that makes web pages interactive using JavaScript. In AJAX, requests are sent to the server using XMLHttpRequest objects. The response is used by the JavaScript code to dynamically change the current page. Each XMLHttpRequest can be viewed as a REST service request, sent using GET. And the response is often in JSON format.
For example, if our client application wants to get the ISBN for a book the user knows the title of, we might send our API server an HTTP GET with the URL :
http://www.myapiserver.com/books/ISBN/Catch-22
Using jQuery we can implement this AJAX request in our client application simply like this:
$.getJSON("http://www.myapiserver.com/books/ISBN/Catch-22", function(data) {
  console.log("The ISBN for this book is "+data );
 });
The HTTP reply our server sends back to the client is the raw result data — not embedded inside an HTML page, not XML-encoded, just the data you need in a way you can immediately use – a String or a JSON object you can use directly.
With REST, a simple network connection is all you need. You can even test the API directly, by typing the API URL into your browser. For instance, try out the twitter API by enteringhttps://api.twitter.com/1/statuses/home_timeline.json?include_entities=true in your browser. Because you haven’t included a key in your request, you will see an authentication error response in the browser window, encoded as a JSON object, which looks something like this:
{"errors":[{"message":"Bad Authentication data","code":215}]}
As you may have noticed in these examples, REST can easily handle more complex requests, including multiple parameters. In most cases, you’ll just use HTTP GET parameters in the URL.
For example, if we can only uniquely specify a book by both title and author, our API might accept a request like this: “http://myapiserver/books/ISBN?title=Catch-22&author=Heller”
As a convention, HTTP GET requests should be for read-only queries; they should not change the state of the server and its data. For creation, updating, and deleting data, use POST requests.

REST on the Raspberry Pi

Nodejs_logo_lightI’ve been using Node.JS as the backend (server-side) framework for building single-page or client-server web apps and more recently as a Javascript platform on my Raspberry Pi. On top of providing the advantage of an asynchronous, event-based programming model, it means I can code in he same language – Javascript – on  the frontend and the backend and on the Pi.
The Raspberry Pi as a Web Application server
To install Node.JS on your Raspberry Pi, see my earlier Blog post HOW TO INSTALL NODE.JS ON A RASPBERRY PI 
On the Raspberry Pi, we need to use the Node Package Manager npm to download and install the other modules we will need to build our web application. We will be using the express web application framework module initially, and also the connect module it depends on.
On your RPi, create a new directory for your project, and download the node modules you’ll need as follows :
$ mkdir myapp
$ cd myapp
$ npm init
$ npm install express --save
$ npm install connect --save
Or use the -g flag if you prefer the package to be installed globally, i.e. in /usr/local where node is installed, rather than in./node_modules. To install global packages, you need to use sudo to execute with superuser priviledges.
The node package manager will download and install the express framework.

Coding a RESTful API example on the Raspberry Pi

We’re now going to build an example client-server application using our Raspberry Pi as the server.
To build this full REST example, we need to create three source files on our Raspberry Pi: The server-side Javascript code, a simple HTML page, and some client-side Javascript.
myapi.js – our server-side Javascript code uses the Node and the Express framework to provide simplistic Web server functionality and to expose a RESTful API.
index.html – the HTML page which the browser loads from the Raspberry Pi and uses to render the presentation layer for our application.
myclient.js – Javascript code executed in the browser when our HTML page loads. This code implements the AJAX client functionality to call our API and render the results directly in the HTML page.
The application architecture looks like this:
Our Example – using Raspberry Pi as an App Server

MYAPI.JS: The Server(RPi)-side code

Now create a file called myapi.js on your Pi and copy the code below to build a simple  server in Javascript, which processes API requests on port 3000 with a JSON object. (Port 3000 is the standard port most commonly used for an express server).
First we need to let Node know we will be using the http and expresspackages,  call express to create our application server as an object, and assign it to a variable.
var http = require('http');
var express = require('express');

var app = express();
Next we will define an array of objects the client will be able to query….
var inputs = [{ pin: '11', gpio: '17', value: 1 },
              { pin: '12', gpio: '18', value: 0 }];
Then configure Express to serve index.html and any other static pages stored in the home directory, such as your myclient.js JavaScript source file
  app.use(express['static'](__dirname ));
Next we need to define the API middleware for our server-side application. We use express’s get function to define routes for the API calls and/or page requests to our server.
// Express route for incoming requests for a customer name
app.get('/inputs/:id', function(req, res) {
  res.status(200).send(inputs[req.params.id]);
}); 

// Express route for any other unrecognised incoming requests
app.get('*', function(req, res) {
  res.status(404).send('Unrecognised API call');
});

// Express route to handle errors
app.use(function(err, req, res, next) {
  if (req.xhr) {
    res.status(500).send('Oops, Something went wrong!');
  } else {
    next(err);
  }
});
Finally, start the server application, listening on port 3000:
app.listen(3000);
console.log('App Server running at port 3000');

INDEX.HTML: the homepage

Our web page simply displays a title, and sets up an input div as a placeholder that will be used by our  client-side JavaScript code in myclient.js to display the I/O values retrieved from our RPi.
<!DOCTYPE html>
<html lang="en">
 <head>
   <meta charset="utf-8" />
   <title>My Express API server example</title>
   <script src="http://code.jquery.com/jquery-latest.js"></script> 
   <script src="myclient.js"></script>
 </head>
 <body>
   <H1>My Express API server example</H1>
   <div id="input"></div>
 </body>
</html>

MYCLIENT.JS: the client-side code

this JavaScript code will be loaded and executed on the client machine when the browser loads our HTML page. It makes 2 calls to our API server running on the Raspberry Pi to retrieve and display the state of two inputs.
window.onload = function () {
  var url, 
      i,
      jqxhr;

  for (i = 0; i < 2; i++) {
    url = document.URL + 'inputs/' + i;
    jqxhr = $.getJSON(url, function(data) {
      console.log('API response received');
      $('#input').append('<p>input gpio port ' + data['gpio'] + ' on pin ' +
        data['pin'] + ' has current value ' + data['value'] + '</p>');
    });
  }
};

Download the Source Code

You can also download the full source code (client, server and html) for this example from github herehttps://github.com/fatkahawai/rpi-webapp-express
Create or download the three source files into a new folder on your RPi.

Running your Raspberry Pi Web App Server

To start up your web server on your RPi , invoke your application with node, from the folder you have saved the source files in.
$ node myapi.js
App Server running at port 3000
$
(Making sure that you have first installed the express module using npm, as already described above.)
Your web server is now running continuously in the background, waiting for API calls.
Finally, using another machine on the same local network, open a web browser and navigate to your App Server hosted on the RPi.
If your RPi has the local IP address 192.168.0.22, you would enter this in your browser:
http://192.168.0.22:3000
This will cause the browser to load your index.html file from your RPi, which then loads your javascript client code in myclient.js.
If you’re in luck, this should appear in your browser window:

What’s Next ?

One of the most useful reasons for providing your Raspberry Pi with a RESTful API is to expose its input and output ports to web clients for remote monitoring and control.
So in our next exercise, we will do just this, exposing the real GPIO I/O ports through a RESTful API, which will allow you to control your Pi’s inputs and outputs from any smartphone or PC wherever you are in the world.
I hope this exercise has been useful. If you have any feedback or spot any errors or omissions, feel free to leave a note in the comments section below.

No comments: