Red Green Repeat Adventures of a Spec Driven Junkie

Angular Services - HTTP

I continue my previous article on setting up Angular services by adding HTTP support to the Angular app. This will focus on how to set up an Angular app to connect an external server.

There needs to be some internal setup for the Angular framework for this to happen:

  • Import HttpClientModule
  • Connect HTTP module in the Service component
  • Connect App Component with the Service component

Angular
Logo

Motivation

I am ‘hacking my way’ through to connecting a basic Angular app to a web server, I find I learn more about Angular this way than by doing than reading a chapter or copying lesson code. Like taking the shortest path to getting working code. I love tests, but working code teaches a lot too, especially in a framework!

Requirements

We are building from the previous article, the requirements are similar:

If you would like to follow with the code, the code is available here

The completed code is here

HTTP Response File

I want to start by adding the response I expect the server to send when connecting. This will make sure I have setup the Angular app to receive HTTP requests properly and not worry about external server configurations. I want to debug one application at a time not two.

The response will be simple so I have made a file, named result.json, to have content:

{
  "value": 4200
}

I save the file in the assets/ directory so it is accessible to the app. Thanks to Gabe O’Leary for this answer. I could not serve this file using other methods.

Setting up the URL

In the NumberGeneratorService class, I add a private variable to save the URL that the HTTP service will get the response from:

export class NumberGeneratorService {
  private _HTTPFileURL = 'assets/result.json';
  ...
}

Ideally, when switching to an external server, only this line will have to change within the Angular app. Everything else in the app would stay the same.

Let’s test that the file is accessible in browser, launch Angular app:

$ cd number-generator-service
$ docker run --mount type=bind,source="$(pwd)",target=/angular -p 4200:4200 angular-rgr ng serve

In a new browser, navigate to: localhost:4200/assets/result.json

One should see:

Angular Service
result.json

If you do not see this, contact me so we can figure out the problem. This is a critical step in the whole HTTP setup testing process.

Importing HttpClientModule

After setting up the response file, we have to add the HttpClientModule so the Angular app can handle interfacing with HTTP servers.

I will add HttpClientModule to app.module.ts, so it is accessible within any part of app.

The app.module.ts file will have an additional import at the top of the file and entry on imports on the class line. The app.module.ts file now look like:

import { HttpClientModule } from '@angular/common/http';
...
   imports: [
    BrowserModule,
    HttpClientModule
   ],
   providers: [],

Making HTTP call in NumberGeneratorService

After getting the HTTPClientModule and the result.json file set up, it’s time to connect these together in the NumberGeneratorService class. This service will do the bulk of the connection work.

Import Headers

There are headers required for HTTP support, at the top of the number-generator.service.ts file, add:

import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
Library Explanation
HttpClient The library to handle client interactions with an HTTP server.
Observable Handles HTTP responses asynchronously.
rxjs/add/operator/do This add the do operator so it is easier to debug the observable.

From my understanding, observable are basically a super-powered version of a Promise, which handles external connections like this. In Angular, they are the recommended way managing external connections, so I will use them here.

Inject Dependencies

With required imports taken care of, to use the HttpClient, we inject dependencies. Basically, we have Angular pass in the HttpClient in and assign the value to a variable for access.

In the constructor section of the NumberGeneratorService, change the line from:

constructor() { }

to be:

constructor(private _http: HttpClient) { }

Now, when loading this service component, the Angular framework will automatically pass in the imported HttpClient and assign it to the class’ private variable: _http.

Connecting Functions

With the basics setup for the service class, let’s connect the HTTP Client to a function in the class:

This is the function we add in the class’ body:

valueHTTPFile(): Observable<any> {
  return this._http.get<any>(this._HTTPFileURL)
             .do(data => console.log('All: ' + JSON.stringify(data)))
}

This function is simple, but there are two subtle parts:

Observable<any> The function return is not the server response, but an observable that is of type any.
do(data =>) This allows us to ‘peek’ into the function and print out the response.

Observable<any>

One cool thing with using TypeScript is one can assign a specific type to the response.

One application of types in our situation: the payload format. If the response format will always have certain fields, create a specific type for it.

Assigning the payload type to this observable will guarantee only those responses that fit the type to flow through, otherwise, they will error.

In our situation, we will keep things flexible and use the <any> type.

do

The do function is a great way to debug a functional call, such as map & reduce, by being able to spy in the middle of the call chain.

.do(data => console.log('All: ' + JSON.stringify(data)))

In this case, print all the data received to the web console. A great way to verify what’s going on without disturbing the call chain or saving the data in a temporary variable.

Setting Up App Component

With the service component completed, we need to hook it up into the main app.component.

I will use OnInit function as a way to make the HTTP call so the app fetches the server value once, instead of multiple, multiple times. (Try it once you have things working!)

ngOnInit

To have the Angular framework call a custom process:

  • import OnInit from @angular/core
  • declare the class implements the OnInit method
  • create an ngOnInit function

The equivalent code snippets in the section of the app.component.ts file are:

import { Component, OnInit } from '@angular/core';
...
export class AppComponent implements OnInit {
...
  ngOnInit(): void {
    ...
  }
}

Storing Response

As the ngOnInit function will call the NumberGeneratorService.HTTPfile() function to get the value, we will store the value in a private variable.

The value will be accessible in the app.component.html as: valueHTTPFile. This declares the variable as a class variable of the AppComponent class.

export class AppComponent implements OnInit {
  valueHTTPFile: number;
  ...
}

Connecting to Service

To set the valueHTTPFile variable, we create another function to set the value that connects to the service component:

fromNumberGeneratorServiceHTTPFile() {
  this._numberGeneratorService.valueHTTPFile()
      .subscribe(value => this.valueHTTPFile = value.value);
}

The fromNumberGeneratorServiceHTTPFile function subscribes to the valueHTTPFile() function because valueHTTPFile() is an observable.

On success, this assigns the returned value, value.value to the class’ private variable: valueHTTPFile.

ngOnInit Connection

To have ngOnInit call the fromNumberGeneratorServiceHTTPFile function, set up the function as:

 ngOnInit(): void {
   this.fromNumberGeneratorServiceHTTPFile();
 }

App Component View

Now for the final part: getting the value to display. This means changing app.component.html to display the value by adding to the current list::

<li>value of app.component fromNumberGeneratorServiceHTTPFile(): </li>
<li>value of app.component fromNumberGeneratorServiceHTTPFile(): </li>

Result

Save these changes, start the Angular app from the application’s directory using docker command:

$ cd number-generator-service
$ docker run --mount type=bind,source="$(pwd)",target=/angular -p 4200:4200 angular-rgr ng serve

Open a web browser to address: localhost:4200 and see:

Angular Service from HTTP
Result

Console Message

Opening up the browser’s web console (by right clicking and selecting Inspect page), you will see:

Angular Service from HTTP Console
Result

This is the message from the do command in the NumberGeneratorService.valueHTTPFile()!

Conclusion

So, we have set up all the required parts of an Angular app to support a basic HTTP connection to load local data.

  • We imported the HttpClientModule in the app.module so it is accessible throughout the app.
  • We configured service component to read from a pre-made response file, result.json.
  • The main app.component connects to the service component to display the value from the file.

Again, the completed code is here.