Make API Calls the Right Way in Angular

Read it in 8 Mins

Last updated on
07th Jun, 2022
Published
18th Jan, 2021
Views
5,150
Make API Calls the Right Way in Angular

About Angular 10

Angular 10 is the latest version of the Angular family. Angular applications are basically designed for Single Page Applications, where all controls are required in single page architecture. Angular is an application based design framework, which provides the Cross-Platform development environment for creating the most sophisticated SPAs. These SPAs are efficient enough for giving us a component to view to model environment, making it an MVC or MVVM application. If you want to know more about the latest & simple markup language you may also check what is markdown.

Angular provides a Progressive Web App architecture, which means that an application made in Angular gives us an App like experience with high performance. Angular has zero-step installation, making its up- gradation using modern web capabilities possible, even if offline. Angular has the capability of making cross platform Desktop Apps which can be created using MAC, Windows, or Linux OS using the same Angular methods. Angular can be rendered in Node.js, Microsoft .Net, PHP and many other servers by giving the output in HTML-CSS format. This even optimizes the app for SEO. Angular framework turns our templates into JavaScript Virtual machine codes which are highly optimized. With Angular CLI, the Command Line tools, we can build and deploy Apps faster than ever before. Angular uses Karma for unit tests and Protractor for scenario tests making the applications made in Angular more stable.

Know more about angular cli.

Introduction

Front-end applications in today’s programming world use HTTP protocol modules to talk to the back-end services. Almost all current browsers make this communication via two ways, one by HTTPrequests through XMLHttpRequest interface and the other by the API fetch() method call.

We usually make API calls to remote HTTP servers via HttpClient module of Angular 10 by sending HTTP requests. HttpClient has methods which perform HTTP requests. HttpClient is an injectable class for Angular 10. The methods of this class have request methods with many types of signatures, and their return types are different based on the signature of the request, thus giving different response types.

We will study about HttpClient in detail in the subsequent passage.

The Common Mistake

One thing for sure is that we need to call APIs in our programs. If we do so correctly, it can help us in upgrading to further versions, in making test modules, and even in handling errors. One common mistake that programmers usually make is in the call they use API URLs directly in the component. This means that if the API URL is upgraded for any reason, we will need to upgrade the URLs in every single component.
For Eg: 

this.httpClient.get('https://www.userdomain.com/api_name/data/' + this.id);  

Again, since we are not validating the path by using the Path variable of Angular, this call might fail if the URL is not valid or not available for some reason. Also, changing the modules with direct call to httpClient will require a lot of changes in the component. 

Let us now talk about the right approach.

The Right Way

The correct approach towards calling APIs in Angular includes the following:

Create Constants

We need to set global variables in Angular 10 to access our variables synchronously throughout our application. 

We declare Global variables in a Global Constant file. Create a folder under src/app and name it config. To create the global constant file, name it constants.ts and place it under src/app/config folder.

Eg: create the following file: 
src/app/config/constants.ts 

Open this file and put global constants like API_ENDPOINT, API_MOCK_ENDPOINT etc. These global variables will be used later in Component files like AppComponent so that they can be used like Site constants.

 Declaring Global Constants

// Angular Modules
import { Injectable } from '@angular/core'; 
@Injectable() 
export class Constants {
public readonly API_ENDPOINT: string = ' https://www.userdomain.com/'; 
public readonly API_MOCK_ENDPOINT: string = 'https://www.userdomainmock.com/'; 
public static TitleOfSite: string = " Making API calls the Right Way by Monica"; 

An example of AppComponent using the above global constant is: 
Edit the app.component.ts file from the src/app folder: 
src/app/app.component.ts: 
import { Component, OnInit } from '@angular/core';
import{ Constants } from './config/constants'; 
@Component({ 
  selector: 'app-root', 
  templateUrl: './app.component.html', 
  styleUrls: ['./app.component.css'] 
}) 
export class AppComponent implements OnInit{ 
    title = Constants.TitleOfSite; 
    constructor() { 
        console.log(GlobalConstants.API_ENDPOINT); 
    } 
    ngOnInit() { 
        console.log(this.title); 
    } 

Run the project by navigating to the project folder and calling ng serve : 
$ cd hello-world  

$ ng serve  

The output will be seen in the browser: https://www.userdomain.com/ 

Making API calls the Right Way by Monica

Create a Service

To create a service in Angular 10, create a file api-http.service.ts in the src/app/core/services folder.

Add the following code in the file as below: 

// Angular Modules 
import { Injectable } from '@angular/core'; 
import { HttpClient } from '@angular/common/http'; 
@Injectable() 
export class ApiHttpService { 
constructor( 
// Angular Modules 
private http: HttpClient 
) { } 
public get(url: string, options?: any) { 
return this.http.get(url, options); 
} 
public post(url: string, data: any, options?: any) { 
return this.http.post(url, data, options); 
} 
public put(url: string, data: any, options?: any) { 
return this.http.put(url, data, options); 
} 
public delete(url: string, options?: any) { 
return this.http.delete(url, options); 
} 
}

Use HTTPClient Library

HttpClient Library is present in @angular/common/http folder. The older version of HttpClient was in @angular/http folder, this is replaced by the upgraded version of the same in @angular/common/http folder.

Almost all current browsers communicate with APIs via two ways, one by HTTPrequests through XMLHttpRequest interface and the other by the API fetch() method call.

The HttpClient module is built over XMLHttpRequest interface. It wraps all the complexities of this interface and provides extra features like: RxJS Obervables, Interceptors for requests and responses, Typed requests and responses, Error handling techniques, ease in Testing Modules, etc. 

Benefits of using HTTPClient Library

HttpClient is a module found in angular/common/http module. HttpClient is based on XMLHttpRequest interface, the Interface which is commonly given by most modern browsers. HttpClient gives us a lot more than XMLHttpRequest, and some of its benefits are:

  1. It gives us ease in using testing modules.
  2. It has request and response objects in strongly typed manner.
  3. It has APIs Support with Observable class object.
  4. It provides error handling modules.

Importing the library

In order to use HttpClient library we need to import HttpClientModule from the @angular/common/http package and include the library in the imports array of the App module : 

Edit the AppModule file in the src/app folder and add the line on top of the file as follows: 

src/app/app.module.ts: 

import { HttpClientModule } from '@angular/common/http'; 

Configure HTTPClient

Including HttpClient: 

Once done, include HttpClientModule in the imports array of the app.module and further use it:

import { NgModule }         from '@angular/core';
import { BrowserModule }    from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
  imports: [
    BrowserModule,
    // import HttpClientModule after BrowserModule.
    HttpClientModule,
  ],
  declarations: [
    AppComponent,
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule {}
…

Now we are ready to use the HttpClient library to send HTTP requests or receive API response. 

Injecting HttpClient into our Application: 

Once we have  imported HttpClientModule into the AppModule, we can inject the HttpClient into our application as:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable()
export class ConfigService {
  constructor(private http: HttpClient) { }
}

Create a query parameter

Getting JSON data

In this example we will request JSON data from the API server. Here our app needs a configuration file on the server, config.json, that specifies resource URLs.

{
  "demoUrl": "api/demo",
  "filename": "assets/demotextfile.txt"
}
The ConfigService fetches this file with a get() method from HttpClient library as follows:

configUrl = 'assets/config.json';
getConfig() {
  return this.http.get(this.configUrl);
}

A component, such as ConfigComponent, injects the ConfigService and this getConfig service method is called from the component as for example:

showConfig() {
  this.configService.getConfig()
    .subscribe((data: Config) => this.config = {
        demoUrl: data['demoUrl'],
        filename:  data['filename']
    });
}

The service method returns an Observable object of configuration data. Thus the component subscribes to the method's return value. The subscription callback copies the data fields into the component's config object, which binds the data in the component template for display.

We can get the Observable object of typed HTtpResponse from the HttpClient as follows:

getConfigResponse(): Observable<HttpResponse<Config>> {
  return this.http.get<Config>(
    this.configUrl, { observe: 'response' });
}

Here, HttpClient.get() returns an Observable object of typed HttpResponse rather than just the JSON data.

The showConfigResponse() method of the component displays the response headers as well as the configuration.

Create Error Handler

HttpClient returns an error object instead of a successful response if a request fails on the server. This usually happens due to a request fail, poor network connection or other network related issues.

We can create an error handler component by adding a second callback to the.subscribe():

showConfig() {
  this.configService.getConfig()
    .subscribe(
      (data: Config) => this.config = { ...data }, // success path
      error => this.error = error // error path
    );
}

We can give different reasons and feedback for a failed request, but displaying the error object can also help at times. 

@angular/common/http

@angular/common/http implements an HTTP client API for Angular apps that relies on the XMLHttpRequest interface exposed by browsers.

This includes testability features, typed request and response objects, request and response interception, observable APIs, and streamlined error handling.

Entry point exports

NgModules
HttpClientJsonpModuleConfigures the dependency injector for HttpClient with supporting services for JSONP. Without this module, Jsonp requests reach the backend with method JSONP, where they are rejected.
HttpClientModuleConfigures the dependency injector for HttpClient with supporting services for XSRF. Automatically imported by HttpClientModule.
HttpClientXsrfModuleConfigures XSRF protection support for outgoing requests.
Classes
HttpBackendA final HttpHandler which will dispatch the request via browser HTTP APIs to a backend.
HttpClientPerforms HTTP requests. This service is available as an injectable class, with methods to perform HTTP requests. Each request method has multiple signatures, and the return type varies based on the signature that is called (mainly the values of observe and responseType).
HttpErrorResponseA response that represents an error or failure, either from a non-successful HTTP status, an error while executing the request, or some other failure which occurred during the parsing of the response.
HttpHandlerTransforms an HttpRequest into a stream of HttpEvents, one of which will likely be a HttpResponse.
HttpHeaderResponseA partial HTTP response which only includes the status and header data, but no response body.
HttpHeadersRepresents the header configuration options for an HTTP request. Instances are immutable. Modifying methods return a cloned instance with the change. The original object is never changed.
HttpParamsAn HTTP request/response body that represents serialized parameters, per the MIME type application/x-www-form-urlencoded.
HttpRequestAn outgoing HTTP request with an optional typed body.
HttpResponseA full HTTP response, including a typed response body (which may be null if one was not returned).
HttpResponseBaseBase class for both HttpResponse and HttpHeaderResponse.
HttpUrlEncodingCodecProvides encoding and decoding of URL parameter and query-string values.
HttpXhrBackendUses XMLHttpRequest to send requests to a backend server.
HttpXsrfTokenExtractorRetrieves the current XSRF token to use with the next outgoing request.
JsonpClientBackendProcesses an HttpRequest with the JSONP method, by performing JSONP style requests.
JsonpInterceptorIdentifies requests with the method JSONP and shifts them to the JsonpClientBackend.
XhrFactoryA wrapper around the XMLHttpRequest constructor.
Structures
HttpDownloadProgressEventA download progress event.
HttpEventTypeType enumeration for the different kinds of HttpEvent.
HttpInterceptorIntercepts and handles an HttpRequest or HttpResponse.
HttpParameterCodecA codec for encoding and decoding parameters in URLs.
HttpProgressEventBase interface for progress events.
HttpSentEventAn event indicating that the request was sent to the server. Useful when a request may be retried multiple times, to distinguish between retries on the final event stream.
HttpUploadProgressEventAn upload progress event.
HttpUserEventA user-defined event.
Types
HTTP_INTERCEPTORSA multi-provider token that represents the array of registered HttpInterceptor objects.
HttpEventUnion type for all possible events on the response stream.

HttpClient vs HttpBackend

HttpBackend

A final HttpHandler which will dispatch the request via browser HTTP APIs to a backend.

Interceptors sit between the HttpClient interface and the HttpBackend.

When injected, HttpBackend dispatches requests directly to the backend, without going through the interceptor chain.

abstract class HttpBackend implements HttpHandler {
  abstract handle(req: HttpRequest<any>): Observable<HttpEvent<any>>
}

HttpClient

Performs HTTP requests. This service is available as an injectable class, with methods to perform HTTP requests. Each request method has multiple signatures, and the return type varies based on the signature that is called (mainly the values of observe and responseType).

Note that the response Type options value is a String that identifies the single data type of the response. A single overload version of the method handles each response type. The value of responseType cannot be a union, as the combined signature could imply.

class HttpClient {
request(first: string | HttpRequest<any>, url?: string, options: { body?: any; headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: HttpObserve; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "arraybuffer" | ... 2 more ... | "json"; withCredentials?: boolean; } = {}): Observable<any>
  delete(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: HttpObserve; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "arraybuffer" | ... 2 more ... | "json"; withCredentials?: boolean; } = {}): Observable<any>
  get(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: HttpObserve; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "arraybuffer" | ... 2 more ... | "json"; withCredentials?: boolean; } = {}): Observable<any>
  head(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: HttpObserve; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "arraybuffer" | ... 2 more ... | "json"; withCredentials?: boolean; } = {}): Observable<any>
  jsonp<T>(url: string, callbackParam: string): Observable<T>
  options(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: HttpObserve; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "arraybuffer" | ... 2 more ... | "json"; withCredentials?: boolean; } = {}): Observable<any>
  patch(url: string, body: any, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: HttpObserve; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "arraybuffer" | ... 2 more ... | "json"; withCredentials?: boolean; } = {}): Observable<any>
  post(url: string, body: any, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: HttpObserve; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "arraybuffer" | ... 2 more ... | "json"; withCredentials?: boolean; } = {}): Observable<any>
  put(url: string, body: any, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: HttpObserve; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: "arraybuffer" | ... 2 more ... | "json"; withCredentials?: boolean; } = {}): Observable<any>
}

The request that we send by HttpClient always go through interceptor of Angular application and the request we send by HttpBackend will dispatch requests directly to the backend, without going through the interceptor chain. So we should use both HttpClient and HttpBackend to send a request.

Citation.

Conclusion

The above article included all the information that we need for working with APIs for Angular Applications. We worked with the Http module and HttpClient Module. We worked with services and efficient API Calls. We understood how to improve on calling API from an Angular Application.

Profile

KnowledgeHut

Author
KnowledgeHut is an outcome-focused global ed-tech company. We help organizations and professionals unlock excellence through skills development. We offer training solutions under the people and process, data science, full-stack development, cybersecurity, future technologies and digital transformation verticals.