Prototype Angular UIs Without A Backend

Doug TurnbullSeptember 16, 2013
vectors are fun

So you’ve got an AngularJS UI built out, but you’ll need a fleshed-out backend before being able to really take it for a test drive, right? Actually, it turns out, with the magic of Angular and its mocked $httpBackend, we don’t need no stinking backend!

If you’ve heard of $httpBackend, you’ve probably heard of it it terms of writing unit tests. Tests that look like:

// tell http backend what to do when in gets a GET request at a specific URL
$httpBackend.when(“GET”, “/users/4”).respond( {userName: “Doug”, userId: 4} );
// Code we’re testing
// flush all pending requests (pretend the server just got back with response)
expect(userService.getUser(4)).toBe( {userName: “Doug”, userId: 4});

While unit testing like this can help test and play with bits of code, it can’t drive an overall vision the way that seeing, clicking, and typing into a prototype can. Therefore, I’ve taken $httpBackend and implemented a complete mock-up of my backend to allow me to use my UI and iterate quickly. Basically, I can now simply open file://path/to/my/project/index.html in my browser use my application as if it were backed by a database on a server. (That is as long as I don’t fully reload the page:) ).

How have I done this? Read along with the corresponding jsfiddle

First, I tell Angular to use the angular-mocks $httpBackend (by passing it the $httpBackend constructor function) as a decorator on top of the concrete $httpBackend service. In Angular’s dependency injection, a decorator wraps the original service, layering on some custom functionality. In this case, Angular’s mock $httpBackend is setup to receive the concrete $httpBackend service, and will pass through to it if you use the passThrough() function after creating a rule (examples further down). In other words, I reserve the ability to pass some requests along as real HTTP requests.

.config(function($provide) {
    $provide.decorator('$httpBackend', createHttpBackendMock);

All our code to mock the backend will take place in this function we execute before running the angular application:$httpBackend, $timeout) {
        … <the cool stuff you’ll see below>

In this run function, I can use the mock $httpBackend API to specify some rules, with actions to perform on the receipt of HTTP requests:

// Some state
var users = {};
var userId = 0;
$httpBackend.when('PUT', '/users')
.respond(function(method, url, data) {
  data = angular.fromJson(data);
  users[userId] = {userName: data.userName, userId: userId};
  return [200, users[data.userId]];

I can then specify some rules based on a regex if need be:

var regexpUrl = function(regexp) {
  return {
    test: function(url) {
      this.matches = url.match(regexp);
      return this.matches && this.matches.length > 0;

$httpBackend.when('GET', regexpUrl(/users\/(\d+)/))
.respond(function(method, url, data) {
  data = angular.fromJson(data);
  return [200, users[data.userId]];

And since I’m using a delegate, I can decide that certain requests will just get passed through to do real requests (say JSONP requests to solr from my instant search directive!):

$httpBackend.when('JSONP', regexpUrl(/http:\/\/.*/))

$httpBackend’s way of simulating an asynchronous response is for you to call flush() from your tests. So none of our app’s requests will be responded to until we tell $httpBackend to flush. To create a kind-of $flush run-loop, we’ll use the angular $timeout service to call flush every half-second. $httpBackend still wants to be used in a unit testing context, so it will throw an exception if there’s nothing to flush. So we catch and discard that exception.

var flushBackend = function() {
  try {
  } catch (err) {
  // ignore that there's nothing to flush
  $timeout(flushBackend, 500 /*ms*/);    };    $timeout(flushBackend, 500);

Viola, now I can experiment with my UI much more efficiently! Compared to other solutions, like mocking individual angular services or creating a mockable backend service that wraps the $http calls, I have found this solution the cleanest and least imposing on my production code.

Have you had to solve a similar problem? Please comment and let me know! Also, do you need help with rich search & discovery oriented user interfaces? Let us know. We know quite a bit about building rich UIs for Solr!

More blog articles:

Let's do a project together!

We provide tailored search, discovery and analytics solutions using Solr and Elasticsearch. Learn more about our service offerings