Angular Functions

 

Angular and RESTful APIs: Consuming Data from Backend Services

In modern web development, creating dynamic and data-driven applications is essential. Angular, a popular front-end framework, enables developers to build robust and responsive applications that interact with backend services through RESTful APIs. RESTful APIs serve as a bridge between the client-side application and the server-side backend, allowing seamless data retrieval and manipulation.

Angular and RESTful APIs: Consuming Data from Backend Services

This blog will walk you through the process of consuming data from backend services using Angular and RESTful APIs. We will explore the fundamental concepts of RESTful APIs and demonstrate how to integrate them into Angular applications to fetch data from servers. Throughout this tutorial, we will cover various techniques, best practices, and code samples to help you become proficient in handling data in your Angular projects.

1. Understanding RESTful APIs

1.1. What are RESTful APIs?

REST (Representational State Transfer) is an architectural style for designing networked applications. RESTful APIs allow clients to communicate with servers over standard HTTP methods. Each resource on the server is represented by a URL, and the available actions on that resource are performed using HTTP methods like GET, POST, PUT, and DELETE.

1.2. HTTP Methods (GET, POST, PUT, DELETE)

  • GET: Used for retrieving data from the server.
  • POST: Used for creating new resources on the server.
  • PUT: Used for updating existing resources on the server.
  • DELETE: Used for removing resources from the server.
  • RESTful API URL Structure

A typical RESTful API follows a structured URL pattern. For example:

https://api.example.com/users represents the collection of users, and https://api.example.com/users/123 represents a specific user with the ID 123.

2. Setting Up an Angular Project

2.1. Installing Angular CLI

Before we start building our Angular application, we need to have Angular CLI installed. Open your terminal or command prompt and run the following command:

bash
npm install -g @angular/cli

2.2. Creating a New Angular Project

Once Angular CLI is installed, we can create a new Angular project using the following command:

bash
ng new my-angular-app

Replace “my-angular-app” with your preferred project name.

2.3. Project Structure Overview

Angular projects have a well-defined structure. The primary files and folders include:

  • src: Contains the application source code.
  • app: Holds the root component and other components, services, and modules.
  • angular.json: Configuration file for Angular CLI.

3. Making HTTP Requests with Angular

3.1. Using HttpClient Module

Angular provides the HttpClient module to perform HTTP requests. Before using it, make sure it’s imported into your application’s root module:

typescript
// app.module.ts
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  // ...
  imports: [HttpClientModule],
  // ...
})
export class AppModule { }

3.2. Handling Asynchronous Operations with Observables

HTTP requests are asynchronous, and Angular handles them using Observables. An Observable is a representation of any set of values over time. To make an HTTP request, subscribe to the Observable returned by the HttpClient methods:

typescript
import { HttpClient } from '@angular/common/http';

@Injectable()
export class DataService {
  constructor(private http: HttpClient) { }

  getData(): Observable<any> {
    return this.http.get<any>('https://api.example.com/data');
  }
}

3.3. Error Handling

When working with HTTP requests, it’s crucial to handle errors gracefully. You can use the catchError operator from RxJS to handle errors within the service:

typescript
import { HttpClient } from '@angular/common/http';
import { catchError } from 'rxjs/operators';

@Injectable()
export class DataService {
  constructor(private http: HttpClient) { }

  getData(): Observable<any> {
    return this.http.get<any>('https://api.example.com/data').pipe(
      catchError((error: any) => {
        console.error('An error occurred:', error);
        // Handle the error gracefully (e.g., show an error message).
        return throwError('Something went wrong; please try again later.');
      })
    );
  }
}

4. Retrieving Data from a RESTful API

4.1. Sending GET Requests

In our previous example, we created a DataService to fetch data from the server. Now, let’s see how to use this service to retrieve and display the data in our Angular component:

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

@Component({
  selector: 'app-data',
  template: `
    <ul>
      <li *ngFor="let item of data">{{ item.name }}</li>
    </ul>
  `,
})
export class DataComponent implements OnInit {
  data: any[];

  constructor(private dataService: DataService) { }

  ngOnInit() {
    this.dataService.getData().subscribe(
      (response: any) => {
        this.data = response;
      },
      (error: any) => {
        console.error(error);
      }
    );
  }
}

In this example, we use *ngFor to iterate through the data array and display the names of the items.

4.2. Parsing Server Responses

The server might return data in different formats like JSON, XML, or plain text. By default, Angular’s HttpClient automatically parses JSON responses. If the server returns a different data type, you may need to set the response type explicitly:

typescript
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';

@Injectable()
export class DataService {
  constructor(private http: HttpClient) { }

  getData(): Observable<any> {
    const headers = new HttpHeaders().set('Accept', 'application/xml');
    return this.http.get('https://api.example.com/data', { headers, responseType: 'text' }).pipe(
      map((response: HttpResponse<any>) => {
        // Parse the XML response here and return the data.
      })
    );
  }
}

5. Sending Data to the Backend

5.1. Using POST Method

POST requests are used to send data to the server to create new resources. Let’s see how to use the HttpClient to send data in a POST request:

typescript
import { HttpClient, HttpHeaders } from '@angular/common/http';

@Injectable()
export class DataService {
  constructor(private http: HttpClient) { }

  postData(data: any): Observable<any> {
    const headers = new HttpHeaders().set('Content-Type', 'application/json');
    return this.http.post('https://api.example.com/data', data, { headers });
  }
}

5.2. Handling Form Submissions

In real-world scenarios, you might want to send data submitted through a form to the server. To achieve this, first, bind the form fields to Angular properties:

html
<form (submit)="submitForm()">
  <input type="text" [(ngModel)]="formData.name" name="name" />
  <input type="email" [(ngModel)]="formData.email" name="email" />
  <button type="submit">Submit</button>
</form>

Then, handle the form submission in the component:

typescript
import { Component } from '@angular/core';
import { DataService } from './data.service';

@Component({
  selector: 'app-form',
  template: `
    <form (submit)="submitForm()">
      <input type="text" [(ngModel)]="formData.name" name="name" />
      <input type="email" [(ngModel)]="formData.email" name="email" />
      <button type="submit">Submit</button>
    </form>
  `,
})
export class FormComponent {
  formData = {
    name: '',
    email: '',
  };

  constructor(private dataService: DataService) { }

  submitForm() {
    this.dataService.postData(this.formData).subscribe(
      (response: any) => {
        // Handle the server response (e.g., show a success message).
      },
      (error: any) => {
        console.error(error);
        // Handle errors gracefully (e.g., show an error message).
      }
    );
  }
}

5.3. Sending Data in JSON Format

In our example, we sent data to the server in JSON format, which is a common practice for RESTful APIs. Angular’s HttpClient automatically serializes JavaScript objects into JSON:

typescript
import { HttpClient, HttpHeaders } from '@angular/common/http';

@Injectable()
export class DataService {
  constructor(private http: HttpClient) { }

  postData(data: any): Observable<any> {
    const headers = new HttpHeaders().set('Content-Type', 'application/json');
    return this.http.post('https://api.example.com/data', data, { headers });
  }
}

6. Updating Data with PUT and DELETE

6.1. Modifying Existing Records

The PUT method is used to update existing resources on the server. To modify data, we can create a method in the DataService to handle the PUT request:

typescript
import { HttpClient, HttpHeaders } from '@angular/common/http';

@Injectable()
export class DataService {
  constructor(private http: HttpClient) { }

  updateData(data: any): Observable<any> {
    const headers = new HttpHeaders().set('Content-Type', 'application/json');
    return this.http.put('https://api.example.com/data/' + data.id, data, { headers });
  }
}

6.2. Removing Data from the Backend

The DELETE method is used to remove resources from the server. Similarly, we can create a method in the DataService to handle the DELETE request:

typescript
import { HttpClient } from '@angular/common/http';

@Injectable()
export class DataService {
  constructor(private http: HttpClient) { }

  deleteData(id: number): Observable<any> {
    return this.http.delete('https://api.example.com/data/' + id);
  }
}

7. Handling Authentication in RESTful APIs

7.1. Token-Based Authentication

For secure communication between the client and server, RESTful APIs often use token-based authentication. The server issues an access token to the client upon successful authentication. The client includes this token in the HTTP headers for subsequent requests.

7.2. Sending Authenticated Requests

To send authenticated requests, we need to include the access token in the request headers. We can create an AuthInterceptor that intercepts each request and adds the authorization header:

typescript
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  private readonly accessToken = 'YOUR_ACCESS_TOKEN';

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const authReq = req.clone({
      setHeaders: {
        Authorization: `Bearer ${this.accessToken}`
      }
    });

    return next.handle(authReq);
  }
}

Don’t forget to include the AuthInterceptor in your app’s providers:

typescript
import { HTTP_INTERCEPTORS } from '@angular/common/http';

@NgModule({
  // ...
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true
    }
  ],
  // ...
})
export class AppModule { }

Conclusion

In this blog, we covered the fundamental concepts of consuming data from backend services using Angular and RESTful APIs. We explored various HTTP methods to interact with the server, parsed server responses, and handled form submissions. Additionally, we discussed how to update and delete data from the backend and implement token-based authentication for secure communication.

By understanding these concepts and following the code samples, you can confidently build Angular applications that consume data from RESTful APIs, providing seamless user experiences and responsive web applications. Angular’s robust features and RESTful APIs’ flexibility combine to form a powerful toolset for modern web development. Happy coding!

Previously at
Flag Argentina
Mexico
time icon
GMT-6
Experienced Engineering Manager and Senior Frontend Engineer with 9+ years of hands-on experience in leading teams and developing frontend solutions. Proficient in Angular JS