Introduction
When building web applications, HTTP requests often require additional data to be sent along with them. This can include headers (for authentication, content type, etc.) and query parameters (for pagination, searching, filtering, or sorting).
Angular’s HttpClient
provides powerful options to attach both headers and parameters dynamically. These make your API interactions more flexible, secure, and maintainable.
In this detailed guide, we’ll explore how to use HttpHeaders
and HttpParams
in Angular to send custom headers and query parameters in GET, POST, PUT, and DELETE requests.
Table of Contents
- Setting Up HttpClientModule
- Creating a Data Service
- What Are HTTP Headers?
- Why Use Headers in Angular?
- Creating and Adding Headers
- Example: Adding Authorization Header
- Dynamic Headers
- Setting Multiple Headers
- Removing and Appending Headers
- Using Headers with POST, PUT, and DELETE
- What Are Query Parameters?
- Creating Query Parameters in Angular
- Example: Pagination with Query Parameters
- Example: Filtering Data Using Parameters
- Dynamic Parameters in Requests
- Combining Headers and Params
- Example: GET Request with Headers and Params
- Using Observables for Request Handling
- Handling Errors in Header-Based Requests
- Reusing Headers and Params with Services
- Using Interceptors for Global Headers
- Adding Auth Tokens Automatically
- Using Environment Variables for API URLs
- Best Practices for Headers and Params
- Full Working Example (User Service)
- Conclusion
1. Setting Up HttpClientModule
Before using headers and parameters, you must set up the HttpClientModule
in your main app 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 {}
This enables HttpClient
for the entire application.
2. Creating a Data Service
A service allows you to centralize your API logic.
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } 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. What Are HTTP Headers?
Headers are key-value pairs sent along with an HTTP request or response.
They provide metadata such as authentication information, content type, or caching policies.
For example:
Content-Type
: Defines the format of the request body (e.g., JSON, XML).Authorization
: Used for access tokens or credentials.Accept
: Defines the response format expected by the client.
4. Why Use Headers in Angular?
You might need headers for:
- Sending authentication tokens.
- Specifying content type.
- Managing cache control.
- Controlling API versioning.
const headers = new HttpHeaders({ 'Authorization': 'Bearer token' });
5. Creating and Adding Headers
Headers in Angular are created using the HttpHeaders
class.
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer my-token'
});
this.http.get(this.apiUrl, { headers });
6. Example: Adding Authorization Header
Here’s how to add a token header in a service method.
getUsers(): Observable<any> {
const headers = new HttpHeaders({
Authorization: 'Bearer 12345abcde'
});
return this.http.get(this.apiUrl, { headers });
}
In the component:
this.dataService.getUsers().subscribe(data => {
console.log('Users:', data);
});
7. Dynamic Headers
Sometimes, headers need to be generated at runtime (for example, after login).
getProtectedData(token: string): Observable<any> {
const headers = new HttpHeaders({
Authorization: Bearer ${token}
});
return this.http.get(${this.apiUrl}/protected
, { headers });
}
8. Setting Multiple Headers
You can set multiple headers at once.
const headers = new HttpHeaders()
.set('Content-Type', 'application/json')
.set('Authorization', 'Bearer 123')
.set('Custom-Header', 'AppData');
this.http.get(this.apiUrl, { headers }).subscribe();
9. Removing and Appending Headers
The HttpHeaders
object is immutable. Each operation like set
or append
returns a new instance.
let headers = new HttpHeaders().set('Authorization', 'Bearer token');
headers = headers.append('App-Version', '1.0.0');
To remove a header:
headers = headers.delete('Authorization');
10. Using Headers with POST, PUT, and DELETE
Headers can be attached to any type of request.
addUser(user: any): Observable<any> {
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
return this.http.post(this.apiUrl, user, { headers });
}
Similarly for PUT:
updateUser(id: number, user: any): Observable<any> {
const headers = new HttpHeaders({ 'Authorization': 'Bearer xyz' });
return this.http.put(${this.apiUrl}/${id}
, user, { headers });
}
And DELETE:
deleteUser(id: number): Observable<any> {
const headers = new HttpHeaders({ 'Authorization': 'Bearer xyz' });
return this.http.delete(${this.apiUrl}/${id}
, { headers });
}
11. What Are Query Parameters?
Query parameters are appended to the end of a URL to pass extra information to the server.
They are useful for:
- Filtering results
- Paginating data
- Searching
- Sorting
Example:
https://api.example.com/users?page=2&limit=10
12. Creating Query Parameters in Angular
Angular provides the HttpParams
class to build parameters easily.
const params = new HttpParams()
.set('page', '1')
.set('limit', '10');
Usage:
this.http.get(this.apiUrl, { params });
13. Example: Pagination with Query Parameters
getUsers(page: number, limit: number): Observable<any> {
const params = new HttpParams()
.set('page', page)
.set('limit', limit);
return this.http.get(this.apiUrl, { params });
}
Component:
this.dataService.getUsers(1, 10).subscribe(data => {
console.log('Page 1 Users:', data);
});
14. Example: Filtering Data Using Parameters
Query parameters can also filter results dynamically.
searchUsers(name: string): Observable<any> {
const params = new HttpParams().set('name', name);
return this.http.get(this.apiUrl, { params });
}
this.dataService.searchUsers('John').subscribe(result => {
console.log(result);
});
15. Dynamic Parameters in Requests
Parameters can be added conditionally based on user actions.
getFilteredUsers(filters: any): Observable<any> {
let params = new HttpParams();
if (filters.name) params = params.set('name', filters.name);
if (filters.age) params = params.set('age', filters.age);
if (filters.status) params = params.set('status', filters.status);
return this.http.get(this.apiUrl, { params });
}
16. Combining Headers and Params
You can send both headers and parameters together in a single request.
const headers = new HttpHeaders({ 'Authorization': 'Bearer token' });
const params = new HttpParams().set('page', '2').set('limit', '5');
this.http.get(this.apiUrl, { headers, params }).subscribe();
17. Example: GET Request with Headers and Params
getUsersWithAuthAndPagination(token: string, page: number): Observable<any> {
const headers = new HttpHeaders({ Authorization: Bearer ${token}
});
const params = new HttpParams().set('page', page.toString());
return this.http.get(this.apiUrl, { headers, params });
}
18. Using Observables for Request Handling
Angular’s HttpClient
returns Observables, making it easy to handle asynchronous data and responses.
this.dataService.getUsersWithAuthAndPagination('token', 2)
.subscribe(response => {
console.log('Received data:', response);
});
You can also use RxJS operators like map
, catchError
, or tap
for transformation and error handling.
19. Handling Errors in Header-Based Requests
You can use catchError
to handle failed API requests.
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
getSecureData(): Observable<any> {
const headers = new HttpHeaders({ Authorization: 'Bearer invalid-token' });
return this.http.get(this.apiUrl, { headers }).pipe(
catchError(error => {
console.error('API Error:', error);
return throwError(() => error);
})
);
}
20. Reusing Headers and Params with Services
You can define reusable header and parameter logic inside your service.
private createAuthHeaders(token: string): HttpHeaders {
return new HttpHeaders({ Authorization: Bearer ${token}
});
}
private createPaginationParams(page: number, limit: number): HttpParams {
return new HttpParams().set('page', page).set('limit', limit);
}
getPaginatedData(token: string, page: number, limit: number): Observable<any> {
const headers = this.createAuthHeaders(token);
const params = this.createPaginationParams(page, limit);
return this.http.get(this.apiUrl, { headers, params });
}
21. Using Interceptors for Global Headers
Interceptors allow adding headers automatically to all HTTP requests without repeating code.
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const cloned = req.clone({
setHeaders: {
Authorization: 'Bearer my-global-token'
}
});
return next.handle(cloned);
}
}
Register the interceptor in your app module:
import { HTTP_INTERCEPTORS } from '@angular/common/http';
@NgModule({
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
]
})
export class AppModule {}
22. Adding Auth Tokens Automatically
Once the interceptor is in place, every request sent by HttpClient
will automatically include the token header.
This eliminates the need to manually add headers in every service method.
23. Using Environment Variables for API URLs
Instead of hardcoding API URLs, define them in your environment.ts
files.
export const environment = {
production: false,
apiUrl: 'https://api.example.com'
};
Usage in service:
import { environment } from '../environments/environment';
private apiUrl = ${environment.apiUrl}/users
;
24. Best Practices for Headers and Params
- Use Services for All API Calls
Keep components clean and focused on UI logic. - Centralize Headers
Use interceptors or helper functions to avoid duplication. - Use Strong Typing
Create TypeScript interfaces for responses. - Avoid Hardcoding Tokens
Store tokens securely using local storage or Angular services. - Handle Errors Gracefully
UsecatchError
and provide user feedback. - Combine Headers and Params Efficiently
Don’t create new HttpHeaders or HttpParams unnecessarily. - Leverage RxJS Operators
Usemap
,tap
,finalize
, andcatchError
for robust data streams. - Use Environment Configurations
Keep different API URLs for development and production.
25. Full Working Example (User Service)
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '../environments/environment';
@Injectable({
providedIn: 'root'
})
export class UserService {
private apiUrl = ${environment.apiUrl}/users
;
constructor(private http: HttpClient) {}
getUsers(token: string, page: number, limit: number): Observable<any> {
const headers = new HttpHeaders({ Authorization: Bearer ${token}
});
const params = new HttpParams().set('page', page).set('limit', limit);
return this.http.get(this.apiUrl, { headers, params });
}
addUser(token: string, user: any): Observable<any> {
const headers = new HttpHeaders({
Authorization: Bearer ${token}
,
'Content-Type': 'application/json'
});
return this.http.post(this.apiUrl, user, { headers });
}
updateUser(token: string, id: number, user: any): Observable<any> {
const headers = new HttpHeaders({ Authorization: Bearer ${token}
});
return this.http.put(${this.apiUrl}/${id}
, user, { headers });
}
deleteUser(token: string, id: number): Observable<any> {
const headers = new HttpHeaders({ Authorization: Bearer ${token}
});
return this.http.delete(${this.apiUrl}/${id}
, { headers });
}
}
Usage in component:
this.userService.getUsers('myToken', 1, 10).subscribe(users => {
console.log(users);
});
Leave a Reply