Skip to content

Instantly share code, notes, and snippets.

@kennethlynne
Last active February 19, 2019 10:41
Show Gist options
  • Save kennethlynne/7767088 to your computer and use it in GitHub Desktop.
Save kennethlynne/7767088 to your computer and use it in GitHub Desktop.
High fidelity prototyping using a mock back-end. Include angular-mocks in your script includes after angular. Demo: http://codepen.io/kennethlynne/pen/lJbce
'use strict';
angular.module('yourApp')
.constant('Config', {
viewDir: 'views/',
API: {
useMocks: true,
fakeDelay: 2000,
protocol: window.location.protocol.split(':')[0],
host: window.location.hostname,
port: String(window.location.port || 80),
path: '/api',
}
})
.config(function(Config, $provide) {
//Decorate backend with awesomesauce
if(Config.API.useMocks) $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
})
.config(function ($httpProvider, Config) {
if(!Config.API.useMocks) return;
$httpProvider.interceptors.push(function ($q, $timeout, Config, $log) {
return {
'request': function (config) {
$log.log('Requesting ' + config.url, config);
return config;
},
'response': function (response) {
var deferred = $q.defer();
if(response.config.url.indexOf(Config.viewDir) == 0) return response; //Let through views immideately
//Fake delay on response from APIs and other urls
$log.log('Delaying response with ' + Config.API.fakeDelay + 'ms');
$timeout(function () {
deferred.resolve(response);
}, Config.API.fakeDelay);
return deferred.promise;
}
}
})
})
.factory('APIBase', function (Config) {
return (Config.API.protocol + '://' + Config.API.host + ':' + Config.API.port + Config.API.path + '/');
})
.constant('regexEscape', function regEsc(str) {
//Escape string to be able to use it in a regular expression
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
})
.run(function (Config, $httpBackend, $log, APIBase, $timeout, regexEscape) {
//Only load mocks if config says so
if(!Config.API.useMocks) return;
var collectionUrl = APIBase + 'tags';
var IdRegExp = /[\d\w-_]+$/.toString().slice(1, -1);
var QueryRegExp = /[\d\w-_\.%\s]*$/.toString().slice(1, -1);
var id = 0;
var TagRepo = {};
TagRepo.data = [
{id: id++, text:'Javascript'},
{id: id++, text:'Angular'},
{id: id++, text:'.NET'},
{id: id++, text:'Java'},
{id: id++, text:'Firebase'},
{id: id++, text:'Ember'},
{id: id++, text:'generator-angular-xl'},
];
TagRepo.index = {};
angular.forEach(TagRepo.data, function(item, key) {
TagRepo.index[item.id] = item; //Index messages to be able to do efficient lookups on id
});
//GET tag/
$httpBackend.whenGET(collectionUrl).respond(function(method, url, data, headers) {
$log.log('Intercepted GET to tag', data);
return [200, TagRepo.data, {/*headers*/}];
});
//GET tag/<id>
$httpBackend.whenGET( new RegExp(regexEscape(collectionUrl + '/') + IdRegExp ) ).respond(function(method, url, data, headers) {
$log.log('Intercepted GET to tag/id');
var id = url.match( new RegExp(IdRegExp) )[0];
var Tag = TagRepo.index[id];
if (!Tag) {
return [404, {} , {/*headers*/}];
}
return [200, Tag, {/*headers*/}];
});
//POST tag/
$httpBackend.whenPOST(collectionUrl).respond(function(method, url, data, headers) {
$log.log('Intercepted POST to tag', data);
var Tag = angular.fromJson(data);
Tag.id = id++;
TagRepo.data.push(Tag);
TagRepo.index[Tag.id] = Tag;
return [200, Tag, {/*headers*/}];
});
//GET tag/search?q=<query>
$httpBackend.whenGET( new RegExp(regexEscape(collectionUrl + '/search?q=') + QueryRegExp ) ).respond(function(method, url, data, headers) {
$log.log('Intercepted GET to tag/search');
var term = url.match( new RegExp(QueryRegExp) )[0] || '';
var hits = TagRepo.data.filter(function (tag) {
return tag && typeof tag.text == 'string' && tag.text.toLowerCase().indexOf(term.toLowerCase()) >= 0;
});
return [200, hits, {/*headers*/}];
});
//PUT tag/<id>
$httpBackend.whenPUT( new RegExp(regexEscape(collectionUrl + '/') + IdRegExp ) ).respond(function(method, url, data, headers) {
$log.log('Intercepted PUT to tag');
var id = url.match( new RegExp(IdRegExp) )[0];
if (!TagRepo.index[id]) {
return [404, {} , {/*headers*/}];
}
var Tag = TagRepo.index[id] = angular.fromJson(data);
return [200, Tag, {/*headers*/}];
});
//DELETE tag/<id>
$httpBackend.whenDELETE( new RegExp(regexEscape(collectionUrl + '/') + IdRegExp ) ).respond(function(method, url, data, headers) {
$log.log('Intercepted DELETE to tag');
var id = url.match( new RegExp(IdRegExp) )[0];
var Tag = TagRepo.index[id];
if (!Tag) {
return [404, {} , {/*headers*/}];
}
delete TagRepo.index[Tag.id];
var index = TagRepo.data.indexOf(Tag);
TagRepo.data.splice(index, 1);
return [200, Tag , {/*headers*/}];
});
});
@amitaibu
Copy link

amitaibu commented Mar 6, 2014

Thanks for this. Is it working for you when Angular is trying to fetch a view? I see there's a code that deals with it, but I'm still getting Unexpected request: GET views/main.html errors.

@amitaibu
Copy link

amitaibu commented Mar 7, 2014

Found the problem. The gist is currently missing this statement, in the end of all the $httpBackend.when*:

// pass through everything else.
$httpBackend.whenGET(/\/*/).passThrough();

@kennethlynne
Copy link
Author

Thank you for clarifying. :)

Here is a working example: http://codepen.io/kennethlynne/pen/lJbce

@lucasfeliciano
Copy link

I'm using some parts of your code and I'm having the same problem @amitaibu had, tried his solution with no success.

the response function it is even called.

'use strict';

angular.module('blakerFrontApp')
.config(function($provide) {
  $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
})
.config(function ($httpProvider) {
  $httpProvider.interceptors.push(function($q, $timeout, $log) {
    return {
      'request': function(config) {
        var deferred = $q.defer(),
        //Simulando latencia de rede
        delay = _.random(200, 3000);

        $timeout(function() {
          $log.log('Request ' + config.url , ' Delayed: ' + delay , config);
          deferred.resolve(config);
        }, delay);

        return deferred.promise;
        //return config;
      },
      'response': function(response) {
        var deferred = $q.defer(),
        delay = _.random(200, 3000);
        if (response.config.url.indexOf('views/') === 0) {
          return response;
        }

        $timeout(function() {
          $log.log('Response ' + response.config.url , ' Delayed: ' + delay , response);
          deferred.resolve(response);
        }, delay);

        return deferred.promise;
      }

    };
  });
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment