Intercepting Http Requests-- Using And Testing Angular's HttpClient
Tags: angular, testing, javascript, programming
Published: 2017-08-28 18:28:13

---
title: Intercepting Http Requests-- Using And Testing Angular's HttpClient
published: true
description: A brief overview with code samples and unit test examples using Angular's HttpClient
tags: angular,testing,javascript,programming
cover_image: "https://raw.githubusercontent.com/alisaduncan/tutorial-angular-httpclient/master/messageWithText.jpg"
---

The `HttpClientModule`, which debuted in Angular 4.3, is an easy to use API. It automatically expects json as its default response type, builds in the ability to intercept both requests and responses, and makes testing a breeze. 

I recently worked on converting calls to use `HttpClientModule` from `HttpModule`. While working on this project I had a hard time finding good resources and examples, especially examples of tests. So I decided to write a simple app that uses `HttpClientModule` along with corresponding unit tests as an example with a little more *oomph* than what’s available on [Angular’s documentation](https://angular.io/guide/http#httpclient). It’s not perfect as I’m still learning myself, but I hope you’ll find it helpful.

## Update
6/10/2018- The code examples in this post and the code in the GitHub repo now uses Angular v6.

## Assumptions
This tutorial assumes you have some familiarity with Angular, angular-cli, Material2 libraries, Jasmine, calling REST apis,... The scope of this tutorial is only using the `HttpClientModule` and the associated unit tests for making http calls.

## Background
Using angular-cli, I generated a new application and used Material 2 starter app as a base for the design and for the cute icons. angular-cli was used to generate all the scaffolding for the services, components, and classes. I used [JSONPlaceholder API](https://jsonplaceholder.typicode.com/) to GET and POST user information. Complete app and code can be found [in my GitHub repo](https://github.com/alisaduncan/tutorial-angular-httpclient "https://github.com/alisaduncan/tutorial-angular-httpclient").


## Creating A User Service
The User Service wraps functionality to create and retrieve user information. This is where we will use `HttpClient`. In the method `getUsers()` notice that we no longer have to map the response to json format. We can also declare the type for the response data. I’m using an incredibly unhelpful `Array<any>` but that’s just to show the syntax. 

```javascript
  public getUsers(): Observable<User[]> {
    return this.http.get<Array<any>>(this.apiEndpoint, {
      headers: new HttpHeaders().set('Accept', 'application/json')
    }).pipe(
      map(this.mapUsers),
      catchError(error => {
        return observableThrowError('An error occurred');
      }),
    );
  }
```

Don’t forget to add `HttpClientModule` to _app.module.ts_ imports.

## Testing The User Service
Angular made a lot of improvements to testing http calls via the `HttpClientTestingModule` and `HttpClientTestingController`. Simply import the `HttpClientTestingModule` into the `TestBed` and inject both the `HttpClient` and `HttpTestingController` into the tests. 

```javascript
describe('UserService', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [UserService]
    });
  });

  afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => {
    httpMock.verify();
  }));
```

In the test, you mock out a http response and then simulate the http call by flushing `TestRequest`. You can assert on the http method, expected response, expected headers, and the number of times the http call is made.  You’ll want an `afterEach` method to verify that no more requests remain to be consumed. Here’s a happy path example to verify my response filtering and mapping works.

```javascript
it('returns users with an id <= 5', inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
      const mockResponse = [
        {
          id: 5,
          name: 'Test5',
          company: {bs: 'blah'}
        },
        {
          id: 6,
          name: 'Test6',
          company: {bs: 'blah'}
        }
      ];

      const userService = getTestBed().get(UserService);
      userService.getUsers().subscribe(
        actualUsers => {
          expect(actualUsers.length).toBe(1);
          expect(actualUsers[0].id).toEqual(5);
        }
      );

      const req = httpMock.expectOne(userService.apiEndpoint);
      expect(req.request.method).toEqual('GET');

      req.flush(mockResponse);
      httpMock.verify();
    }));
```

Testing the unhappy path isn’t hard at all. 

```javascript
it('should throw with an error message when API returns an error',
      inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
        const userService = getTestBed().get(UserService);
        userService.getUsers().subscribe({
          error(actualError) {
            expect(of(actualError)).toBeTruthy();
            expect(actualError).not.toBeNull();
            expect(actualError).not.toBeUndefined();
          }
        });

        const req = httpMock.expectOne(userService.apiEndpoint);
        expect(req.request.method).toEqual('GET');

        req.flush({ errorMessage: 'Uh oh!' }, { status: 500, statusText: 'Server Error' });
        httpMock.verify();
      }));
```

## Intercepting Calls
In a real app, we need to authenticate our requests. So we can create our own interceptor by implementing Angular’s `HttpInterceptor` interface. In this example, I add an Authorization header to each of my calls. I created a fake authentication service to spoof token retrieval and inject the authentication service to better mimic real life and form my token.

```javascript
export class AuthInterceptor implements HttpInterceptor {
  constructor(private authService: AuthService) {}
 
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  const authReq = req.clone({setHeaders: {Authorization: `${this.authService.tokenType} ${this.authService.tokenValue}`}});
    return next.handle(authReq);
  }
}
```

In order to use the interceptor, we have to provide it to the _app.module.ts_.

```javascript
providers: [UserService, AuthService,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true
    }],
```

Now all calls made using `HttpClient` will include the Authorization header.

## Testing Interceptors
Just like before, you need to prep the `Testbed`. But this time we’re also going to provide the interceptor. I’m also providing a mock to the authentication service.

```javascript
beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [HttpClientTestingModule],
            providers: [
                {
                    provide: AuthService,
                    useValue: mockAuthService
                },
                {
                    provide: HTTP_INTERCEPTORS,
                    useClass: AuthInterceptor,
                    multi: true
                }]
        });
    });
```

Testing the interceptor is pretty much the same as testing the User Service. Except in this case we’ll customize the verification to check for the header.

```javascript
describe('making http calls', () => {
        it('adds Authorization header', inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {

            http.get('/data').subscribe(
                response => {
                    expect(response).toBeTruthy();
                }
            );

            const req = httpMock.expectOne(r =>
                r.headers.has('Authorization') &&
                r.headers.get('Authorization') === `${mockAuthService.tokenType} ${mockAuthService.tokenValue}`);
            expect(req.request.method).toEqual('GET');

            req.flush({ hello: 'world' });
            httpMock.verify();
        }));
    });
```


That’s all I have for now. I hope you found this useful. All my code can be found [in my GitHub repo](https://github.com/alisaduncan/tutorial-angular-httpclient "https://github.com/alisaduncan/tutorial-angular-httpclient"). Please feel free to check it out and I’m open to any feedback you have.