Friday, April 20, 2018

HTTP based backend mock for Angular JS

AngularJS based frontend applications consume their data mostly from a backend system. But in some cases a working backend is not available for a frontend developer. Fortunately the Angular JS dev team provides a package for this situations: the ngMock. This package is generally used for test purposes, but it's easily to use for mocking as well. The corresponding documentation can be found here: https://docs.angularjs.org/api/ngMock This guide not covers how to install it, you can find it in the documentation of ngMock.

Ok, now I assume you installed ngMocks, and you want to start work with it. First, let's create a basic application, which'll consumes and displays recipes from a currently not existing backend. Create an empty, AngularJS compatible HTML file, name it "index.html".

<!doctype html>
<html lang="en" ng-controller="RecipeController as vm">
      <head>
        <meta charset="UTF-8" />
        <title>My recipes</title>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular-mocks.js"></script>
        <script>
            var Config = {
                mockEnabled : false
            };
        </script>
        <script src="js/app.js"></script>
        <base href="{{vm.contextPath}}">
      </head>
      <body>
        My recipes:
            <ul>
                <li ng-repeat="item in vm.recipeList">{{item.id}}. {{item.name}}</li>
            </ul>
      </body>
</html>


You can notice there is a highlighted part. This variable'll manage our mocks to be turned on or off. Now we turned off. Create an app.js in a folder called "js".

var app = angular.module("app", [])

  .constant("BACKEND_URL", "http://localhost:8080/")
  .constant("CONTEXT_PATH", "/")
 .service("BackEndService", function($http, $q, BACKEND_URL) {
        var vm = this;

         vm.getAll = function() {
            return $http.post(BACKEND_URL + "get_all");
        };

})

.controller('RecipeController', function(BackEndService, CONTEXT_PATH) {

   var vm = this;
   vm.recipeList = [];
   vm.contextPath = CONTEXT_PATH;

  BackEndService.getAll().then(function(response) {
      vm.recipeList = response.data;
  }, function(response) {
      console.error("error", response);
  });

});

var runMock = function($httpBackend, BACKEND_URL) {
    var allData = [{id:1, "name":"Onion soup"}, {id:2, "name":"Hungarian goulash soup"}];

    $httpBackend.whenGET(/home.html$/).passThrough();
    $httpBackend.whenPOST(BACKEND_URL + 'get_all').respond(function(method, url, data) {
        return [200, allData];
    });

};

app.run(function($httpBackend, BACKEND_URL) {
    console.debug("Application run", "mock = " + Config.mockEnabled);
    if(Config.mockEnabled === true) {
    }
});

angular.element(document).ready(function() {
    if(Config.mockEnabled === true) {
        angular.module('app').requires.push('ngMockE2E');
    }
    angular.bootstrap(document, ['app']);
});

Ok, try this code, how it works!


As you can see in the developer console, there's no response from the backend, which is correct, because we don't have a backend for our frontend. Now, we'll extend our code with some mocks. Open the app.js again, and write the following lines after the "app":

var runMock = function($httpBackend, BACKEND_URL) {
         var allData = [{id:1, "name":"Onion soup"}];
        // Templates
        $httpBackend.whenGET(/home.html$/).passThrough();

      $httpBackend.whenPOST(BACKEND_URL + 'getAll').respond(function(method, url, data) {
            return [200, allData];
        });
};

Modify the Config.mockEnabled variable in the index.html:

<!doctype html>
<html lang="en" ng-controller="RecipeController as vm">
      <head>
        <meta charset="UTF-8" />
        <title>My recipes</title>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular-mocks.js"></script>
        <script>
            var Config = {
                mockEnabled : true
            };

        </script>
        <script src="js/app.js"></script>
        <base href="{{vm.contextPath}}">
      </head>
      <body>
        My recipes:
            <ul>
                <li ng-repeat="item in vm.recipeList">{{item.id}}. {{item.name}}</li>
            </ul>
      </body>
</html>


Try to open again the webapp in your browser:


This error happened, because there's no incoming http post request.

Finally, extend the app.run with the recently added function:
app.run(function($httpBackend) {
    console.debug("Application run", "mock = " + Config.mockEnabled);
    if(Config.mockEnabled === true) {
        runMock($httpBackend, BACKEND_URL);
    }
});


Now let's try again. You'll see the list in the screen.Thats all! :)


Configure and use VSCode for Java web development

Embarking on Java web development often starts with choosing the right tools that streamline the coding process while enhancing productivity...