Was this helpful?

In this cookbook example, you will learn how to create a simple BaaS solution using Node.js on Apigee Edge. 

Download and try out the sample code

We recommend that you download and try out this topic's sample code. The sample is called nodejs-baas-cookbook, which you can find in the doc-samples folder in the Apigee Edge API Services samples repository in GitHub. For information on downloading Apigee samples, see Using the samples.

The sample code includes a complete proxy definition that includes the Node.js application. The Node.js app serves as the backend "target" of the API proxy. Instructions for deploying and calling this cookbook sample API are provided in the README file that comes with the sample. You can also find brief deployment instructions here: Using the samples.

About this cookbook sample

Another way to look at this example, is that it represents a programmable target in Apigee Edge. In this case, the application logic is written entirely in Node.js. The Node.js code orchestrates calls to the API BaaS data store, executes custom logic, and returns appropriate responses.

 

The sample includes two Node.js modules:

  • Express -- A web application framework for Node.js. The API for this example is written using Express. That is, the GET and POST commands are written using the Express API. For more information about Express, go to expressjs.com.
     
  • Usergrid -- An open source data platform for mobile applications. Usergrid handles user and data management, push notifications, geolocation, logging, eventing, and more. Apigee's API BaaS feature is based on Usergrid. For more information about API BaaS, see API BaaS home. For more information about Usergrid, visit the Usergrid repository on GitHub. In this application, Usergrid handles data store transactions and user authentication. 

The API surfaced through this proxy includes a simple GET for fetching data and a POST for storing data in the data store. The basic API calls that are implemented look like this:

1. Retrieve a list of employees stored in the API BaaS data store:

$ curl http://org-test.apigee.net/nodejs-baas-cookbook/employees/profiles

2. Create a new employee profile in the API BaaS data store:

$ curl http://wwitman-test.apigee.net/employees/profile \
-H "Content-Type: application/json" \
-d '{"id":"jdoe", "firstName":"Jane", "lastName":"Doe", "phone": "201-555-5555" }' \
-X POST

Setup tasks

This sample takes advantage of the Node.js module called usergrid. The usergrid module provides methods for creating and accessing entities and collections in Apigee's API BaaS data store. Following this basic pattern, you can create a backend service that includes other API BaaS features like push notifications, user management, geolocation, and more. The sample also uses the popular Express module for Node.js to create an API for the service. 

If you want to run the sample, you need to perform the following setup tasks. 

  1. You need an Apigee  account to use API BaaS. Setting up an account is free and only takes a minute. See Creating an Apigee Account.
  2. In the API BaaS admin portal, create a new application called employees. For detailed information, see Creating a New Application with the Admin Console
  3. In the API BaaS admin portal, create a new data store called employees. For detailed information, see Creating Collections.

Before you begin

For this cookbook example, we assume you are familar with these techologies and concepts:

  • How an API proxy project is organized on your filesystem, as explained in API proxy configuration reference. This cookbook topic demonstrates local development (file system-based) as opposed to cloud-based development where you would use the management UI to develop the API proxy.
     
  • The basics of how Node.js applications are used in Apigee Edge. See Overview of Node.js on Apigee Edge.
     
  • A working knowledge of JavaScript.
     
  • Basic understanding of Node.js. For an overview, see the nodejs.org website.
     
  • Basic understanding of how the API BaaS data store works. For an overview, see API BaaS features.

If you have downloaded the sample code, you can locate all of the files discussed in this topic in the nodejs-baas-cookbook sample folder. The following sections discuss the sample code in detail.

Going with the flow

Before looking at the Node.js source code, let's take a quick look at the ProxyEndpoint and TargetEndpoint definitions. As for all proxies, the endpoints are defined in XML files located in the proxy file structure under the apiproxy/proxy and apiproxy/target folders. The XML, shown below, tells us a lot about this API proxy and how the Node.js application is integrated into the flow of the proxy.

Let's look at the ProxyEndpoint flow first. If you downloaded the sample from GitHub, you can find this API proxy definition in the file doc-samples/nodejs-baas-cookbook/apiproxy/proxies/default.xml. The ProxyEndpoint configuration defines the inbound (app-facing) interface for an API proxy.

<ProxyEndpoint name="default">
   <HTTPProxyConnection>
        <BasePath>/employees</BasePath>
        <VirtualHost>default</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
    </RouteRule>
    <PreFlow name="PreFlow">
        <Request/>
        <Response/>
   </PreFlow>
</ProxyEndpoint>

This proxy endpoint is very basic. For detailed information on proxy endpoint definitions, see API proxy configuration reference. Note that the proxy specifies the BasePath as /employees. The BasePath identifies the URL used by Apigee Edge to route incoming messages to this API proxy. So, that's why you need to put /employees in the path when you call this API. One other thing to note about the endpoint is that it declares the TargetEndpoint as default. Again, this is fairly standard configuration. 

Now let's look at the TargetEndpoint definition. If you downloaded the sample from GitHub, you can find this API proxy definition in the file doc-samples/nodejs-baas-cookbook/apiproxy/targets/default.xml.

<TargetEndpoint name="default">
    <ScriptTarget>
        <ResourceURL>node://server.js</ResourceURL>
    </ScriptTarget>
    <PreFlow name="PreFlow">
        <Request/>
        <Response/>
    </PreFlow>
</TargetEndpoint>

The most important thing to notice is that the TargetEndpoint includes a <ScriptTarget> element, which is the standard way of declaring the main Node.js file in the app. This is the file that you would call with the node command if you were to run the app from the command line. <ScriptTarget> is discussed in more detail in Adding Node.js to an existing API proxy. In our example, the <ScriptTarget>.<ResourceURL> parameter tells Edge that the main Node.js file in the application is called server.js

If you downloaded the sample from GitHub, you can find the server.js file is under apiproxy/resources/node/server.js. This is the standard location where the main Node.js file must reside in the proxy file structure.

Coding the Node.js application

Here's the complete listing of our example Node.js application. We'll discuss code in more detail immediately following the listing.

var express = require('express');
var usergrid = require('usergrid');
var config = require('./config');

// Set up Express environment and enable it to read and write JavaScript
var app = express();
app.use(express.bodyParser());

// Initialize Usergrid

var client = new usergrid.client({
	'orgName' : config.organization,
	'appName' : config.application,
	'clientId' : config.clientId,
	'clientSecret' : config.clientSecret,
	'authType' : usergrid.AUTH_CLIENT_ID,
	logging : config.logging
});


// The API starts here

// GET /

var rootTemplate = {
	'employees' : {
		'href' : './employees'
	}
};

app.get('/', function(req, resp) {
	resp.jsonp(rootTemplate);
});

// GET /profiles

app.get('/profiles', function(req, res) {	
		getProfiles(req, res);
});

function getProfiles(req, res) {
	client.createCollection({
		type : 'employees'
	}, function(err, employees) {
		if (err) {
			res.jsonp(500, {
				'error' : JSON.stringify(err)
			});
			return;
		}

		var emps = [];
		while (employees.hasNextEntity()) {
			var emp = employees.getNextEntity().get();
			var e = {
				'id' : emp.id,
				'firstName' : emp.firstName,
				'lastName' : emp.lastName,
				'phone' : emp.phone
			};
			emps.push(e);
		}
		res.jsonp(emps);
	});
}

// POST /profile

app.post('/profile', function(req, res) {
	if (!req.is('json')) {
		res.jsonp(400, {
			error : 'Bad request'
		});
		return;
	}

	var b = req.body;
	var e = {
		'id' : b.id,
		'firstName' : b.firstName,
		'lastName' : b.lastName,
		'phone' : b.phone
	};

	if ((e.id === undefined) || (e.firstName === undefined)
			|| (e.lastName === undefined) || (e.phone === undefined)) {
		res.jsonp(400, {
			error : 'Bad request'
		});
		return;
	}

	createProfile(e, req, res);
});

function createProfile(e, req, res) {
	var opts = {
		type : 'employees',
		name : e.id
	};

	client.createEntity(opts, function(err, o) {
		if (err) {
			res.jsonp(500, err);
			return;
		}
		o.set(e);
		o.save(function(err) {
			if (err) {
				res.jsonp(500, err);
				return;
			}
			res.send(201);
		});
	});
}


// Listen for requests until the server is stopped

app.listen(process.env.PORT || 9000);
console.log('The server is running!');

The code uses Express to handle GET and POST requests and the Usergrid API to handle interactions with the API BaaS data store. When a request is recieved, the Usergrid API is used to fetch or create entities in the API BaaS data store. The Node.js app also handles user authentication and creates an HTTP server to listen for requests. The server starts as soon as the app is deployed and listens on the specified port.

Handling GET and POST requests with Express and Usergrid

The Node.js app uses Express API methods express().get() and express().post() to handle GET and POST requests. On a GET request the app calls the getProfiles() method, which uses Usergrid createCollection() method to create and populate a Usergrid Collection object with values taken from the request. The POST request calls another method called createProfile(), which uses the Usergrid createEntity() method to create a new entity and store it in the API BaaS data store.

Here is is the get() method of Express, that handles the GET request:

// GET /profiles
app.get('/profiles', function(req, res) {
    if (loggedIn === null) {
      logIn(req, res, getProfiles);
    } else {
      getProfiles(req, res);
    }
});

The getProfiles() method is shown below. It simply iterates over an employees collection to retrieve the employee profile data. This method requires a valid application user. We'll discuss authentication in the next section. Note that the createCollection() method automatically populates an object with items from the collection. It is a common technique for interacting with the API BaaS data store. For more information on these Usergrid Node.js module methods, see https://npmjs.org/package/usergrid

function getProfiles(req, res) {
    loggedIn.createCollection({ type: 'employees' }, function(err, employees) {
        if (err) {
          res.jsonp(500, {'error': JSON.stringify(err) });
          return;
        }
       
        var emps = [];
        while (employees.hasNextEntity()) {
          var emp = employees.getNextEntity().get();
          var e = { 'id': emp.id,
                    'firstName': emp.firstName,
                    'lastName': emp.lastName,
                    'phone': emp.phone };
          emps.push(e);
        }
        res.jsonp(emps);
    });
}

The code that handles POST requests follows a similar pattern, using the express().post() method as the starting point.

Understanding the authentication pattern

Client authentication is handled in the usergrid.client() method of the usergrid module. We pass in the organization and application names, as well as the Client Secret and Client ID values. This level of authentication grants all clients access to the data store through the usergrid.client object. 

You can find your client secret and client id on the "Properties" page of the API BaaS Admin Portal.

var client = new usergrid.client({
    'orgName': config.organization,
    'appName': config.application,
    'clientId': config.clientId,
    'clientSecret': config.clientSecret,
    'authType' : usergrid.AUTH_CLIENT_ID,
    'logging' : config.logging
});

For more information on the usergrid node module API, see Usergrid Node.js module documentation.

The way the sample app is implemented, the actual user login credentials (username and password) are stored in the config.js file that the app reads at runtime. Before running the app on Edge, you need to make sure this config file is populated with the information for your organization.

For example:

exports.organization = 'myorg'
exports.application = 'employees'
exports.clientId = 'b3U6gj36in4gEeOaDDtwafXLGg'
exports.clientSecret = 'b3U6JAorOoLMzn0bE02uuJqgXx40p78'
exports.tokenExpiration = 60000
exports.logging = true

For more information on how to configure and run the sample application, refer to the README file in the root folder of the nodejs-baas-cookbook sample.

The Node.js server

Finally, we point out that the Node.js app is an HTTP server and it's function is to listen on its specified port until the server stops. As a Node.js app, it will listen for and handle requests asynchronously. 

// Listen for requests until the server is stopped
app.listen(process.env.PORT || 9000);
console.log('The server is running.');

Note that coding the port argument to conditionally retrieve the port number from a system variable is considered a best practice by Apigee.

Testing the example

If you have not already done so, try to download, deploy, and run the nodejs-baas-cookbook sample, which you can find in the doc-samples folder in the Apigee Edge samples repository on GitHub. Just follow the instructions in the README file in the nodejs-baas-cookbook folder. Or, follow the brief instructions here: Using the samples.

To summarize, you can call the API as follows. Substitute myorg with your organization name:

1. Create a new employee profile in the API BaaS data store:

$ curl http://myorg-test.apigee.net/employees/profile \
-H "Content-Type: application/json" \
-d '{"id":"cjones", "firstName":"Chris", "lastName":"Jones", "phone": "201-555-5555" }' \
-X POST

 

2. Retrieve a list of employee profiles stored in the API BaaS data store:

$ curl http://myorg-test.apigee.net/nodejs-baas-cookbook/employees/profiles -X GET
[
  {
    "id": "cjones",
    "firstName": "Chris",
    "lastName": "Jones",
    "phone": "201-555-5555"
  }
]

The POST operation stores profile employee data in the data store. The GET operation returns the employee profile data from the data store. 

Summary

This cookbook topic explained how to create a simple BaaS service in Apigee Edge. The service logic is written entirely in Node.js and Apigee's API BaaS data store is used for the app's cloud storage. 

 

Get help

For help, see Apigee Customer Support.

Add new comment

Provide your email address if you wish to be contacted offline about your comment.
We will not display your email address as part of your comment.

We'd love your feedback and perspective! Please be as specific as possible.
Type the characters you see in this picture. (verify using audio)

Type the characters you see in the picture above; if you can't read them, submit the form and a new image will be generated. Not case sensitive.