Angular HTTP Client & APIs
Zeit für echte Daten! Lerne mit Backend-APIs zu kommunizieren. 🌐
📋 In diesem Artikel lernst du:
- HttpClient Setup und Konfiguration
- GET Requests (Daten laden)
- POST Requests (Daten erstellen)
- PUT/PATCH Requests (Daten updaten)
- DELETE Requests (Daten löschen)
- Error Handling
- HTTP Headers und Query Parameters
- Interceptors (Request/Response Manipulation)
- RxJS Operators für HTTP
- Loading States und Retry Logic
Was ist HttpClient?
HttpClient ist Angular's Service für HTTP-Kommunikation mit Backend-APIs.
Features:
- ✅ Type-safe (TypeScript Interfaces)
- ✅ Observable-basiert (RxJS)
- ✅ Automatisches JSON Parsing
- ✅ Error Handling
- ✅ Interceptors (Middleware)
- ✅ Testing Support
HttpClient Setup
HttpClientModule importieren
app.module.ts:
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [
BrowserModule,
HttpClientModule // ✅ Wichtig!
],
// ...
})
export class AppModule { }
Ohne diesen Import funktioniert HttpClient NICHT!
GET Requests - Daten laden
Basic GET Request
API Endpoint: https://jsonplaceholder.typicode.com/users
user.service.ts:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
export interface User {
id: number;
name: string;
email: string;
username: string;
}
@Injectable({
providedIn: 'root'
})
export class UserService {
private apiUrl = 'https://jsonplaceholder.typicode.com/users';
constructor(private http: HttpClient) {}
// ✅ GET Request
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl);
}
// ✅ GET Single User
getUserById(id: number): Observable<User> {
return this.http.get<User>(`${this.apiUrl}/${id}`);
}
}
Erklärung:
http.get<User[]>()- Type-safe! Response istUser[]- Return Type:
Observable<User[]>- Asynchron! .get()führt Request NICHT aus! Erst bei.subscribe()
Service in Komponente nutzen
user-list.component.ts:
import { Component, OnInit } from '@angular/core';
import { UserService, User } from './services/user.service';
@Component({
selector: 'app-user-list',
template: `
<div class="user-list">
<h1>Users</h1>
<!-- Loading State -->
<div *ngIf="loading" class="loading">
Lädt Daten...
</div>
<!-- Error State -->
<div *ngIf="error" class="error">
{{ error }}
</div>
<!-- Success State -->
<div *ngIf="!loading && !error">
<div *ngFor="let user of users" class="user-card">
<h3>{{ user.name }}</h3>
<p>{{ user.email }}</p>
<p>@{{ user.username }}</p>
</div>
</div>
</div>
`,
styles: [`
.user-card {
padding: 1rem;
border: 1px solid #e5e7eb;
border-radius: 8px;
margin-bottom: 1rem;
}
.loading {
text-align: center;
padding: 2rem;
color: #6b7280;
}
.error {
padding: 1rem;
background: #fef2f2;
border: 1px solid #ef4444;
border-radius: 8px;
color: #dc2626;
}
`]
})
export class UserListComponent implements OnInit {
users: User[] = [];
loading = false;
error: string | null = null;
constructor(private userService: UserService) {}
ngOnInit() {
this.loadUsers();
}
loadUsers() {
this.loading = true;
this.error = null;
// ✅ Subscribe zu Observable
this.userService.getUsers().subscribe({
next: (users) => {
this.users = users;
this.loading = false;
},
error: (err) => {
this.error = 'Fehler beim Laden der User';
this.loading = false;
console.error('Error:', err);
}
});
}
}
Wichtig:
.subscribe()startet den Request!next:- Success Handlererror:- Error Handler- Immer Loading & Error States implementieren!
Tipps & Tricks
Type-Safety mit Interfaces
Ohne Interface (BAD):
getUsers(): Observable<any> { // ❌ any = no type safety
return this.http.get(this.apiUrl);
}
Mit Interface (GOOD):
getUsers(): Observable<User[]> { // ✅ Type-safe!
return this.http.get<User[]>(this.apiUrl);
}
Nutze IMMER Interfaces für API Responses!
Async Pipe Alternative
Statt Subscribe:
export class UserListComponent {
users$ = this.userService.getUsers(); // ✅ Observable direkt
constructor(private userService: UserService) {}
}
<div *ngFor="let user of users$ | async">
{{ user.name }}
</div>
Async Pipe macht automatisch subscribe/unsubscribe!
Environment Variables für API URLs
environments/environment.ts:
export const environment = {
production: false,
apiUrl: 'https://api.example.com'
};
Service:
import { environment } from '../environments/environment';
@Injectable({ providedIn: 'root' })
export class UserService {
private apiUrl = environment.apiUrl;
// ...
}
POST Requests - Daten erstellen
POST erstellt neue Daten auf dem Server.
Create User
user.service.ts:
createUser(user: Partial<User>): Observable<User> {
return this.http.post<User>(this.apiUrl, user);
}
create-user.component.ts:
import { Component } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { UserService } from './services/user.service';
@Component({
selector: 'app-create-user',
template: `
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<h2>Neuen User erstellen</h2>
<input formControlName="name" placeholder="Name">
<input formControlName="email" placeholder="Email">
<input formControlName="username" placeholder="Username">
<button
type="submit"
[disabled]="form.invalid || loading"
>
{{ loading ? 'Wird erstellt...' : 'User erstellen' }}
</button>
<div *ngIf="error" class="error">{{ error }}</div>
<div *ngIf="success" class="success">User erfolgreich erstellt!</div>
</form>
`
})
export class CreateUserComponent {
form = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
username: ['', Validators.required]
});
loading = false;
error: string | null = null;
success = false;
constructor(
private fb: FormBuilder,
private userService: UserService
) {}
onSubmit() {
if (this.form.invalid) return;
this.loading = true;
this.error = null;
this.success = false;
// ✅ POST Request
this.userService.createUser(this.form.value).subscribe({
next: (createdUser) => {
console.log('User created:', createdUser);
this.success = true;
this.loading = false;
this.form.reset();
},
error: (err) => {
this.error = 'Fehler beim Erstellen des Users';
this.loading = false;
console.error('Error:', err);
}
});
}
}
POST Body: Form Data wird automatisch als JSON gesendet!
PUT/PATCH Requests - Daten updaten
PUT: Komplette Ressource ersetzen PATCH: Nur bestimmte Felder updaten
Update User
user.service.ts:
// PUT - Komplettes Update
updateUser(id: number, user: User): Observable<User> {
return this.http.put<User>(`${this.apiUrl}/${id}`, user);
}
// PATCH - Partielles Update
patchUser(id: number, updates: Partial<User>): Observable<User> {
return this.http.patch<User>(`${this.apiUrl}/${id}`, updates);
}
Komponente:
updateUserEmail(userId: number, newEmail: string) {
this.loading = true;
// ✅ PATCH nur Email
this.userService.patchUser(userId, { email: newEmail }).subscribe({
next: (updatedUser) => {
console.log('User updated:', updatedUser);
this.loading = false;
},
error: (err) => {
this.error = 'Update fehlgeschlagen';
this.loading = false;
}
});
}
DELETE Requests - Daten löschen
Delete User
user.service.ts:
deleteUser(id: number): Observable<void> {
return this.http.delete<void>(`${this.apiUrl}/${id}`);
}
Komponente:
deleteUser(userId: number) {
if (!confirm('User wirklich löschen?')) return;
this.loading = true;
// ✅ DELETE Request
this.userService.deleteUser(userId).subscribe({
next: () => {
console.log('User deleted');
// Remove from local array
this.users = this.users.filter(u => u.id !== userId);
this.loading = false;
},
error: (err) => {
this.error = 'Löschen fehlgeschlagen';
this.loading = false;
}
});
}
Query Parameters & Headers
Query Parameters
URL: /users?role=admin&active=true
getUsers(role?: string, active?: boolean): Observable<User[]> {
// ✅ Option 1: HttpParams
let params = new HttpParams();
if (role) params = params.set('role', role);
if (active !== undefined) params = params.set('active', active.toString());
return this.http.get<User[]>(this.apiUrl, { params });
}
// ✅ Option 2: Object (einfacher!)
getUsersSimple(role?: string): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl, {
params: { role: role || '' }
});
}
Usage:
// GET /users?role=admin&active=true
this.userService.getUsers('admin', true).subscribe(users => {
console.log(users);
});
Custom Headers
getUsersWithAuth(): Observable<User[]> {
const headers = new HttpHeaders({
'Authorization': 'Bearer my-token-123',
'Custom-Header': 'value'
});
return this.http.get<User[]>(this.apiUrl, { headers });
}
Error Handling
Proper Error Handling
user.service.ts:
import { catchError, throwError } from 'rxjs';
import { HttpErrorResponse } from '@angular/common/http';
@Injectable({ providedIn: 'root' })
export class UserService {
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl).pipe(
catchError(this.handleError)
);
}
private handleError(error: HttpErrorResponse) {
let errorMessage = 'Ein Fehler ist aufgetreten';
if (error.error instanceof ErrorEvent) {
// Client-seitiger Error
errorMessage = `Client Error: ${error.error.message}`;
} else {
// Server-seitiger Error
switch (error.status) {
case 400:
errorMessage = 'Ungültige Anfrage';
break;
case 401:
errorMessage = 'Nicht authentifiziert';
break;
case 403:
errorMessage = 'Zugriff verweigert';
break;
case 404:
errorMessage = 'Ressource nicht gefunden';
break;
case 500:
errorMessage = 'Server-Fehler';
break;
default:
errorMessage = `Server Error: ${error.status}`;
}
}
console.error('HTTP Error:', error);
return throwError(() => new Error(errorMessage));
}
}
Komponente:
loadUsers() {
this.userService.getUsers().subscribe({
next: (users) => this.users = users,
error: (err) => this.error = err.message // ✅ Formatted Error Message
});
}
Häufige Fehler
Fehler 1: HttpClientModule nicht importiert
❌ Problem:
Error: NullInjectorError: No provider for HttpClient!
✅ Lösung:
// app.module.ts
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [HttpClientModule] // ✅ Import hinzufügen
})
Fehler 2: Subscribe vergessen
❌ Problem:
// Request wird NIE ausgeführt!
this.userService.getUsers(); // ❌ Kein subscribe!
✅ Lösung:
this.userService.getUsers().subscribe(users => {
console.log(users); // ✅ Jetzt wird Request ausgeführt
});
Observables sind LAZY! Ohne .subscribe() passiert NICHTS!
Fehler 3: Unsubscribe vergessen
❌ Problem:
ngOnInit() {
// ❌ Memory Leak!
this.userService.getUsers().subscribe(users => {
this.users = users;
});
}
✅ Lösung 1: Async Pipe
users$ = this.userService.getUsers(); // ✅ Kein subscribe
<div *ngFor="let user of users$ | async">
✅ Lösung 2: Unsubscribe
subscription!: Subscription;
ngOnInit() {
this.subscription = this.userService.getUsers().subscribe(...);
}
ngOnDestroy() {
this.subscription?.unsubscribe(); // ✅ Cleanup
}
✅ Lösung 3: takeUntil
private destroy$ = new Subject<void>();
ngOnInit() {
this.userService.getUsers()
.pipe(takeUntil(this.destroy$))
.subscribe(users => this.users = users);
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
Fehler 4: Fehlendes Error Handling
❌ Problem:
this.http.get(url).subscribe(data => {
// ❌ Kein Error Handler!
console.log(data);
});
✅ Lösung:
this.http.get(url).subscribe({
next: (data) => console.log(data),
error: (err) => console.error(err) // ✅ Error Handler
});
HTTP Interceptors
Interceptors manipulieren alle HTTP Requests/Responses!
Use Cases:
- ✅ Auth Token zu allen Requests hinzufügen
- ✅ Loading Spinner global
- ✅ Error Handling
- ✅ Logging
- ✅ Retry Logic
Auth Interceptor (Add Token to all Requests)
interceptors/auth.interceptor.ts:
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>> {
// Get token (z.B. from localStorage or AuthService)
const token = localStorage.getItem('auth_token');
if (token) {
// ✅ Clone Request und füge Authorization Header hinzu
const clonedReq = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
return next.handle(clonedReq);
}
// Kein Token → Original Request
return next.handle(req);
}
}
In app.module.ts registrieren:
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './interceptors/auth.interceptor';
@NgModule({
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true // ✅ Wichtig! Mehrere Interceptors möglich
}
]
})
export class AppModule { }
Jetzt hat JEDER Request automatisch den Authorization Header! ✅
Loading Interceptor
interceptors/loading.interceptor.ts:
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { LoadingService } from '../services/loading.service';
@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
constructor(private loadingService: LoadingService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// ✅ Request startet → Loading anzeigen
this.loadingService.show();
return next.handle(req).pipe(
// ✅ Request fertig (Success oder Error) → Loading verstecken
finalize(() => this.loadingService.hide())
);
}
}
services/loading.service.ts:
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class LoadingService {
private loadingSubject = new BehaviorSubject<boolean>(false);
loading$ = this.loadingSubject.asObservable();
show() {
this.loadingSubject.next(true);
}
hide() {
this.loadingSubject.next(false);
}
}
app.component.ts:
export class AppComponent {
loading$ = this.loadingService.loading$;
constructor(private loadingService: LoadingService) {}
}
app.component.html:
<div *ngIf="loading$ | async" class="loading-spinner">
Lädt...
</div>
<router-outlet></router-outlet>
Jetzt erscheint bei JEDEM HTTP Request automatisch ein Loading Spinner! 🎉
RxJS Operators für HTTP
map - Response transformieren
getUsers(): Observable<string[]> {
return this.http.get<User[]>(this.apiUrl).pipe(
map(users => users.map(u => u.name)) // ✅ Nur Namen zurückgeben
);
}
catchError - Error Handling
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl).pipe(
catchError(error => {
console.error('Error:', error);
return of([]); // ✅ Empty Array zurückgeben bei Error
})
);
}
retry - Automatisch wiederholen
import { retry } from 'rxjs/operators';
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl).pipe(
retry(3), // ✅ Bei Fehler 3x wiederholen
catchError(this.handleError)
);
}
debounceTime - Search mit Delay
Search Input mit Auto-Complete:
export class SearchComponent implements OnInit {
searchControl = new FormControl('');
results$!: Observable<User[]>;
constructor(private userService: UserService) {}
ngOnInit() {
this.results$ = this.searchControl.valueChanges.pipe(
debounceTime(300), // ✅ Warte 300ms nach letztem Keystroke
distinctUntilChanged(), // ✅ Nur wenn Wert sich ändert
switchMap(query => this.userService.searchUsers(query || ''))
);
}
}
<input [formControl]="searchControl" placeholder="Suche...">
<div *ngFor="let user of results$ | async">
{{ user.name }}
</div>
forkJoin - Multiple Requests parallel
import { forkJoin } from 'rxjs';
loadAllData() {
forkJoin({
users: this.userService.getUsers(),
posts: this.postService.getPosts(),
comments: this.commentService.getComments()
}).subscribe(({ users, posts, comments }) => {
console.log('All loaded!', users, posts, comments);
});
}
Alle 3 Requests laufen parallel! Callback erst wenn ALLE fertig!
Debugging & Troubleshooting
Network Tab nutzen (Chrome DevTools)
F12 → Network Tab:
- Filter: XHR für HTTP Requests
- Request URL: Prüfe ob URL korrekt ist
- Status Code: 200 = OK, 404 = Not Found, 500 = Server Error
- Request Headers: Prüfe Authorization, Content-Type
- Response: Prüfe was Server zurückgibt
CORS Errors
Problem:
Access to XMLHttpRequest blocked by CORS policy
Bedeutung: Backend erlaubt keine Requests von deiner Domain!
✅ Lösung:
- Backend muss CORS Header setzen:
Access-Control-Allow-Origin: * - Oder: Proxy in Angular nutzen (Development)
Development Proxy:
proxy.conf.json:
{
"/api": {
"target": "http://localhost:3000",
"secure": false
}
}
angular.json:
"serve": {
"options": {
"proxyConfig": "proxy.conf.json"
}
}
ng serve # Proxy ist aktiv
Requests zu /api/users werden zu http://localhost:3000/api/users weitergeleitet!
HTTP Request debuggen
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl).pipe(
tap(response => console.log('Response:', response)), // ✅ Debug
catchError(error => {
console.error('Error:', error); // ✅ Debug
return throwError(() => error);
})
);
}
Komplettes Beispiel: Todo API Service
todo.service.ts:
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, retry, map } from 'rxjs/operators';
export interface Todo {
id: number;
title: string;
completed: boolean;
userId: number;
}
@Injectable({
providedIn: 'root'
})
export class TodoService {
private apiUrl = 'https://jsonplaceholder.typicode.com/todos';
constructor(private http: HttpClient) {}
// GET all todos
getTodos(): Observable<Todo[]> {
return this.http.get<Todo[]>(this.apiUrl).pipe(
retry(2), // Bei Fehler 2x wiederholen
catchError(this.handleError)
);
}
// GET single todo
getTodoById(id: number): Observable<Todo> {
return this.http.get<Todo>(`${this.apiUrl}/${id}`).pipe(
catchError(this.handleError)
);
}
// GET todos by user
getTodosByUser(userId: number): Observable<Todo[]> {
return this.http.get<Todo[]>(this.apiUrl, {
params: { userId: userId.toString() }
}).pipe(
catchError(this.handleError)
);
}
// POST new todo
createTodo(todo: Partial<Todo>): Observable<Todo> {
return this.http.post<Todo>(this.apiUrl, todo).pipe(
catchError(this.handleError)
);
}
// PUT update todo
updateTodo(id: number, todo: Todo): Observable<Todo> {
return this.http.put<Todo>(`${this.apiUrl}/${id}`, todo).pipe(
catchError(this.handleError)
);
}
// PATCH partial update
toggleTodo(id: number, completed: boolean): Observable<Todo> {
return this.http.patch<Todo>(`${this.apiUrl}/${id}`, { completed }).pipe(
catchError(this.handleError)
);
}
// DELETE todo
deleteTodo(id: number): Observable<void> {
return this.http.delete<void>(`${this.apiUrl}/${id}`).pipe(
catchError(this.handleError)
);
}
// Stats (derived)
getTodoStats(userId: number): Observable<{ total: number; completed: number; active: number }> {
return this.getTodosByUser(userId).pipe(
map(todos => ({
total: todos.length,
completed: todos.filter(t => t.completed).length,
active: todos.filter(t => !t.completed).length
}))
);
}
// Error Handler
private handleError(error: HttpErrorResponse) {
let errorMessage = 'Ein Fehler ist aufgetreten';
if (error.error instanceof ErrorEvent) {
errorMessage = `Client Error: ${error.error.message}`;
} else {
errorMessage = `Server Error (${error.status}): ${error.message}`;
}
console.error('HTTP Error:', error);
return throwError(() => new Error(errorMessage));
}
}
todo-list.component.ts:
import { Component, OnInit } from '@angular/core';
import { TodoService, Todo } from './services/todo.service';
@Component({
selector: 'app-todo-list',
template: `
<div class="todo-list">
<h1>Todos (User 1)</h1>
<!-- Loading -->
<div *ngIf="loading" class="loading">Lädt...</div>
<!-- Error -->
<div *ngIf="error" class="error">{{ error }}</div>
<!-- Todos -->
<div *ngIf="!loading && !error">
<div class="stats">
<span>Total: {{ todos.length }}</span>
<span>Completed: {{ completedCount }}</span>
<span>Active: {{ activeCount }}</span>
</div>
<div *ngFor="let todo of todos" class="todo-item">
<input
type="checkbox"
[checked]="todo.completed"
(change)="toggleTodo(todo)"
>
<span [class.completed]="todo.completed">
{{ todo.title }}
</span>
<button (click)="deleteTodo(todo.id)">Delete</button>
</div>
</div>
</div>
`
})
export class TodoListComponent implements OnInit {
todos: Todo[] = [];
loading = false;
error: string | null = null;
constructor(private todoService: TodoService) {}
ngOnInit() {
this.loadTodos();
}
loadTodos() {
this.loading = true;
this.error = null;
this.todoService.getTodosByUser(1).subscribe({
next: (todos) => {
this.todos = todos;
this.loading = false;
},
error: (err) => {
this.error = err.message;
this.loading = false;
}
});
}
toggleTodo(todo: Todo) {
this.todoService.toggleTodo(todo.id, !todo.completed).subscribe({
next: (updatedTodo) => {
const index = this.todos.findIndex(t => t.id === todo.id);
this.todos[index] = updatedTodo;
},
error: (err) => console.error('Toggle failed:', err)
});
}
deleteTodo(id: number) {
this.todoService.deleteTodo(id).subscribe({
next: () => {
this.todos = this.todos.filter(t => t.id !== id);
},
error: (err) => console.error('Delete failed:', err)
});
}
get completedCount() {
return this.todos.filter(t => t.completed).length;
}
get activeCount() {
return this.todos.filter(t => !t.completed).length;
}
}
Zusammenfassung
Du hast gelernt:
- ✅ HttpClient für HTTP-Kommunikation mit Backend-APIs
- ✅
HttpClientModuleimportieren - ✅ GET Requests zum Laden von Daten
- ✅ POST Requests zum Erstellen von Daten
- ✅ PUT/PATCH Requests zum Updaten
- ✅ DELETE Requests zum Löschen
- ✅ Query Parameters und Headers
- ✅ Error Handling mit
catchError - ✅ Interceptors für globale Request/Response Manipulation
- ✅ RxJS Operators: map, retry, debounceTime, forkJoin
- ✅ Loading & Error States für bessere UX
Key Takeaways:
- HttpClient gibt Observables zurück (lazy!)
.subscribe()startet Request- Type-safe mit Interfaces:
http.get<User[]>() - Error Handling ist Pflicht
- Interceptors für Auth Token, Loading, Logging
- Async Pipe oder Unsubscribe!
Service Pattern:
@Injectable({ providedIn: 'root' })
export class DataService {
constructor(private http: HttpClient) {}
getData(): Observable<Data[]> {
return this.http.get<Data[]>(url).pipe(
retry(2),
catchError(this.handleError)
);
}
private handleError(error: HttpErrorResponse) {
return throwError(() => new Error('Error!'));
}
}
HTTP gemeistert! Zeit für ein komplettes Projekt! 🎯
Quiz
📝 Quiz
Warum muss man .subscribe() aufrufen?
📝 Quiz
Was macht ein HTTP Interceptor?
📝 Quiz
Was ist der Unterschied zwischen PUT und PATCH?
Übungen
Übung 1: User CRUD Service
Erstelle einen kompletten User Service mit:
getUsers()- Alle User ladengetUserById(id)- Einzelner UsercreateUser(user)- User erstellenupdateUser(id, user)- User updatendeleteUser(id)- User löschen- Error Handling für alle Methoden
API: https://jsonplaceholder.typicode.com/users
Übung 2: Search mit Debounce
Erstelle eine Search-Komponente die:
- Input Field für Suche
- Bei jedem Keystroke API Call (mit 300ms debounce)
- Ergebnisse live anzeigen
- Loading State während Request
- "Keine Ergebnisse" wenn nichts gefunden
API: https://jsonplaceholder.typicode.com/users?name_like={query}
Übung 3: Auth Interceptor
Erstelle einen Auth Interceptor der:
- Token aus localStorage holt
- Authorization Header zu allen Requests hinzufügt
- Bei 401 Error automatisch zu
/loginredirectet - Registriere Interceptor in app.module.ts
Nächste Schritte
Im nächsten Artikel:
- Projekt: Todo App
- Alles zusammenbringen
- Components, Services, Routing, Forms, HTTP
- Complete CRUD Application
- Best Practices
➡️ Weiter zu: Angular Todo App - Komplettes Projekt
HTTP gemeistert! Zeit für ein echtes Projekt! 🚀
Gut gemacht! 🎉
Du hast "Angular HTTP Client & APIs - Backend-Kommunikation" abgeschlossen
Artikel bewerten
Bitte einloggen um zu bewerten
Das könnte dich auch interessieren
Angular Reactive Forms - Formulare professionell erstellen
Meistere Reactive Forms in Angular: Form Validation, Custom Validators, Dynamic Forms und Best Practices für robuste Formulare.
Angular Routing & Navigation - Multi-Page Apps erstellen
Lerne Angular Router kennen, erstelle Routes, navigiere zwischen Seiten, nutze Route Parameters und schütze Routes mit Guards.
Angular Services & Dependency Injection - Logik auslagern
Lerne Services in Angular zu erstellen, Dependency Injection zu verstehen und zentrale Geschäftslogik effizient zu organisieren.