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…

web10

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.

web20

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.someapiserver.com/books/ISBN/Catch-22

Using jQuery we can implement this AJAX request in our client application simply like this:

$.getJSON("http://www.someapiserver.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 entering the API call http://api.exip.org/?call=ip directly in your browser; the API server at api.exip.org will return the public IP address of your machine (not the same as the private IP address issued to your PC by your Router’s DHCP service, which you will see when you run ifconfig at the command  line, or displayed in your network settings). Or try out the twitter API by entering https://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.

REST for RPiThe 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:

REST API on RPI

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 express packages,  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>
   http://code.jquery.com/jquery-latest.js 
   http://myclient.js
 </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 here https://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:

Screen Shot 2013-05-08 at 6.30.41 PM

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.

Next

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.

47 comments

  1. Dave Matthews

    G’day, I was wondering is there a step missing somewhere there between installing express and using it? I installed it with the -g option, and I have put the three files together and gone to start the node server and I got an error:
    module.js:340
    throw err

    Error: Cannot find module ‘express’

    express seems to be installed in the correct location (I think)
    /usr/local/bin/express -> /usr/local/lib/node_modules/express/bin/express
    express@3.3.4 /usr/local/lib/node_modules/express

    The previous Hello World example worked without a hitch. Any ideas?

  2. zariapps

    HI,
    I tried the above.. the myapi.js didn’t start at first. After lots of googling it turns out one should create a new directory called node in /usr/local/lib and copy the directories express and npm from node_modules inside node. After having done that, the server started ok, but when I navigate to the http://myraspipy:3000 I get the error message: Unrecognised API call. Could you please provide a solution? Thanks

  3. Scott Newberry

    This is a fantastic guide. Perhaps I’m missing something but I cannot seam to find the link to the second part of the tutorial.

    I only have one recommendation to people following it, if you are going to try and be clever like i did and type out the code, make sure you have no typos……4 hours of bashing my head against my desk my friend kindly told me “oh, you’re missing the ‘s’ off the end of the variable ‘inputs'”….

  4. Allen Essensa

    What a great tutorial! Great explanation of the concepts and implementation. Thanks much for taking the time and effort to put this together Can’t wait to try this out and learn more.

  5. Kieron

    Really great tutorial. I had a few problems installing Node on my Pi but picked that up somewhere else and then came back to this. Ive found this a great launch pad. Thanks for putting this together.

  6. dv

    1. express4 deprecates configure and send(body,status)… remove configure, use send(status).send(body)
    2. favicon is not bundled anymore… remove the line
    2. you’re incoming request routing node part contains missing characters… idunction
    3. you’re javascript clientside script is flawed aswell. again missing characters .. ixhr

    but it did set me on the path forward, so thx for that

  7. Shane

    Hey great tutorial

    you have a typo in you myapi.js

    // Express route for incoming requests for a customer name

    app.get(‘/inputs/:idunction(req, res){ res.send(inputs[req.params.id]); });

    should be

    app.get(‘/inputs/’, function(req, res){ res.send(inputs[req.params.id]); });

  8. Boxwood

    Your comment is awaiting moderation.

    Confused by the npm -init step.
    There’s no instructions as to how it should be setup?
    Do I need a README.md file? What about scripts?
    Can I just leave it all blank and be okay?

      • ceeb

        usually in response to the prompts you’ll want to enter a description of your project, your name and email address as “author”, and e.g. “MIT” as the “licence type”. And you’ll have a github repository for your project you can enter a link to.

  9. Jack

    Can you explain why in index.html you are calling the following web address “http://code.jquery.com/jquery-latest.js”?

  10. David

    Hi,

    at first I want to thank you for this great tutorial.
    I have a question. I can get it runnning. My Pi is showing the dialog that it is listening on port 3000.
    But I can not connect, If I enter the Pi’s IP address in the browser.
    My Pi is in a subnet (IP:192.168.2.100) and my router is in 192.168.178.1.
    The net structure is as the following.

    |
    1. Router (192.168.178.1)
    |
    | WLAN
    |
    2. Router (Connect through WLAN with Router 1, IP: 192.168.178.41)
    |
    |LAN (192.168.2.22)
    |
    Raspberry Pi (IP:192.168.2.100)

    What do I have to do that I can reach the Pi
    entering http://192.168.100:3000 does not work.

    Thank you in advance and I’d appreciate your help.

    David

  11. Luke Murphy

    Hi,

    Thanks for the detailed explanation above, I’ve installed and tested on my RPi and all works fine.

    I am working on a project where where I aim to retrieve data from a TI Sensortag, using the following code https://github.com/sandeepmistry/node-sensortag and display it via a web application. I think your method above would be ideal for this.

    Do you have any idea how I would manipulate myapi.js and myclient.js to in order to be able to call these sensor values from the ‘node-sensortag’ code and display in index.html?

    Many thanks in advance,
    Luke

  12. Dr. Matthias H. Fröhlich

    HI – many thanks for interesting and helpful explanation. Side note: are you aware, that the example URL http://api.exip.org/?call=ip appears to have been hijacked by some rogue server according to warning messages appearing in my browser?

    Otherwise many thanks again. Best regards, Matthias

  13. Robert

    Thanks so much for taking the time to form this tutorial this was exactly what i needed to get started!!

  14. Marguerite

    Hey, I think your blog might bbe having browser compatibility issues.
    When I look at your blog site in Firefox, it looks fine but when opening
    in Internet Explorer, it has some overlapping. I just wanted to give you a quick headss up!
    Other then that, superb blog!

  15. UltimateOgee

    Need some help with an error I encounter at require(‘express’) in myapi.js.

    module.js:340
    throw err

    Error: Cannot find module ‘express’

    I followed the instructions exactly, and my best guess right now is that I installed express in the wrong location. (the part where you make a directory called ‘myapp’).

    I tried installing express in /usr/local and also tried doing it at /home/pi with no luck so far.

    Any suggestions would help.

  16. Max

    You specify steps of
    $ mkdir myapp
    $ cd myapp
    $ npm init
    $ npm install express –save
    $ npm install connect –save

    what’s with the npm init?

  17. uday

    You are Awesome Sir, Im now fan of your tutorials, Its good to see someone exposing their knowledge through a web server, can fetch data in your brain with a Simple GET request. Kudos to you, keep it up.

  18. Sandeep

    Hi Sir,
    Good tutorial , but if i have raspberry pi with more than two ultrasonic sensors than how to send data to the client and then that data i have to store in database at desktop application i.e client side , how to do it .
    pls help me

  19. Howard Bash

    Hi,

    I ran through this tutorial and the message that the server is running on port 3000 never appears. So, I downloaded the code and duplicated it on my RPi. The server is running.

    But, when I run the browser from my desktop using the RPi IP address on the assigned port, I get the message Unrecognized API call.

    This is almost good as it shows the code runs. But, I don’t get back the input data.

    Any suggestion(s) would be appreciated on this.

    Thanks,
    Howard

  20. Wendell White

    I just found this tutorial after doing a web search and this is just what I’ve been looking for…this is great!

  21. stilgar

    New to node & PI so…

    how can I easily access pi4j libraries from node? interested in the i2c part that the library offers, exposing calls to the PI via the browser.

    Thanks!

  22. Jules

    Worked like a charm except that I had to install npm on my fresh pi.
    I suggest telling beginners that they may need to run
    “sudo apt install npm”

  23. Aristide Vanwanzeele

    Hi,

    Nice tutorial and works as expected.

    However, suppose my information is on another webserver running on, say, an ESP8266 within the same network, how can I do a GET from my Raspberry Pi to that ESP8266 using the techniques exposed here?

    In my particular case, the ESP8266 is measuring temperature and humidity and I’ve added the necessary REST variables, names and id’s to that component. IP is 192.168.123.19.

    I want to use the RPi to “get” the temperature and humidity from the ESP8266 web server using the above mentioned methods and showing this in a web UI. This, instead of getting the info from a variable within the same web server (RPi with IP 192.168.123.61).

    I’ve tried to directly put the IP address of the ESP8266 in the url variable of myclient.js and execute the $.getJSON(url, function…..) but that fails with the error 400 (Bad Request).

    Any ideas/suggestions on how to do this?

Leave a Reply to Ceeb Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s