Consuming APIs with AngularJS 1.x

Consuming APIs allows you to retrieve data from a particular service. This service can be one that you made or something publicly available. Previously, we made an API to call our own. This post will show you how to create a front-end to consume that API!

Our front-end will focus on a single collection called Locations. We will have a map that plots our locations, a page to edit/delete a single location, and a page to create a new location.

This post will focus on creating the map page. Our flow will consist of loading the page, retrieving a list of locations from our API and populating a list will eventually link to a page to update/delete them.

Let’s start setting up our project! Our layout will be handled via Bootstrap. To manage our front-end dependencies, we will us Bower. To install Bower, open a command line and type

npm install -g bower

Once Bower is installed, you can then install Bootstrap and AngularJS by typing:

bower install bootstrap --save
bower install angular --save

At the time of this writing, this will install AngularJS 1.6.2 and Boostrap 3.3.7 into a www directory. These should do just fine for our particular project.

Within that www directory, you’ll want to create a blank HTML template with our Bootstrap and AngularJS files named index.html

<html>
<head>
 <!-- jQuery -->
 <script src="lib/jquery/dist/jquery.js"></script>

 <!-- Angular 1.6.2 -->
 <script src="lib/angular/angular.js"></script>

 <!-- Boostrap 3.3.7 -->
 <link rel="stylesheet" href="lib/bootstrap/dist/css/bootstrap.min.css">
 <script src="lib/bootstrap/dist/js/bootstrap.min.js"></script>

 <script src="js/app.js"></script>
</head>

<body ng-app="LocationApp">
 
 <div ng-controller="LocationCtrl" class="container">
 
  <div class="row" ng-repeat="location in locations">
   <div class="col-md-3">{{location.name}}</div>
   <div class="col-md-4">{{location.description}}</div>
  </div>
 </div>
</body>
</html>

Our last piece to setup will be our app.js file. This will contain the reference to our app (LocationApp) and our first controller (LocationCtrl).

(function () {
  'use strict';

  angular.module('LocationApp', [])
   .controller('LocationCtrl', function($scope, $http) {
    // Using Angular's $http module, we can retrieve the Location results
    $http.get('http://www.yourapi.com/locations')
     .then(function(result) {
      // Once the data is retrieved, set it to $scope.locations. This variable directly relates to the locations variable in the ng-repeat in the html
      $scope.locations = result.data;
     });
   });
}());

That is all that is needed to pull data from an API and display it on the front-end of your choosing. This practice can be used with public APIs as well. For example, you can use the OpenWeather API.

Finishing up your Mongo/Node API!

You’ve created your Node API, gave it some basic functionality and now you’re going to add the ability to Update and Delete records in your MongoDB collection.

Adding the Update functionality to your Node API

An Update request is handled via the HTTP method PUT and is typically passed some data with an id to update a document in your collection. Depending on how sensitive the collection is, you would want to add validation to prevent users from updating records by passing in random ids.

	server.route({
		method: 'PUT',
		path:'/locations',
		handler: function (request, reply) {
			var locationId = request.payload.id;

			Location.findByIdAndUpdate(locationId, request.payload, function(err, location) {
				if (err) {
					return reply(err);
				} else {
					return reply(location);
				}
			});
		}
	});

Adding the Delete functionality to your Node API

Similar to Update, the Delete functionality is given an id to a document or some data to retrieve a document.

	server.route({
		method: 'DELETE',
		path:'/locations',
		handler: function (request, reply) {
			var locationId = request.payload.id;

			Location.findByIdAndDelete(locationId, function(err, location) {
				if (err) {
					return reply(err);
				} else {
					return reply(location);
				}
			});
		}
	});

In summary, your Node API should now be capable of doing the following when using the corresponding HTTP methods

  • POST – Create a document / Requires a payload containing document data
  • PUT – Update a document / Requires a payload containing document id and document data
  • GET – Get document list / No payload required
  • DELETE – Delete a document / Required a payload containing document id

With these two methods added, you have a Node API that can handle just about everything required from an API! To extend this functionality to other collections, you could simply copy/paste and substitute the collection name as needed. While that would certainly work, it wouldn’t be best practice.

Next we will focus on making sure your API is laid out in a manner that is easy to read, add functionality, test, etc.

Expand your Mongo/Node API in 10 more minutes!

Previously we spent 10 minutes setting up a barebones Node API using Mongo and Node. Now we are going to invest 10 more minutes to add Create and Read Mongo functionality. These are known as the C and R of CRUD functionality.

Begin the Node API expanding!

Install Mongoose

npm install mongoose

Mongoose is a ORM the bridge between our Node API and Mongo. Mongoose allows you to create models via Node and associate them with your Mongo collections.

Create a Model

A model is a representation of your Mongo collection. In our case, we are going to have a Locations collection consisting of a latitude, longitude, and created fields.

Your directory structure should look similar to this:

models
- Location.js
node_modules
index.js
package.json
Procfile

Create the following Location.js file in a models directory

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var LocationSchema = new Schema({
  name: { type: String, required: true },
  description: { type: String },
  lat: { type: String, required: true },
  lng: { type: String, required: true },
  created: { type: Date, required: true, default: Date.now }
});

module.exports = mongoose.model('Location', LocationSchema);

Update index.js to include new routes

Our server needs to know when to read our Locations or create a Location when you access a specific URL with a given server method. The server methods we will be working with are GET and POST.

const Hapi = require('hapi');
const Mongoose = require('mongoose');

const Location = require('./models/Location');

// Create a server with a host and port
const server = new Hapi.Server();

var mongoUri = process.env.MONGODB_URI || 'mongodb://YOUR_MONGO_URI';
var serverPort = process.env.PORT || 8080;

Mongoose.connect(mongoUri, function(err) {
	if (err) {
		console.log(err);
		process.exit(1);
	}

	server.connection({
		port: serverPort
	});

	// GET locations route
	server.route({
		method: 'GET',
		path:'/locations',
		handler: function (request, reply) {
			// Retrieve all locations
			Location.find({}, function(err, locations) {
				return reply(locations);
			});
		}
	});

	// POST locations route
	server.route({
		method: 'POST',
		path:'/locations',
		handler: function (request, reply) {
			// Make a new location
			var location = new Location();

			// Assign the new location fields to the values from our POST
			location.name = request.payload.name;
			location.description = request.payload.description;
			location.lat = request.payload.lat;
			location.lng = request.payload.lng;

			location.save(function(err, location) {
				if (err) {
					return reply(err);
				} else {
					Location.find({}, function(err, locations) {
						console.log(locations);
					});
					return reply(location);
				}
			});
		}
	});

	// Start the server
	server.start((err) => {

		if (err) {
			throw err;
		}
		console.log('Server running at:', server.info.uri);
	});
});

To explain in detail, your Node API will respond different depending on how you access it. When you to tell your Node API to GET /locations via http://yourapi:8080/locations then you should be presented with a list of Locations from your Mongo database.

When you access your Node API via a POST request to http://yourapi:8080/locations and provide it with some data, your Node API should respond by inserting provided data into your Mongo database.

That’s it! You now have the ability to retrieve and create new records. Further enhancements could be to add validation to your POST request to ensure things don’t go haywire with bogus data or even add the ability to update (via PUT) or delete (via DELETE) your records.