Recently, I updated an Angular app with an HTTP interceptor to handle HTTP exceptions, from this tutorial — what an amazingly simple way to add that kind of feature! While adding an alert window to notify the user of a failed REST call was simple, I then found out that my e2e tests with Protractor failed because I didn’t have a live backend during the tests … which meant that my alert windows popped up automatically during each e2e test. I couldn’t figure out how to mock out my REST API, though. nock
wasn’t working at all, and it seems like Angular took out their $httpMockBackend
(plus Protractor doesn’t play well with it, even if it was still present).
Then, I stumbled upon the In-Memory-Web-Api for Angular, and it seemed like the perfect solution. However, turns out it doesn’t automagically work for nested REST URLs, i.e. api/namespace/resources
and api/namespace2/entities
— it has a very strict expectation for the REST API pattern by default, which I didn’t understand from the documentation. It assumes that the first path element after the apiBase
(in the config) is the collection name, and the second is the element id
— for example, namespace
would be the collection and resources
the id
of a given namespace
entity. i.e.
GET /api/resources
GET /api/resources/1
would work with the default methods, but
GET /api/students/resources
GET /api/students/resources/1
GET /api/teachers/resources
GET /api/teachers/resources/5
would require some customization.
So if your API pattern is a little different, you have to get creative. What I wound up doing was to parse all the get
requests per my own pattern, similar to this example, which is duplicated below:
// HTTP GET interceptor
get(reqInfo: RequestInfo) {
const collectionName = reqInfo.collectionName;
if (collectionName === 'villains') {
return this.getVillains(reqInfo);
}
return undefined; // let the default GET handle all others
}
You can also create a custom URL parser, which is probably cleaner than my hack. Code duplicated below:
// parseRequestUrl override
// Do this to manipulate the request URL or the parsed result
// into something your data store can handle.
// This example turns a request for `/foo/heroes` into just `/heroes`.
// It leaves other URLs untouched and forwards to the default parser.
// It also logs the result of the default parser.
parseRequestUrl(url: string, utils: RequestInfoUtilities): ParsedRequestUrl {
const newUrl = url.replace(/\/foo\/heroes/, '/heroes');
// console.log('newUrl', newUrl);
const parsed = utils.parseRequestUrl(newUrl);
console.log(`parseRequestUrl override of '${url}':`, parsed);
return parsed;
}