Angular 7 Http Mock Interceptors

All this API does is return some JSON?

Abraham Lincoln

When working on a project that heavily depends on RESTful data calls, there’s nothing worse than a back-end environment crashing. Development is forced to come to a halt and the whole experience can be incredibly infuriating. As someone who was sick of dealing with this issue, I decided to research methods of implementing a mock-tier layer into my Angular applications.

Why Use a Mock Interceptor?

A refreshing 500 internal server error

Efficiency. Imagine a world where you never had to deal with 500 Internal Server Error responses or wait for an environment to update. Most modern web applications just deal with JSON returned by an API, so why not just artificially mock these calls and provide dummy JSON when working locally? This would allow for an unlimited amount of server crashes and environmental updates to occur, all without ever hindering on the front-end developer’s ability to further work on the application. Fortunately, using Angular’s built in Http Interceptor functionality allows us to easily do this. This posts assumes you have basic knowledge of making Http requests in Angular.

But, Wait! This Seems Too Good to Be True!

While mock interceptors may be the answer to not having to rely on the stability of back-end environments, using it does come with some caveats. At the end of the day, you still need to make sure the web application works with real data returned from the server. This is the data users will be receiving, and if there really is a problem with your API, it needs to be addressed before deploying your application to a production environment.

Setting up a Mock JSON Server Run Time

Let’s start by adding the JSON server and concurrent libraries to our Angular application:

yarn add json-server && yarn add concurrently

By leveraging these libraries, we can concurrently run a JSON server alongside our application when developing in a local environment. Modify the scripts section of your project’s package.json file with the following changes:

  1. A run time that concurrently runs a JSON server alongside your application, represented by “start”
  2. A run time script that runs the application standalone with the production environment enabled, represented by “start:prod”
// package.json
"scripts": {
...
    "start": "concurrently --kill-others \"ng serve\" \"json-server --watch db.json\"",
    "start:prod": "ng serve --configuration production",
...
  }

We will create a db.json file for the JSON server to use and explain the use of the configuration flag in the next section.

Creating a Database

Let’s create a db.json file and define the “/todo” endpoint in the root of our project:

// db.json

{
    "todo": 
        {
            "userId": 1,
            "id": 1,
            "title": "this was intercepted",
            "completed": false
        }
}

Now, when our project is ran using the “start” run time script, json-server intercepts all requests made to localhost:3000 and is able to perform basic CRUD operations. When a GET request is made to “localhost:3000/todo”, the local server will return the data as defined in this file as JSON.

Creating a Http Interceptor

We now need to create an interceptor that is used on all http requests. To do this, create a file called interceptor.ts under your src/app directory:

// src/app/interceptors/interceptor.ts
import { Injectable } from '@angular/core';
import {
    HttpEvent, HttpInterceptor, HttpHandler, HttpRequest
} from '@angular/common/http';

import { Observable } from 'rxjs';
import { environment } from 'src/environments/environment';

/** Pass untouched request through to the next request handler. */
@Injectable()
export class Interceptor implements HttpInterceptor {

    intercept(req: HttpRequest<any>, next: HttpHandler):
        Observable<HttpEvent<any>> {
        console.log('intercepted ' + req.url);
        if (!environment.prod) {
            return next.handle(req.clone({ url: 'http://localhost:3000/todo' }));
        } else {
            return next.handle(req);
        }
    }
}

Your environment.ts and environment.prod.ts should have a “prod” attribute that is set to false and true, respectively:

// src/environments/environment.ts
export const environment = {
  production: false
};
// src/environments/environment.prod.ts
export const environment = {
  production: true
};

Next, let’s provide the newly created interceptor inside app.module.ts:

// src/app/app.module.ts
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { Interceptor } from './interceptors/noop-interceptor';
...
providers: [
    { provide: HTTP_INTERCEPTORS, useClass: Interceptor, multi: true }
  ]
...

Now, all requests will be routed through our interceptor. If the prod environmental flag is set to false, the JSON server, running on port 3000, will deliver dummy data defined in db.json.

Using our Mock Interceptor

Run your application using the “start” run time script. Now, all GET requests made will be intercepted by the JSON server and the dummy data defined in db.json will be returned.

The source code for this post can be seen here: https://github.com/AlexKopen/Angular-Http-Interceptor