This article on Making HTTP Requests in Angular is part of the Learning Angular series.
MUST READ: Angular 6 and HTTP
Angular 6 is currently the latest version of Angular and it deprecates the Http-access method taught in this module.
What does this mean?
It means that the method still works, still is secure – you can use it! But there is a better Http module to use now: HttpClient.
I added a module (section 23) on that new client months ago, even before Angular 5 was released. You’ll meet it later in the course and we’ll easily update all our Http calls with the new client there.
So for now, follow along with this module here – the core concepts taught here will still apply (i.e. how it works etc.).
And later in the course, we’ll revisit this solution and update it to HttpClient.
Introduction and How HTTP Requests work in SPA
In traditional apps, the front end used to request some data, and the server gave the response and it was loaded in a page.
But in SPA, the data should come back to the page itself to make sure that the page doesn’t get reloaded.
Example App and Backend Setup
Use Firebase for the backend.
One needs to setup the read/write permission of the database to true to be able to work on the database.
Sending Requests (Example: POST Request)
this.http.post(…) doesn’t actually make the request but returns an Observable.
To fire the request one needs to subscribe to the Observable returned by
http.post(...)
To make a request to the firebase, paste the url and append <table-name>.json
json is the extension required for the firebase service to work.
www.firebase.url/something.json
Adjusting Request Headers
To send headers, one can
const myHeaders = new Headers({ 'Content-Type': 'application/json' }); this.http.post('service_url', dataToPost, { headers: myHeaders });
Sending GET Requests
getServers() { return this.http.get('service_url'); }
And use it as,
myService.getServers().subscribe({ next: (response) => console.log(response), error: (error) => console.log(error) });
If one inspects the data that is returned in the body of the response, it is of type JSON
The response object that is returned from the Subscriber is of type Response which can be imported form @angular/http
And it provides a way to parse the JSON directly to an object. This can be done by:
(response: Response) => { console.log(response.json()); }
Sending a PUT Request
this.http.put('service_url', dataToPost, { headers: myHeaders });
PUT request will overwrite the existing data and has the process similar to that of the POST request.
Transform Responses Easily with Observable Operators (map())
The map operator will simply take the old Observable and wrap the data that returns back, transform the data and wrap that transformed data into a new Observable.
With this the earlier way
// service.ts getServers() { this.http.get('api_url'); } // component.ts myService.getServers().subscribe( (response: Response) => { var data = response.json(); console.log(data); } );
Will get converted to:
service.ts
getServers() { this.http.get('api_url').pipe( map((response: Response) => { var data = response.json(); return data; }) ); }
component.ts
myService.getServers().subscribe( (servers: any[]) => { console.log(data); } );
Modifying the response at the service level is required to be able to send the request from multiple places and not need to parse the result at every calling place.
Using the Returned Data
this.http.get('api_url').pipe( map((response: Response) => { var data = response.json(); for (const server of data) { server.name = 'FETCHED_' + server.name; } return data; }) );
This just shows what we can do with the map operator.
todo: When the user added a new server and did a PUT request to firebase, it was able to retain the previous servers and add a new one.
It should be working because he overwrote the previous ones. Need to check.
Catching HTTP Errors
If some error happens while doing some requests, one can catch them using the catch operator
import { catchError } from 'rxjs/operators'; import { throwError } from 'rxjs'; this.http.get('wrong_api_url').pipe( map(...), catchError((error: Response) => { return throwError(error); }) };
Using throwError(…) will wrap the error in an Observable and be send to the class observing it.
Similar to the map, the error can also be transformed before sending it as an Observable
... catchError((error: Response) => { return throwError('Something went wrong'); })
Using the async pipe with HTTP Requests
service.ts
getAppName() { return this.http.get('_url_to_get_app_name').pipe( map((response: Response) => { return reponse.json(); }) ); }
component.ts
appName = service.getAppName();
This would return an Observable, and to be able to use this directly the HTML component, async pipe would turn very handy
component.html
<h2>{{ appName | async }}</h2>
Transforming Response Data to Prevent Errors
If the reponse array has any attribute missing, we can use the map to put that back in so that it doesn’t generate any error
map((response: Response) => { const recipes: Recipe[] = response.json(); for (recipe of recipes) { if (!recipe['ingredients']) { recipe['ingredients'] = []; } } return recipes; })
In Anular 4.2 a new HttpCLient was released and it’s just an alternative to the original Http.
It is built up of with the modern web api’s and has better and advanced features, interceptors for example.
To start using the HttpClient, we would need to remove the HttpModule if implemented and use the HttpClientModule instead. This can be imported from @angular/common/http
Now eherever we are using the Http, we can uise the HttpClient instead. The pway the parameters ahndled are the same.
this.http.put('some_url', data) gets updated to this.httpClient.put('some_url', data)
and
this.http.get('some_url') gets updated to this.httpClient.get('some_url')
One thing to notice about the get method in HttpClient is that now we can be explicit about what type of data we are expecting from the service.
this.httpClient.get<Recipe[]>(‘some_url’)
So if we are using a map to parse the result, that can be overwrittyen by
this.httpClient.get<Recipe[]>('some_url').pipe( map(recipes => { for (let recipe of recipes) { if (!recipe['ingredients']) { recipe['ingredients'] = []; } } }) );
Request Configutation and Response
The request/response can be configured by providing the options parameter in the GET/PUT request. IT takes an object.
this.httpClient.get( 'some_url', { observe: 'response', // default is body responeType: 'text' // can be type json/text/blob. default is json } )
In the response we will get the data of the value we set in the observe parameter in the format we sopecify in the responseType parameter.
Requesting Events
We can pass the events string in the observe parameter of the options obect in a reqquest. This would return all the events that get fiored while processing a request.
this.httpClient.put( 'some_url', someData, { observe: 'events' // other values are body/response } )
The first event that will be fired would have a type of 0, which stands for the HttpEventType.Sent
Setting Headers
To pass custom headers we will need to pass the headers attribute in the request’s option parameter
this.httpClient.get( 'some_url', { headers: new HttpHeaders() .append('Authorization', 'bearer asfhaskghkasghaksdg234235sadgsd') .append(....) } )
Http Parameters
Sometimes query params need not be directly attached to the url string. We can pass it to the options parameter the same way we pass the headers.
this.httpClient.get( 'some_url', { params: new HttpParams() .append('auth', firebase_token) .append(....) } )
Progress
HttpEventType 1 – Upload
HttpEventType 3 – Download
While we can use the HttpClient directly to fire requests, we can also create a fullynconfigured request manually.
const req = new HttpRequest( 'PUT', 'some_url', dataToSave, { reportProgress: true, // This will give the progress of the request thus making it earier to track file uiploads/downloads. params: new HttpParams().set('auth': firebase_auth_token) } ); return this.httpClient.request(req);