This document discusses how to mock a backend for an AngularJS application without a real backend. It recommends organizing URL definitions, creating JSON fixture files to represent mock data, using $httpBackend to mock server responses, and $resource to load local JSON files. It emphasizes using $httpBackend's dynamic response capabilities to validate requests and return custom headers. It also recommends persisting mock data using localStorage and a service to represent cached data, completing the backend simulation experience. The document provides code examples for implementing these techniques to mock CRUD operations on a user resource as part of a user ranking application.
2. Wearing multiple hats at Narada Robotics startup, from coding to whatever else…
Main interests - mobile development
IN LOVE WITH ANGULARJS
Enrique Oriol
CTO @ Narada Robotics
blog.enriqueoriol.com @enrique.oriol
5. BACKEND STORIES 5
URLS TO LOCAL JSONS
Of course we can use urls to local JSON files, but…
We cannot use POST, PUT...
We cannot use response codes
We cannot access headers
So we cannot really prepare client side API connections
@enrique.oriol
7. MOCKING THE SERVER
What we will cover:
URL DEFINITIONS01
CREATING JSON FIXTURES02
USING $HTTPBACKEND03
USING $RESOURCE04
DYNAMIC RESPONSES05
BACKEND PERSISTENCE06
9. BACKEND STORIES 9
Why not Node.js mock?
It is just an alternative to any other mock server
It runs at the same JS VM, so it does not need a public
endpoint somewhere
Think about sending the results to a client in the case of a
hybrid app
@enrique.oriol
10. BACKEND STORIES 10
You can download code here:
https://github.com/kaikcreator/UserRanking
And play with the results here:
http://kaikcreator.github.io/UserRanking/
EXAMPLE APP
We will use User Ranking app as
example
@enrique.oriol
11. QUICK OVERVIEW USER RANKING
Require Following Integration With API
NON AUTHENTICATED
CREATE USER - POST user endpoint
USERS RANKING - GET users endpoint
AUTHENTICATED
UPDATE USER - PUT user endpoint
17. BACKEND STORIES 17
CREATING JSON FIXTURES
How a user will look like
{
id: userId,
name: username,
image: urlToUserImage,
rating: userRating
}
@enrique.oriol
27. BACKEND STORIES 27
If you perform a $http call just after app boostrap, it’s possible that $resource is
not already populated, returning an empty value.
In that case you should perform some additional trick, always trying to perform
all the stuff in MockServerModule, so it’s easier to “shut down” mock server
when real server comes to life.
You can see a decorator approach in the example code available on github.
REMEMBER that $resource
is populated ASYNC
$resource
@enrique.oriol
29. BACKEND STORIES 29
Dynamic responses
Using function inside $httpBackend.respond
<!-- mocked data -->
$httpBackend.whenGET(urls.users).respond( $resource(fixturePaths.users).query() );
/*mocked data*/
var usersResource = $resource(fixturePaths.users).query();
$httpBackend.whenGET(urls.users).respond(function(method, url, data, headers){
return [200, usersResource, {}];
});
Changing this:
Into this:
Gives us access to url, data and headers, so our response can be dynamic
@enrique.oriol
30. BACKEND STORIES 30
Dynamic responses
We can perform data validation, and return custom headers
.run(['$httpBackend', 'urls', 'fixturePaths', '$resource', function($httpBackend, urls, fixturePaths, $resource){
/*...previous stuff...*/
/* regex allowing any user id in user url*/
var anyUserUrl = new RegExp(urls.user('.*'));
/*mock POST rx of a new user, and return auth token*/
$httpBackend.whenPOST(anyUserUrl).respond(function(method, url, data, headers){
data = angular.fromJson(data);
if(data.name === undefined || !angular.isString(data.name) || data.name.length === 0){ return [400, null, null]; }
else{
var user = {
"id": "7",
"name": data.name,
"points": 0
};
return [200, user, {Authorization: "1234567890asdfghjklzxcvbnm"}];
}
});
}])
@enrique.oriol
31. BACKEND STORIES 31
Dynamic responses
We lack persistence
.run(['$httpBackend', 'urls', 'fixturePaths', '$resource', function($httpBackend, urls, fixturePaths, $resource){
/*...previous stuff...*/
/*mock POST rx of a new user, and return auth token*/
$httpBackend.whenPUT(anyUserUrl).respond(
function(method, url, data, headers){
data = angular.fromJson(data);
if(headers['Authorization'] !== "Token 1234567890asdfghjklzxcvbnm"){
return [401, null, null];
}
else if(data.name === undefined && data.points === undefined && data.image ===undefined){
return [400, null, null];
}
else{
/*here we need to return updated data, so our app can reflect changes*/
var user = {...};
return [200, user, {}];
}
});
}])
@enrique.oriol
33. BACKEND STORIES 33
Write in LS
$window.localStorage['myKey'] = angular.toJson(myData);
Read from LS
var data = angular.fromJson($window.localStorage['myKey']);
Usage
Backend persistence
Local Storage
@enrique.oriol
35. BACKEND STORIES 35
.run(['$httpBackend', '$resource', 'urls', 'mockedUsers', function($httpBackend, $resource, urls, mockedUsers){
/* local calls */
$httpBackend.whenGET(/fixtures/.*/).passThrough();
/* regex allowing any user id in user url*/
var anyUserUrl = new RegExp(urls.user('.*'));
/*mocked users list*/
$httpBackend.whenGET(urls.users).respond(function(method, url, data, headers){
return [200, mockedUsers.list];
});
Backend persistence
Using our service in mock server - whenGET
@enrique.oriol