ng-http-client

Angular HTTP Client


Overview


Requests

http.get<Student>(`/api/students/${id}`).subscribe(student => {
  // process student
});
{
  "id": 42,
  "name": "John Doe",
  "data": "unused"
}
export interface Student {
  id: number,
  name: string
}
  • Generisch
  • Lazy requests (subscribe)

Post

http.post(url, body)
http.post<Student>('/api/students', newStudent)
  .subscribe(student => {
    console.log('Student saved:', student);
  }
);

Service

export class ApiService {

  private readonly baseUrl = 'http://www.the-backend.com/api';
  private http = inject(HttpClient);

  getAllStudent() {
    return this.http
      .get<Student[]>(`${this.baseUrl}/students`);
  }
  
  saveStudent(student: Student) {
    return this.http
      .post<Student>(`${this.baseUrl}/students`, student);
  }
}

Basic usage

export class StudentListComponent {

  private apiService = inject(ApiService);
  students = signal<Student[]>([]);

  loadStudents() {
    this.apiService
        .getAllStudents()   // return this.http.get( ... )
        .subscribe(students => this.students.set(students));
  }
}

Error handling

export class StudentListComponent {

  private apiService = inject(ApiService);
  students = signal<Student[]>([]);
  error = signal('');

  loadStudents() {
    this.apiService
        .getAllStudents()
        .subscribe({
          next: students => this.students.set(students),
          error: (error: HttpErrorResponse) => this.error.set(error)
        });
  }
}

Caching

export class ApiService {

  private readonly baseUrl = environment.baseUrl;
  private readonly _students = signal<Student[]>([]);
  readonly students = this._students.asReadonly();

  getStudent(id: number): Observable<Student> {
    const cached = this._students().find(p => p.id === id)
    if (cached)
      return of(cached); // Student -> Observable<Student>
    // cache miss
    return this.http
      .get<Student>(`${this.baseUrl}/students/${id}`)
      .pipe(
        tap(student => // do this, then continue as normal 
                      this._students.set([...this._students(), student]))
    );
  }

| async

@for (student of students$ | async; track $index) {
  <app-student-item [student]="student"></app-student-item>
}
Component {
  students$: Observable<Student[]>;
  private apiService = inject(ApiService);
  
  constructor() {
    this.students$ = apiService.getAll();
  }
}

automatisches subscribe


Query params

go(): Student[] {
  return http.get<Student[]>('/api/search', {
    params: {q: 'angular'}, // /api/search?q=angular
  });
}

Kein Request geht raus; warum?


Headers

http.get<Status>('/api/status', 
  { headers: { 'Authorization': 'Basic bG9yZW0gaXBzdW0=' } }
);

Zugriff auf Response header:

http.get<Status>('/api/status', { observe: 'response' })
  .subscribe(res => {
    console.log('Response status:', res.status);
    console.log('Body:', res.body);
);

Interceptors

getAllStudents() {
  console.log('Request:', 'GET', `${this.baseUrl}/students`);
  return this.http
    .get<Student[]>(`${this.baseUrl}/students`)
    .pipe(tap(res => console.log('Response:', res)));
}

saveStudent(student: Student) {
  console.log('Request:', 'POST', `${this.baseUrl}/students`);
  return this.http
    .post<Student>(`${this.baseUrl}/students`, student)
    .pipe(tap(res => console.log('Response:', res)));
}

...

Funktionalität dupliziert auf alle http-Calls


Interceptors

export const logInterceptor: HttpInterceptorFn = (req, next) => {
  console.log('Request:', req.method, req.url);
  return next(req).pipe(tap(res => console.log('Response:', res)));
};
export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(withInterceptors(
      [errorInterceptor, logInterceptor]
    ))
  ]
};

Use cases

  • Authentication Header
  • Failed Requests retrying
  • Caching
  • Logging
  • Zeitmessung bis zur Serverantwort