> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/angular/angular/llms.txt
> Use this file to discover all available pages before exploring further.

# HttpClient

> Make HTTP requests with Angular HttpClient using Observables and RxJS operators.

## Overview

The `HttpClient` service provides a powerful and flexible API for making HTTP requests in Angular applications. It returns RxJS Observables, enabling reactive programming patterns and composable data streams.

## Setup

### Standalone applications

Provide `HttpClient` in your application configuration:

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

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient()
  ]
};
```

### Module-based applications

Import `HttpClientModule` in your application module:

```typescript app.module.ts theme={null}
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

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

<Note>
  For server-side rendering applications, use `withFetch()` for better performance:

  ```typescript theme={null}
  provideHttpClient(withFetch())
  ```
</Note>

## Injecting HttpClient

Inject `HttpClient` into your services or components:

```typescript user.service.ts theme={null}
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

interface User {
  id: number;
  name: string;
  email: string;
}

@Injectable({ providedIn: 'root' })
export class UserService {
  private http = inject(HttpClient);
  private apiUrl = 'https://api.example.com';

  getUsers(): Observable<User[]> {
    return this.http.get<User[]>(`${this.apiUrl}/users`);
  }
}
```

## HTTP Methods

### GET requests

Retrieve data from the server:

```typescript theme={null}
// Simple GET request
http.get<User[]>('/api/users').subscribe(users => {
  console.log('Users:', users);
});

// GET with query parameters
http.get<User[]>('/api/users', {
  params: { role: 'admin', active: true }
}).subscribe(users => {
  console.log('Admin users:', users);
});

// GET with headers
http.get<User>('/api/users/1', {
  headers: { 'Authorization': 'Bearer token' }
}).subscribe(user => {
  console.log('User:', user);
});
```

### POST requests

Send data to create new resources:

```typescript theme={null}
const newUser: User = {
  id: 0,
  name: 'John Doe',
  email: 'john@example.com'
};

http.post<User>('/api/users', newUser).subscribe({
  next: (user) => console.log('Created user:', user),
  error: (error) => console.error('Error:', error)
});

// POST with options
http.post<User>('/api/users', newUser, {
  headers: { 'Content-Type': 'application/json' },
  observe: 'response'
}).subscribe(response => {
  console.log('Status:', response.status);
  console.log('User:', response.body);
});
```

### PUT requests

Update existing resources:

```typescript theme={null}
const updatedUser: User = {
  id: 1,
  name: 'Jane Doe',
  email: 'jane@example.com'
};

http.put<User>('/api/users/1', updatedUser).subscribe({
  next: (user) => console.log('Updated user:', user),
  error: (error) => console.error('Update failed:', error)
});
```

### PATCH requests

Partially update resources:

```typescript theme={null}
// Update only the name field
http.patch<User>('/api/users/1', { name: 'New Name' }).subscribe(user => {
  console.log('Patched user:', user);
});
```

### DELETE requests

Remove resources:

```typescript theme={null}
http.delete(`/api/users/${userId}`).subscribe({
  next: () => console.log('User deleted'),
  error: (error) => console.error('Delete failed:', error)
});

// DELETE with response body
http.delete<{ message: string }>(`/api/users/${userId}`).subscribe(result => {
  console.log(result.message);
});
```

## Request Options

### Query parameters

Add URL query parameters using the `params` option:

```typescript theme={null}
import { HttpParams } from '@angular/common/http';

// Using object notation
http.get('/api/users', {
  params: { 
    page: 1, 
    limit: 10,
    sort: 'name'
  }
});

// Using HttpParams for complex scenarios
let params = new HttpParams()
  .set('page', '1')
  .set('limit', '10')
  .append('tags', 'angular')
  .append('tags', 'typescript');

http.get('/api/posts', { params });
// URL: /api/posts?page=1&limit=10&tags=angular&tags=typescript
```

### Headers

Customize request headers:

```typescript theme={null}
import { HttpHeaders } from '@angular/common/http';

// Using object notation
http.get('/api/users', {
  headers: {
    'Authorization': 'Bearer token',
    'X-Custom-Header': 'value'
  }
});

// Using HttpHeaders
const headers = new HttpHeaders()
  .set('Authorization', 'Bearer token')
  .set('Content-Type', 'application/json');

http.post('/api/users', data, { headers });
```

### Response types

Specify the expected response type:

```typescript theme={null}
// JSON (default)
http.get<User>('/api/users/1');

// Text
http.get('/api/data', { responseType: 'text' }).subscribe(text => {
  console.log(text);
});

// ArrayBuffer
http.get('/api/file', { responseType: 'arraybuffer' }).subscribe(buffer => {
  const blob = new Blob([buffer]);
});

// Blob
http.get('/api/image', { responseType: 'blob' }).subscribe(blob => {
  const url = URL.createObjectURL(blob);
});
```

### Observing responses

Control what information is returned:

```typescript theme={null}
// Body only (default)
http.get<User>('/api/users/1').subscribe(user => {
  console.log(user);
});

// Full response with headers and status
http.get<User>('/api/users/1', { observe: 'response' }).subscribe(response => {
  console.log('Status:', response.status);
  console.log('Headers:', response.headers.get('X-Custom'));
  console.log('Body:', response.body);
});

// Event stream for progress tracking
http.get('/api/large-file', { 
  observe: 'events',
  reportProgress: true 
}).subscribe(event => {
  if (event.type === HttpEventType.DownloadProgress) {
    const progress = event.loaded / (event.total || 1) * 100;
    console.log(`Download: ${progress}%`);
  }
});
```

## Working with Observables

### Basic subscription

```typescript theme={null}
import { Component, OnInit, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-users',
  template: `
    <div *ngFor="let user of users">
      {{ user.name }}
    </div>
  `
})
export class UsersComponent implements OnInit {
  private http = inject(HttpClient);
  users: User[] = [];

  ngOnInit() {
    this.http.get<User[]>('/api/users').subscribe({
      next: (users) => this.users = users,
      error: (error) => console.error('Error loading users:', error)
    });
  }
}
```

### RxJS operators

Transform HTTP responses using RxJS operators:

```typescript theme={null}
import { map, filter, catchError, retry, timeout } from 'rxjs/operators';
import { of } from 'rxjs';

// Transform the response
http.get<User[]>('/api/users').pipe(
  map(users => users.filter(u => u.active)),
  map(users => users.sort((a, b) => a.name.localeCompare(b.name)))
).subscribe(sortedActiveUsers => {
  console.log(sortedActiveUsers);
});

// Retry on failure
http.get<User[]>('/api/users').pipe(
  retry(3),
  catchError(error => {
    console.error('Failed after 3 retries:', error);
    return of([]); // Return empty array as fallback
  })
).subscribe(users => {
  console.log(users);
});

// Timeout
http.get<User[]>('/api/users').pipe(
  timeout(5000),
  catchError(error => {
    console.error('Request timed out');
    return of([]);
  })
).subscribe(users => {
  console.log(users);
});
```

### Combining multiple requests

```typescript theme={null}
import { forkJoin, combineLatest } from 'rxjs';

// Wait for all requests to complete
forkJoin({
  users: http.get<User[]>('/api/users'),
  posts: http.get<Post[]>('/api/posts'),
  comments: http.get<Comment[]>('/api/comments')
}).subscribe(({ users, posts, comments }) => {
  console.log('All data loaded:', users, posts, comments);
});

// Combine latest values
combineLatest([
  http.get<User[]>('/api/users'),
  http.get<Config>('/api/config')
]).subscribe(([users, config]) => {
  console.log('Users and config:', users, config);
});
```

### Sequential requests

```typescript theme={null}
import { switchMap, mergeMap } from 'rxjs/operators';

// Switch to new request (cancels previous)
http.get<User>('/api/users/1').pipe(
  switchMap(user => http.get<Post[]>(`/api/users/${user.id}/posts`))
).subscribe(posts => {
  console.log('User posts:', posts);
});

// Process all requests
http.get<User[]>('/api/users').pipe(
  mergeMap(users => users),
  mergeMap(user => http.get<Post[]>(`/api/users/${user.id}/posts`))
).subscribe(posts => {
  console.log('Posts:', posts);
});
```

## Type safety

Provide type information for responses:

```typescript theme={null}
interface ApiResponse<T> {
  data: T;
  status: string;
  timestamp: number;
}

interface User {
  id: number;
  name: string;
  email: string;
}

// Type-safe request
http.get<ApiResponse<User>>('/api/users/1').subscribe(response => {
  const user = response.data;
  console.log(user.name); // TypeScript knows about .name
});

// Array of users
http.get<User[]>('/api/users').subscribe(users => {
  users.forEach(user => {
    console.log(user.email); // Type-safe access
  });
});
```

## Advanced options

### Request credentials

```typescript theme={null}
// Include credentials in cross-origin requests
http.get('/api/users', {
  withCredentials: true
}).subscribe();

// Using Fetch API credentials option
http.get('/api/users', {
  credentials: 'include' // 'omit' | 'same-origin' | 'include'
}).subscribe();
```

### Request timeout

```typescript theme={null}
// Set timeout in milliseconds
http.get('/api/users', {
  timeout: 5000 // 5 seconds
}).subscribe({
  error: (error) => console.error('Request timed out')
});
```

### Transfer cache (SSR)

```typescript theme={null}
// Cache responses for server-side rendering
http.get('/api/users', {
  transferCache: true
}).subscribe();

// Cache with specific headers
http.get('/api/users', {
  transferCache: {
    includeHeaders: ['Authorization', 'X-Custom-Header']
  }
}).subscribe();
```

## Best practices

<Tip>
  **Use services for HTTP calls**

  Encapsulate HTTP logic in dedicated services rather than making calls directly from components.
</Tip>

<Tip>
  **Provide type information**

  Always specify generic types for type-safe responses: `http.get<User[]>('/api/users')`
</Tip>

<Tip>
  **Handle errors appropriately**

  Use error handlers or the `catchError` operator to gracefully handle failed requests.
</Tip>

<Warning>
  HTTP requests are not executed until you subscribe to the Observable. Always remember to subscribe, or use operators like `toPromise()` or the `async` pipe in templates.
</Warning>

<Tip>
  **Unsubscribe when needed**

  For long-lived subscriptions in components, unsubscribe in `ngOnDestroy` or use the `async` pipe which automatically unsubscribes.
</Tip>

## Next steps

<CardGroup cols={2}>
  <Card title="Interceptors" icon="filter" href="/http/interceptors">
    Transform requests and responses globally with HTTP interceptors.
  </Card>

  <Card title="Error handling" icon="triangle-exclamation" href="/http/error-handling">
    Handle HTTP errors and implement retry logic.
  </Card>
</CardGroup>
