Angular’s 17 HttpClient Complete Tutorial
Tags: angular, angular17, httpclient
Published: 2024-04-15 18:49:14

Angular, being a powerful front-end framework, equips developers with various tools to communicate seamlessly with servers over the internet. One such essential tool is HttpClient, which simplifies fetching data from servers or sending data to servers. In this article, we’ll delve into understanding what HttpClient is and how to effectively set it up within your Angular application.

**HttpClient** is a tool provided by Angular that helps us communicate with servers over the internet. We use it to fetch data from servers or send data to servers.

Setting up HttpClient in your application involves configuring it using dependency injection. Here’s a step-by-step guide with examples:

## 1. Providing HttpClient through dependency injection:

First, you need to provide HttpClient through dependency injection. This is typically done in your app’s configuration file (**app.config.ts**).

```
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(),
  ]
};
```
If your app uses NgModule-based bootstrap, you can include provideHttpClient in the providers array of your app’s NgModule.

```
// app.module.ts
import { NgModule } from '@angular/core';
import { provideHttpClient } from 'somewhere';

@NgModule({
  providers: [
    provideHttpClient(),
  ],
  // ... other application configuration
})
export class AppModule {}
```
Now, HttpClient is available for injection in your components, services, or other classes.

While HttpClient can be injected and used directly from components, generally it is recommended you create reusable, injectable services which isolate and encapsulate data access logic

```
// data.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({ providedIn: 'root' })
export class DataService {
  constructor(private http: HttpClient) {
    // This service can now make HTTP requests via `this.http`.
  }
}
```

## 2. Configuring features of HttpClient:

You can configure optional features of HttpClient when providing it through dependency injection.

**withFetch:**
This feature switches HttpClient to use the fetch API instead of the default XMLHttpRequest API.

```
// app.config.ts
import { provideHttpClient, withFetch } from 'somewhere';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(
      withFetch(),
    ),
  ]
};
```
**withInterceptors:**
Configures a set of interceptor functions to process requests made through HttpClient.

**withInterceptorsFromDi:**
Includes the older style of class-based interceptors in the HttpClient configuration.

**withRequestsMadeViaParent:**
Passes requests up to the HttpClient instance in the parent injector after passing through interceptors at the current level.

**withJsonpSupport:**
Enables the .jsonp() method on HttpClient for cross-domain loading of data using JSONP convention.

**withXsrfConfiguration:**
Allows customization of HttpClient’s built-in XSRF security functionality.

**withNoXsrfProtection**:

Disables HttpClient’s built-in XSRF security functionality.

## Fetching JSON Data

By default, HttpClient assumes that servers will return JSON data.

**Example:**
· Let’s say we have an online store and we want to get information about products from a server.

```
// We use HttpClient to make a GET request to a server endpoint.
this.http.get('/api/products').subscribe({
  next: products => {
    // Once we get the products, we can display them to the user.
    console.log(products);
  }
});
```

## Fetching Other Types of Data

When interacting with a non-JSON API, you can tell **HttpClient** what response type to expect and return when making the request. This is done with the responseType option.

**Example:**
· Let’s say we want to download an image from a server.

```
// We use HttpClient to make a GET request for an image.
this.http.get('/images/cat.jpg', { responseType: 'blob' }).subscribe({
  next: image => {
    // Once we get the image, we can display it to the user.
    console.log(image);
  }
});

```

## Mutating Server State

If we want to change data on the server we can use HTTP methods like POST, PUT, or DELETE to modify data on the server.

**Example:**
· Let’s say we want to add a new product to our online store.

```
// We use HttpClient to make a POST request to add a new product.
this.http.post('/api/products', newProduct).subscribe({
  next: response => {
    // Once the product is added, we can do something with the response.
    console.log(response);
  }
});
```

## Handling Errors

Sometimes requests fail due to network issues or server errors. We need to handle these errors gracefully.

**Example:**
· Let’s say our request to add a product fails because the server is down.

```
// We use HttpClient to make a POST request to add a new product.
http.post('/api/products', newProduct).subscribe({
  next: response => {
    console.log('Product added successfully:', response);
  },
  error: err => {
    console.error('Failed to add product:', err);
    // We can show an error message to the user or retry the request.
  }
});
```

## Example

Now let’s create a simple Angular project to demonstrate the usage of **HttpClient** with various features like sending HTTP requests, handling different data types, and error handling.

Run the following command to generate a new project:

```
ng new http-client-demo

```
Run the following command to generate a new service:

```
ng generate service data

```
Now, let’s modify the **data.service.ts** file in the src/app directory to include HttpClient usage:

```
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; 
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class DataService {

  private apiUrl = 'https://jsonplaceholder.typicode.com';

  constructor(private http: HttpClient) { }

  // Method to fetch JSON data
  getJsonData(): Observable<any> {
    return this.http.get<any>(`${this.apiUrl}/posts`).pipe(
      catchError(error => {
        console.error('Error fetching JSON data:', error);
        return throwError(()=> new Error('Something went wrong; please try again later.'));
      })
    );
  }

  // Method to fetch an image
  getImage(): Observable<Blob> {
    return this.http.get(`${this.apiUrl}/photos/1`, { responseType: 'blob' }).pipe(
      catchError(error => {
        console.error('Error fetching image:', error);
        return throwError(()=> new Error('Unable to fetch image.'));
      })
    );
  }

  // Method to simulate adding a new post
  addPost(newPost: any): Observable<any> {
    return this.http.post<any>(`${this.apiUrl}/posts`, newPost).pipe(
      catchError(error => {
        console.error('Error adding post:', error);
        return throwError(()=> new Error('Failed to add post.'));
      })
    );
  }
}
```
Now, let’s modify the **app.component.ts** file to use the DataService:

```
import { Component, OnInit } from '@angular/core';
import { DataService } from './data.service'; 

@Component({
  selector: 'app-root',
  standalone: true,
  templateUrl: './app.component.html',
  styleUrl: './app.component.css'
})
export class AppComponent implements OnInit {

  constructor(private dataService: DataService) { }

  ngOnInit(): void {
    // Fetch JSON data
    this.dataService.getJsonData().subscribe({
      next: data => {
        console.log('JSON Data:', data)
      },
      error: error => {
        console.error('Error fetching JSON data:', error)
      }
  });

    // Fetch image
    this.dataService.getImage().subscribe({
      next: image => {
        const reader = new FileReader();
        reader.onload = () => {
          console.log('Image:', reader.result);
        };
        reader.readAsDataURL(image);
      },
      error: error => {
        console.error('Error fetching image:', error)
      }
  });

    // Add a new post
    const newPost = {
      title: 'New Post',
      body: 'Description of the new post'
    };
    this.dataService.addPost(newPost).subscribe({
      next: response => {
        console.log('Post added successfully:', response)
      },
      error: error => {
        console.error('Error adding post:', error)
      }
  });
  }
}
```
Finally, let’s update the **app.component.html** file to remove the default content:

```
<div style="text-align:center">
  <h1>
    Welcome to HttpClient Demo!
  </h1>
</div>
```
Now, you can run the application using the following command:

```
ng serve
```
This will start a development server, and you should be able to see the output in the browser console.

## Conclusion

In conclusion, HttpClient is a powerful tool provided by Angular for making HTTP requests in your applications. By following the steps outlined in this guide, you can effectively set up and utilize HttpClient to interact with servers, fetch data, and handle various types of responses.

To get the whole code, check the link below👇👇👇
[https://github.com/anthony-kigotho/http-client-demo
](https://github.com/anthony-kigotho/http-client-demo)

## CTA
Many developers and learners encounter tutorials that are either too complex or lacking in detail, making it challenging to absorb new information effectively.

[Subscribe to our newsletter](https://bytewave.substack.com/) today, to access our comprehensive guides and tutorials designed to simplify complex topics and guide you through practical applications.