Mocking Server Dependencies in Javascript and Angularjs Applications
Most Single Page Applications (SPA) written in HTML and JavaScript interact with server side code using the familar XMLHttpRequest object. During development it can be convenient to run the application with mock data that eliminates this server dependency. This can be useful if the server side stack is complex and not easy to set up on a local machine or if a shared dev server running the server components suddenly goes offline. It’s also handy for tweaking the data returned by the services to ensure the UI behaves appropriately in specific scenarios. Naturally it’s imperative to integrate the SPA with real server code early and often but the flexibility provided by the “server mock” technique can be indispensible.
Note: while this article will illustrate how to mock services in an AngularJS application, this pattern applies to any UI technology (JavaScript or otherwise). The key is achieving Separation of Concerns (SoC) that allows real services and mock services to be easily swapped.
Update 12 September 2013: some folks have inquired why I didn’t use RESTangular in this blog. I think RESTangular is a fine framework that is more flexible than Angular’s $resource abstraction. However, for simple sample code it makes more sense to use $http since more folks are familiar with it. Also, the question misses the main point of this blog post which is applying a pattern so data access code is abstracted, thereby simplifying the controller code. If your application grows and requires new code to implement custom caching or request queueing logic, the Repository will be the perfect place to do it. You can apply this pattern with $http, $resource, RESTangular or any other data access framework. And that’s the whole point: by abstracting the data access code, the controller doesn’t care how data is fetched; it only expects a promise to be returned which will later be resolved or rejected.
Let’s get started!
The Old Way: Use $http Directly
Angular provides the $http and $resource “services” for making HTTP calls to load data into your app. In tutorials and simple applications these are frequently injected directly into UI controllers:
function DonutController($scope, $http) {
// get the data
$http.get("/api/donut/listAll").then(function (response) {
// no fry cakes here
$scope.donuts = response.data.fritters;
});
}
Here the controller invokes $http directly and asks it to fetch data from a known URL. The same approach works for $resource as well. While this approach is simple, it offers limited flexiblity and begins to overcomplicate the controller when data access becomes nontrivial.
Assume we have a number of UI widgets on this page that control the type of donuts we wish to load. When we invoke the backend service, we need to pass parameters to filter the donut based on size, filling, glaze and presence of a hole:
function DonutController2($scope, $http) {
// called from the partial on button click
$scope.fetchDonuts = function () {
// construct url based on values bound to form elements
var url =
"/api/donuts/list?size=" +
$scope.size +
"&filling=" +
$scope.filling +
"&glaze=" +
$scope.glaze +
"&hole=" +
$scope.hasHole
? 1
: 0;
// feed me
$http.get(url).then(function (response) {
$scope.donuts = response.data.results;
});
};
}
The code to construct the URL is getting more complex and muddying up the controller a bit. Furthermore if we have other views that need to fetch these donuts this code would need to duplicated. Clearly we can improve the design through some refactoring and application of patterns.
The New Way: Use a Repository
This technique involves adding an intermediate layer between the controller and $http that encapsulates data access and simplifies the code in the controller. Here’s a simple example of this expressed as an Angular module:
var donutModule = angular.module("donuts", []);
donutModule.service("donutRepository", [
"$http",
function ($http) {
this.$http = $http;
/**
* Retrieves tasty donuts based on user requirements
*/
this.fetchDonuts = function (size, filling, glaze, hasHole) {
// construct url based on values bound to form elements
var url =
"/api/donuts/list?size=" + size + "&filling=" + filling + "&glaze=" + glaze + "&hole=" + hasHole
? 1
: 0;
// feed me
return this.$http.get(url).then(function (response) {
return response.data.results;
});
};
},
]);
donutModule.controller("donutController", [
"$scope",
"donutRepository",
function ($scope, donutRepository) {
// get in my belly
donutRepository.fetchDonuts($scope.size, $scope.filling, $scope.glaze, $scope.hasHole).then(function (donuts) {
$scope.donuts = donuts;
});
},
]);
Note: I’m calling this intermediate a “Repository” although other terminology is likely valid, based on your preference. See “Quick Note on Names” below.
The Repository provides a very similar API as $http in that it ultimately returns a Promise that is later resolved with the data returned by the server. However, it exposes a set of methods which provide a cleaner API to the controller than forcing it to perform string concatenation to build up URLs that are passed to $http.
Using a Repository to Swap Out Mocks and Real Services
Now let’s explore how we can easily swap out real and mock services with another simple Angular module example:
var donutModule = angular.module("donuts", []);
window.DonutRepository = function ($http) {
this.$http = $http;
this.fetchDonuts = function (size, filling, glaze, hasHole) {
var url =
"/api/donuts/list?size=" + size + "&filling=" + filling + "&glaze=" + glaze + "&hole=" + hasHole ? 1 : 0;
// invoke real service
return this.$http.get(url).then(function (response) {
return response.data.results;
});
};
};
window.DonutRepositoryMock = function ($http) {
this.$http = $http;
this.fetchDonuts = function (size, filling, glaze, hasHole) {
// just get data from a flat JSON file
return this.$http.get("/mockdata/donut/fetch.json").then(function (response) {
return response.data.results;
});
};
};
donutModule.factory("donutRepository", [
"$http",
"configModel",
function ($http, configModel) {
if (configModel.mocksEnabled) {
return new DonutRepositoryMock($http);
} else {
return new DonutRepository($http);
}
},
]);
Now we have a new “mock” implementation that loads a JSON file from the local web server. We use Angular’s factory method to control exactly what object is bound as donutRepository for injection into the controller. Alternatively the mock implementation could simply create its own data programmatically and return a promise using the $q and deferred APIs:
var donutModule = angular.module('donuts', []);
donutModule.service('donutRepository', ['$q', '$timeout', function($q, $timeout) {
// get some donuts based on user requirements
this.fetchDonuts(size, filling, glaze, hasHole) {
var deferred = $q.defer();
// return abitrary data after 500ms delay to simulate server call
$timeout(function() {
// sorry bro, we're sold out
deferred.resolve([]);
}, 500);
return deferred.promise;
};
}]);
The configModel referenced by the factory above is a simple object that holds configuration information about the application. The implementation below allows us to control the config options by passing parameters via the URL to the AngularJS app on startup:
var appModule = angular.module("myApp", []);
appModule.service("configModel", [
"$location",
function ($location) {
this.initialize = function () {
this.$location = $location;
this.useMocks = false;
};
// read the parameters passed to app, looking for 'useMocks'
this.configure = function () {
var params = $location.search();
if (params.useMocks) {
this.useMocks = true;
console.log("mocks enabled");
}
};
this.initialize();
},
]);
appModule.run([
"configModel",
function (configModel) {
// extract the config before any route changes happen
configModel.configure();
},
]);
Accessing the application via http://some.url/index.html#?useMocks=true will enable mock mode, based on the code above.
Once we push all data access code into its own discrete layer we can derive other benefits as well. We can easily centralize cross-cutting concerns such as logging or caching into our repository layer. If we need to implement offline mode in an application, each repository can collaborate with a service that queues up requests and pushes them to $http once the application comes back online. This is vastly preferrable to managing this complexity in a controller.
Sample Application
I’ve built a very basic “Reddit Browser” AngularJS application that provides a working sample of these techniques. The code is available on my GitHub’s blog-examples repo.
Clone the repo and then start the Node web server script using: ./scripts/web-server.js
The app will be available here: http://localhost:8000/ng-repository/src/index.html
“Mock mode” can be run easily via hitting dev.html instead.
Feedback is encouraged. Drop me a comment below, use my contact form or hit me up on Twitter.
A Quick Note on Names
I pushed this section to the end because it’s just dealing with semantics. I chose “Repository” as the term for the the new data access layer but there are a variety of terms that are sensible. At the end of the day, the name has significance but the application of the pattern is what really matters. Here are a few other options:
- Proxy: because the intermediate sits between the client controller code and (ultimately) the backend server hosting the service. However, “Proxy” is an extremely generic pattern and doesn’t really tell us what it’s acting as a proxy to.
- Service: due to the popularity of the Service Oriented Architecture (SOA) buzzword, components residing on a server that return data in a HTTP response are frequently called “Services.” Therefore we could call the intermediate a Service. However, in the context of an AngularJS application this would be confusing since “service” is used generically to describe virtually any object available for dependency injection in the AngularJS context.
- Repository: made popular in Eric Evans’ book entitled Domain-Driven Design: Tackling Complexity in the Heart of Software, a Repository can be used in server side code to encapsulate querying and persistence, ultimately returning one or more Domain Objects. This aligns pretty closely with what’s going on in the AngularJS app so I decided to go with it.
- Data Access Object (DAO): this one is popular in Java circles. It’s probably at least as valid as Repository, perhaps moreso since it doesn’t carry along the Domain Model connotations.
It’s up to you. Pick what you like. :)