Introduction
In modern web development, communicating with backend APIs is essential. Angular provides a powerful and easy-to-use HttpClient
service that allows developers to perform all types of HTTP operations — including GET
, POST
, PUT
, and DELETE
.
While GET
requests are used to retrieve data, the other three methods — POST
, PUT
, and DELETE
— are responsible for creating, updating, and removing data from the server.
In this detailed post, we’ll explore each of these methods, their syntax, usage, handling responses, and best practices for writing maintainable and efficient API integrations.
Table of Contents
- Setting Up HttpClient in Angular
- Creating a Data Service for API Calls
- Understanding POST Requests
- Implementing POST Request in Angular
- Handling POST Response
- Example: Submitting a Form with POST
- Understanding PUT Requests
- Implementing PUT Request in Angular
- Handling PUT Response
- Example: Updating User Details
- Understanding DELETE Requests
- Implementing DELETE Request in Angular
- Handling DELETE Response
- Example: Deleting a Record
- Using Observables and Subscriptions
- Handling Errors with HttpClient
- Using HttpHeaders and Options
- Reusing API URLs with Environment Files
- Creating a Reusable Data Service
- Best Practices for POST, PUT, and DELETE
- Conclusion
1. Setting Up HttpClient in Angular
Before using any HTTP methods, the HttpClientModule
must be imported in your Angular root module.
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, HttpClientModule],
bootstrap: [AppComponent]
})
export class AppModule {}
Once imported, you can inject HttpClient
into any service or component.
2. Creating a Data Service for API Calls
It’s a good practice to keep all API-related logic inside a dedicated Angular service.
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class DataService {
private apiUrl = 'https://jsonplaceholder.typicode.com/users';
constructor(private http: HttpClient) {}
}
3. Understanding POST Requests
A POST request is used to send new data to the server — for example, creating a new user, product, or comment.
The server processes the request and usually returns the created object with an assigned ID or confirmation message.
4. Implementing POST Request in Angular
You can use the http.post()
method to send data.
addUser(newUser: any): Observable<any> {
return this.http.post(this.apiUrl, newUser);
}
In your component:
this.dataService.addUser({ name: 'John', email: '[email protected]' })
.subscribe(response => {
console.log('User created:', response);
});
5. Handling POST Response
The response from the POST
request is typically an object returned by the server.
It may include additional fields like an ID, timestamps, or status message.
You can also handle errors and completion:
this.dataService.addUser(newUser).subscribe({
next: data => console.log('User Added:', data),
error: err => console.error('Error:', err),
complete: () => console.log('Request completed')
});
6. Example: Submitting a Form with POST
Imagine you have a user registration form.
When the form is submitted, the data is sent to the API using a POST request.
HTML Template:
<form (ngSubmit)="onSubmit()">
<input type="text" [(ngModel)]="user.name" name="name" placeholder="Name">
<input type="email" [(ngModel)]="user.email" name="email" placeholder="Email">
<button type="submit">Submit</button>
</form>
Component Code:
user = { name: '', email: '' };
onSubmit() {
this.dataService.addUser(this.user).subscribe(response => {
console.log('User created successfully:', response);
});
}
7. Understanding PUT Requests
A PUT request is used to update an existing record on the server.
While POST
creates new data, PUT
replaces or modifies existing data.
For example, updating a user’s information or editing a product’s price.
8. Implementing PUT Request in Angular
The http.put()
method takes the resource URL and the updated object as parameters.
updateUser(id: number, updatedUser: any): Observable<any> {
return this.http.put(${this.apiUrl}/${id}
, updatedUser);
}
In your component:
this.dataService.updateUser(1, { name: 'Updated Name', email: '[email protected]' })
.subscribe(response => {
console.log('User updated:', response);
});
9. Handling PUT Response
A successful PUT response may return the updated object or a status message.
You can handle responses like this:
this.dataService.updateUser(id, updatedData).subscribe({
next: data => console.log('Updated Successfully:', data),
error: err => console.error('Update Error:', err),
complete: () => console.log('Update Complete')
});
10. Example: Updating User Details
Here’s an example where the user can edit details using a form.
HTML Template:
<form (ngSubmit)="onUpdate()">
<input type="text" [(ngModel)]="user.name" name="name">
<input type="email" [(ngModel)]="user.email" name="email">
<button type="submit">Update</button>
</form>
Component Code:
user = { id: 1, name: 'John', email: '[email protected]' };
onUpdate() {
this.dataService.updateUser(this.user.id, this.user)
.subscribe(result => console.log('User updated:', result));
}
11. Understanding DELETE Requests
A DELETE request removes an existing record from the server.
This is commonly used for actions like deleting a user, product, or comment.
12. Implementing DELETE Request in Angular
You can use the http.delete()
method to remove data by ID.
deleteUser(id: number): Observable<any> {
return this.http.delete(${this.apiUrl}/${id}
);
}
In your component:
this.dataService.deleteUser(1).subscribe(response => {
console.log('User deleted:', response);
});
13. Handling DELETE Response
After deletion, the server usually returns a confirmation message or status code (e.g., 200 OK).
this.dataService.deleteUser(id).subscribe({
next: data => console.log('Deleted:', data),
error: err => console.error('Error:', err),
complete: () => console.log('Delete Complete')
});
14. Example: Deleting a Record
HTML Template:
<ul>
<li *ngFor="let user of users">
{{ user.name }}
<button (click)="delete(user.id)">Delete</button>
</li>
</ul>
Component Code:
delete(id: number) {
this.dataService.deleteUser(id).subscribe(() => {
this.users = this.users.filter(u => u.id !== id);
});
}
15. Using Observables and Subscriptions
Each HTTP method in Angular returns an Observable.
This means that data is fetched asynchronously, allowing for efficient updates and reactivity.
this.dataService.addUser(user).subscribe(response => {
console.log('Async response:', response);
});
You can also use RxJS operators like map
, catchError
, or tap
for more control.
16. Handling Errors with HttpClient
It’s crucial to handle errors gracefully.
You can use catchError
from RxJS for error handling.
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
addUser(user: any): Observable<any> {
return this.http.post(this.apiUrl, user).pipe(
catchError(error => {
console.error('Error:', error);
return throwError(() => error);
})
);
}
17. Using HttpHeaders and Options
You can send custom headers (like Content-Type
or authentication tokens) with your HTTP requests.
import { HttpHeaders } from '@angular/common/http';
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
this.http.post(this.apiUrl, user, { headers }).subscribe();
18. Reusing API URLs with Environment Files
Instead of hardcoding URLs, define them in environment files.
environment.ts:
export const environment = {
production: false,
apiUrl: 'https://jsonplaceholder.typicode.com/users'
};
Service File:
import { environment } from '../environments/environment';
private apiUrl = environment.apiUrl;
19. Creating a Reusable Data Service
You can build a generic service that handles all CRUD operations dynamically.
@Injectable({
providedIn: 'root'
})
export class ApiService {
constructor(private http: HttpClient) {}
get<T>(url: string): Observable<T> {
return this.http.get<T>(url);
}
post<T>(url: string, data: any): Observable<T> {
return this.http.post<T>(url, data);
}
put<T>(url: string, data: any): Observable<T> {
return this.http.put<T>(url, data);
}
delete<T>(url: string): Observable<T> {
return this.http.delete<T>(url);
}
}
Usage Example:
this.apiService.post('https://api.example.com/users', newUser)
.subscribe(res => console.log(res));
20. Best Practices for POST, PUT, and DELETE Requests
- Use Services, not Components, for API Calls
Keep your logic clean and reusable. - Always Handle Errors
Use RxJScatchError
for better reliability. - Use Environment Variables
Never hardcode URLs or secrets. - Use Strong Typing with Interfaces
export interface User { id: number; name: string; email: string; }
- Unsubscribe to Avoid Memory Leaks
UsetakeUntil
orasync
pipes where possible. - Validate Data Before Sending
Always ensure data is in the correct format before making a request. - Use Interceptors for Tokens or Headers
Interceptors can attach authentication tokens automatically.
Leave a Reply