Gradle 5.0 and Runtime Dependencies

I recently ran into a problem with CI, where an upgrade to Gradle 5 in their containers broke all of my builds. It seemed like some of the nested dependencies weren’t being downloaded and therefore not found at compile time, so I was getting a ton of Java compilation errors:

package xxxxx does not exist.

My leading theory is this was a consequence of Gradle 5 separating out compile and runtime dependencies.

So, I suspect that some of my dependencies list their dependencies as runtime dependencies, which had previously been included at compilation time by default. However, with Gradle 5 not doing that anymore, the nested dependencies were not being downloaded at compile time and therefore missing. Since I don’t have control of these third-party libraries, I had to explicitly list the missing dependencies as my own compile dependencies to work around the compilation errors.

Angular In-Memory-Web-Api For E2E Testing

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;
  }