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
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:
- Install Docker Community Edition
- Docker image:
angular-rgr,
basically after Docker installed run command:
$ docker pull andrewrgr/angular-rgr
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:
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:
Console Message
Opening up the browser’s web console (by right clicking and selecting
Inspect page
), you will see:
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 theapp.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.