Angular HTTP Book
Angular HTTP Book
Note: see details at the end of this book for getting the Free Angular For
Beginners Course, plus a bonus content Typescript Video List.
HTTP Headers
HTTP PUT
HTTP PATCH
HTTP DELETE
HTTP POST
HTTP Interceptors
Introduction
Welcome to the Angular HTTP Jumpstart Book, thank you for joining!
Like the title says, the goal of the book is to get you proficient quickly
with the New Angular HTTP Client.
The goal is to give here a complete guide on how to do HTTP and REST
in Angular applications in general.
I hope you will enjoy this book, please send me your feedback at
admin@angular-university.io.
Note: The code for this book is also available in this repository, as a
running example.
Section The New Angular HTTP
Module
Introduction to the new HTTP module
The multiple versions of the Angular HTTP module all have an RxJS
Observable-based API. This means that the multiple calls to the HTTP
module will all return an observable, that we need to subscribe to one
way or the other.
Here are some key things to bear in mind regarding this particular type
of Observables returned by the HTTP module:
With this in mind, let's have a look at some of the most common tasks
that we will come across using the HTTP library.
2
3 @NgModule({
4 declarations: [
5 AppComponent
6 ],
7 imports: [
8 BrowserModule,
9 HttpClientModule
10 ],
11 providers: [],
12 bootstrap: [AppComponent]
13 })
15 }
16
This is not the most common way to query Firebase, as we usually use
AngularFire together with the Firebase SDK, but there is also REST
support available.
6
7 interface Course {
8 description: string;
9 courseListIcon:string;
10 iconUrl:string;
11 longDescription:string;
12 url:string;
13 }
14
15 @Component({
16 selector: 'app-root',
17 template: `
20 {{course.description}}
21 </li>
22 </ul>
24 `})
26 courses$: Observable<Course[]>;
27
28 constructor(private http:HttpClient) {
29 }
30
31 ngOnInit() {
32 this.courses$ = this.http
33 .get<Course[]>("/courses.json")
34 .map(data => _.values(data))
35 .do(console.log);
36 }
37 }
38
39
This example is using the HTTP module in a small component, that is
displaying a list of courses. Let's break down this example step-by-step:
the async pipe will subscribe to the HTTP observable, and it's
that implicit subscription that triggers the HTTP request
The end result is that the descriptions of all the courses in the database
will show up listed on the screen, in a bulleted list.
of courses.
If we don't specify a type parameter, then the result of the call to get()
will be an Observable<Object> instead.
https://angular-http-guide.firebaseio.com/courses.json?
orderBy="$key"&limitToFirst=1
This query will take the same results as before, but this time ordered by
the $key property. The first URL parameter that we have in this URL is
orderBy , and the second is limitToFirst .
This is is how we would do this query using the Angular HTTP Client:
1
2 import {HttpParams} from "@angular/common/http";
3
4 const params = new HttpParams()
5 .set('orderBy', '"$key"')
6 .set('limitToFirst', "1");
7
8 this.courses$ = this.http
9 .get("/courses.json", {params})
10 .do(console.log)
11 .map(data => _.values(data))
12
Notice that we are building the HTTPParams object by chaining
successive set() methods. This is because HTTPParams is immutable,
and its API methods do not cause object mutation.
1
2 const params = new HttpParams();
3
4 params.set('orderBy', '"$key"')
5 params.set('limitToFirst', "1");
If we try to populate our parameters like this, we will not have the
expected result. Instead, we would have an empty HTTPParams object,
and the two calls to set would have add no effect.
1
2 const params = new HttpParams({
3 fromString: 'orderBy="$key"&limitToFirst=1'
4 });
5
1
2 const params = new HttpParams({
3 fromString: 'orderBy="$key"&limitToFirst=1'
4 });
5
6 this.courses$ = this.http
7 .request(
8 "GET",
9 "/courses.json",
10 {
11 responseType:"json",
12 params
13 })
14 .do(console.log)
16
HTTP Headers
If we want to add custom HTTP Headers to our HTTP request, in
addition to the headers the browser already attaches automatically we
can do so using the HttpHeaders class:
1
2 const headers = new HttpHeaders()
3 .set("X-CustomHeader", "custom header value");
4
5 this.courses$ = this.http
6 .get(
7 "/courses.json",
8 {headers})
9 .do(console.log)
This configuration object only has one property named headers , just
like the local const that we defined - so we used the object short-hand
creation notation to define the configuration object.
HTTP PUT
Just like in the case of GET, we can also use the Angular HTTP Client to
do all the other available HTTP methods, namely the methods typically
used for data modification such as PUT.
The PUT method should only be used if we want to fully replace the
value of a resource. For example, we would use PUT if we want to
overwrite a course object with a completely new version of that same
course object:
1
2 httpPutExample() {
3
4 const headers = new HttpHeaders()
5 .set("Content-Type", "application/json");
6
7 this.http.put("/courses/-KgVwECOnlc-LHb_B0cQ.json",
8 {
9 "courseListIcon": ".../main-page-logo-small-hat.png",
10 "description": "Angular Tutorial For Beginners TEST",
11 "iconUrl": ".../angular2-for-beginners.jpg",
12 "longDescription": "...",
13 "url": "new-value-for-url"
14 },
15 {headers})
16 .subscribe(
17 val => {
20 },
21 response => {
22 console.log("PUT call in error", response);
23 },
24 () => {
25 console.log("The PUT observable is now completed.");
26 }
27 );
28 }
29
{courseListIcon: "https://angular-
academy.s3.amazonaws.com/main-logo/main-page-logo-small-
hat.png", description: "Angular Tutorial For Beginners
TEST", iconUrl: "https://angular-
academy.s3.amazonaws.com/thumbnails/angular2-for-
beginners.jpg", longDescription: "...", url: "new-value-
for-url"}
The PUT observable is now completed.
So as we can see, the PUT call will replace the whole content of the
course path with a new object, even though we usually only want to
modify a couple of properties.
Also, the response body of the PUT call will contain the new version of
the course object that was created after the upload. In some cases, this
might be a lot of data.
HTTP PATCH
Most often than not, instead of providing a completely new version of a
resource, what we want to do is to just update a single property. And this
is the main use case for the use of the HTTP PATCH method!
For example, here is how we would update only the course description:
1
2 httpPatchExample() {
3
4 this.http.patch("/courses/-KgVwECOnlc-LHb_B0cQ.json",
5 {
7 })
8 .subscribe(
9 (val) => {
11 val);
12 },
13 response => {
15 },
16 () => {
17 console.log("The PATCH observable is now completed.");
18 });
19 }
20
As we can see, the PATCH method returns only the new version of the
modified values, that we already sent initially.
HTTP DELETE
Another frequent operation that we want to do is to trigger a logical
delete of some data. This operation can completely wipe the data from
our database, or simply mark some data as deleted. This is an example
of how we would delete a given course:
1
2 httpDeleteExample() {
3
4 this.http.delete("/courses/-KgVwECOnlc-LHb_B0cQ.json")
5 .subscribe(
6 (val) => {
10 response => {
13 () => {
16 }
17
In the case of Firebase, this completely removes the object from the
database, but we can imagine other REST APIs where only a logical
delete would occur.
HTTP POST
If the operation that we are trying to do does not fit the description of
any of the methods above (GET, PUT, PATCH, DELETE), then we can use
the HTTP wildcard modification operation: POST.
1 httpPostExample() {
2
3 this.http.post("/courses/-KgVwECOnlc-LHb_B0cQ.json",
4 {
5 "courseListIcon": "...",
6 "description": "TEST",
7 "iconUrl": "..",
8 "longDescription": "...",
9 "url": "new-url"
10 })
11 .subscribe(
12 (val) => {
15 },
16 response => {
17 console.log("POST call in error", response);
18 },
19 () => {
20 console.log("The POST observable is now completed.");
21 });
22 }
23
And here the results that show in the console when this POST request
gets executed:
1
2 duplicateRequestsExample() {
3
4 const httpGet$ = this.http
5 .get("/courses.json")
7
8 httpGet$.subscribe(
10 );
11
12 this.courses$ = httpGet$;
13 }
14
This makes shareReplay ideal for handling things like caching AJAX
results, as it's retryable
1
2 // put this next to the other RxJs operator imports
3 import 'rxjs/add/operator/shareReplay';
4
5 const httpGet$ = this.http
6 .get("/courses.json")
7 .map(data => _.values(data))
8 .shareReplay();
With the shareReplay operator in place, we would no longer fall into the
situation where we have accidental multiple HTTP requests.
And this covers the main use cases for doing the most typical read and
modification operations, that we would implement while doing a custom
REST API.
Let's now see some other very frequent use cases, plus some more new
features of the Angular HTTP client.
1
2 import 'rxjs/add/observable/forkJoin';
3
4 parallelRequests() {
5
6 const parallel$ = Observable.forkJoin(
7 this.http.get('/courses/-KgVwEBq5wbFnjj7O8Fp.json'),
8 this.http.get('/courses/-KgVwECOnlc-LHb_B0cQ.json')
9 );
10
11 parallel$.subscribe(
12 values => {
14 }
15 );
16 }
17
This new observable will only emit a value when the two GET
observables emit their value. The value of the combined observable will
be an array containing the multiple results of each GET request.
1
2 sequentialRequests() {
3
4 const sequence$ = this.http.get<Course>(
5 '/courses/-KgVwEBq5wbFnjj7O8Fp.json')
6 .switchMap(course => {
7
8 course.description+= ' - TEST ';
9
10 return this.http.put(
11 '/courses/-KgVwEBq5wbFnjj7O8Fp.json',
12 course)
13 });
14 sequence$.subscribe();
15
16 }
17
If we don't use the generic type, then the inferred type of the course
variable would be Object , but using this parameter the inferred type is
now Course , which gives us auto-completion inside the function passed
to switchMap .
Let's then break down how this switchMap HTTP request chain works:
we are de ning a source HTTP GET request that reads the data
of a course
For example, we can also use it in this other closely related use case.
But the result observable did not have the data of the first request,
instead it only had access to the data of the second HTTP request.
If we would like to have both the data of the first HTTP request and
deliver it together with the data of the second request, we could use a
selector function (notice the second argument passed to switchMap ):
1
2 sequentialRequests() {
3
4 const sequence$ = this.http.get<Course>(
5 '/courses/-KgVwEBq5wbFnjj7O8Fp.json')
6 .switchMap(course => {
9 },
12
13 sequence$.subscribe(
14 values => console.log("result observable ", values)
15 );
16
17 }
18
19
The emitted values of the outer result observable with then become an
array that contains the two value emitted by each HTTP request in the
chain.
Notice that selector functions are not unique to the switchMap operator,
they can be used in many other operators.
There is support for many common error handling use cases, but in the
case of HTTP requests here is a very common functionality for error
handling:
then we want to still emit some sort of default value for the
HTTP stream so that the screens consuming the data still
display something useful to the user
This is how we would implement this use case using the RxJs catch
operator:
1
2 throwError() {
3
4 this.http
5 .get("/api/simulate-error")
10
11 return Observable.of({description: "Error Value Emitted"});
12 })
13 .subscribe(
14 val => console.log('Value emitted successfully', val),
15 error => {
17 },
19 );
20 }
21
To understand this example, let's have a look first at the console output:
Error catched
The HTTP call occurred and an error was thrown in our test
server
This operator creates one observable that only emits one value
(the object passed to Observable.of() ), and then it completes
HTTP Interceptors
A new feature available in the new HTTP client is HTTP Interceptors. An
HTTP Interceptor allows us to add some generic functionality to all our
HTTP requests in only one place.
Interceptors are ideal for cross-cutting concerns like for example adding
an authentication token header transparently to all the requests made
by the HTTP client.
1
2 import {Injectable} from "@angular/core";
7
8 @Injectable()
12 }
13
14 intercept(req: HttpRequest<any>,
15 next: HttpHandler):Observable<HttpEvent<any>> {
16
17 const clonedRequest = req.clone({
18 headers: req.headers.set(
19 'X-CustomAuthHeader',
20 authService.getToken())
21 });
23 return next.handle(clonedRequest);
24 }
25 }
26
27
The cloned request will now have the new HTTP header X-
CustomAuthHeader
1
2 @NgModule({
3 declarations: [
4 AppComponent
5 ],
6 imports: [
7 BrowserModule,
8 HttpClientModule
9 ],
10 providers: [
13 ],
14 bootstrap: [AppComponent]
15 })
16 export class AppModule {
17 }
18
1
2 longRequest() {
3
4 const request = new HttpRequest(
6 {reportProgress: true});
7
8 this.http.request(request)
9 .subscribe(
10 event => {
11
12 if (event.type === HttpEventType.DownloadProgress) {
14 }
15
16 if (event.type === HttpEventType.UploadProgress) {
17 console.log("Upload progress event", event);
18 }
19
20 if (event.type === HttpEventType.Response) {
22 }
23
24 }
25 );
26 }
27
By creating the request like this, we are receiving all the following HTTP
events:
an initial upload event when the request gets fully sent to the
server
a download event, for when the reply arrives from the server
a response event, containing the body of the server response
It also supports several extra use cases: for example interceptors and
progress events.
This new HTTP client will exist side-by-side with the previous HTTP
module, to allow an easier migration.
I hope this helps get the most out of the new Angular HTTP module! If
you have any questions about the book, any issues or comments I would
love to hear from you at admin@angular-university.io
I invite you to have a look at the bonus material below, I hope that you
enjoyed this book and I will talk to you soon.
Kind Regards,
Vasco
Angular University
Typescript - A Video List
In this section, we are going to present a series of videos that cover
some very commonly used Typescript features.