Skip to main content

angular-http

Implement HTTP data fetching in Angular v20+ using resource(), httpResource(), and HttpClient. Use for API calls, data loading with signals, request/response handling, and interceptors. Triggers on data fetching, API integration, loading states, error handling, or converting Observable-based HTTP to signal-based patterns.

Quellinformationen

Repository
mediar-ai/skillhubz
Letzte Quellaktivität
1. März 2026 um 22:51
Erkannte Sprache von SKILL.md
Englisch
Sterne
7
Forks
4

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
angular-http
description
Implement HTTP data fetching in Angular v20+ using resource(), httpResource(), and HttpClient. Use for API calls, data loading with signals, request/response handling, and interceptors. Triggers on data fetching, API integration, loading states, error handling, or converting Observable-based HTTP to signal-based patterns.
# Angular HTTP & Data Fetching Fetch data in Angular using signal-based `resource()`, `httpResource()`, and the traditional `HttpClient`. ## httpResource() - Signal-Based HTTP `httpResource()` wraps HttpClient with signal-based state management: ```typescript import { Component, signal } from '@angular/core'; import { httpResource } from '@angular/common/http'; interface User { id: number; name: string; email: string; } @Component({ selector: 'app-user-profile', template: ` @if (userResource.isLoading()) { <p>Loading...</p> } @else if (userResource.error()) { <p>Error: {{ userResource.error()?.message }}</p> <button (click)="userResource.reload()">Retry</button> } @else if (userResource.hasValue()) { <h1>{{ userResource.value().name }}</h1> <p>{{ userResource.value().email }}</p> } `, }) export class UserProfile { userId = signal('123'); // Reactive HTTP resource - refetches when userId changes userResource = httpResource<User>(() => `/api/users/${this.userId()}`); } ``` ### httpResource Options ```typescript // Simple GET request userResource = httpResource<User>(() => `/api/users/${this.userId()}`); // With full request options userResource = httpResource<User>(() => ({ url: `/api/users/${this.userId()}`, method: 'GET', headers: { 'Authorization': `Bearer ${this.token()}` }, params: { include: 'profile' }, })); // With default value usersResource = httpResource<User[]>(() => '/api/users', { defaultValue: [], }); // Skip request when params undefined userResource = httpResource<User>(() => { const id = this.userId(); return id ? `/api/users/${id}` : undefined; }); ``` ### Resource State ```typescript // Status signals userResource.value() // Current value or undefined userResource.hasValue() // Boolean - has resolved value userResource.error() // Error or undefined userResource.isLoading() // Boolean - currently loading userResource.status() // 'idle' | 'loading' | 'reloading' | 'resolved' | 'error' | 'local' // Actions userResource.reload() // Manually trigger reload userResource.set(value) // Set local value userResource.update(fn) // Update local value ``` ## resource() - Generic Async Data For non-HTTP async operations or custom fetch logic: ```typescript import { resource, signal } from '@angular/core'; @Component({...}) export class Search { query = signal(''); searchResource = resource({ // Reactive params - triggers reload when changed params: () => ({ q: this.query() }), // Async loader function loader: async ({ params, abortSignal }) => { if (!params.q) return []; const response = await fetch(`/api/search?q=${params.q}`, { signal: abortSignal, }); return response.json() as Promise<SearchResult[]>; }, }); } ``` ### Resource with Default Value ```typescript todosResource = resource({ defaultValue: [] as Todo[], params: () => ({ filter: this.filter() }), loader: async ({ params }) => { const res = await fetch(`/api/todos?filter=${params.filter}`); return res.json(); }, }); // value() returns Todo[] (never undefined) ``` ### Conditional Loading ```typescript const userId = signal<string | null>(null); userResource = resource({ params: () => { const id = userId(); // Return undefined to skip loading return id ? { id } : undefined; }, loader: async ({ params }) => { return fetch(`/api/users/${params.id}`).then(r => r.json()); }, }); // Status is 'idle' when params returns undefined ``` ## HttpClient - Traditional Approach For complex scenarios or when you need Observable operators: ```typescript import { Component, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { toSignal } from '@angular/core/rxjs-interop'; @Component({...}) export class Users { private http = inject(HttpClient); // Convert Observable to Signal users = toSignal( this.http.get<User[]>('/api/users'), { initialValue: [] } ); // Or use Observable directly users$ = this.http.get<User[]>('/api/users'); } ``` ### HTTP Methods ```typescript private http = inject(HttpClient); // GET getUser(id: string) { return this.http.get<User>(`/api/users/${id}`); } // POST createUser(user: CreateUserDto) { return this.http.post<User>('/api/users', user); } // PUT updateUser(id: string, user: UpdateUserDto) { return this.http.put<User>(`/api/users/${id}`, user); } // PATCH patchUser(id: string, changes: Partial<User>) { return this.http.patch<User>(`/api/users/${id}`, changes); } // DELETE deleteUser(id: string) { return this.http.delete<void>(`/api/users/${id}`); } ``` ### Request Options ```typescript this.http.get<User[]>('/api/users', { headers: { 'Authorization': 'Bearer token', 'Content-Type': 'application/json', }, params: { page: '1', limit: '10', sort: 'name', }, observe: 'response', // Get full HttpResponse responseType: 'json', }); ``` ## Interceptors ### Functional Interceptor (Recommended) ```typescript // auth.interceptor.ts import { HttpInterceptorFn } from '@angular/common/http'; import { inject } from '@angular/core'; export const authInterceptor: HttpInterceptorFn = (req, next) => { const authService = inject(Auth); const token = authService.token(); if (token) { req = req.clone({ setHeaders: { Authorization: `Bearer ${token}` }, }); } return next(req); }; // error.interceptor.ts export const errorInterceptor: HttpInterceptorFn = (req, next) => { return next(req).pipe( catchError((error: HttpErrorResponse) => { if (error.status === 401) { inject(Router).navigate(['/login']); } return throwError(() => error); }) ); }; // logging.interceptor.ts export const loggingInterceptor: HttpInterceptorFn = (req, next) => { const started = Date.now(); return next(req).pipe( tap({ next: () => console.log(`${req.method} ${req.url} - ${Date.now() - started}ms`), error: (err) => console.error(`${req.method} ${req.url} failed`, err), }) ); }; ``` ### Register Interceptors ```typescript // app.config.ts import { provideHttpClient, withInterceptors } from '@angular/common/http'; export const appConfig: ApplicationConfig = { providers: [ provideHttpClient( withInterceptors([ authInterceptor, errorInterceptor, loggingInterceptor, ]) ), ], }; ``` ## Error Handling ### With httpResource ```typescript @Component({ template: ` @if (userResource.error(); as error) { <div class="error"> <p>{{ getErrorMessage(error) }}</p> <button (click)="userResource.reload()">Retry</button> </div> } `, }) export class UserCmpt { userResource = httpResource<User>(() => `/api/users/${this.userId()}`); getErrorMessage(error: unknown): string { if (error instanceof HttpErrorResponse) { return error.error?.message || `Error ${error.status}: ${error.statusText}`; } return 'An unexpected error occurred'; } } ``` ### With HttpClient ```typescript import { catchError, retry } from 'rxjs'; getUser(id: string) { return this.http.get<User>(`/api/users/${id}`).pipe( retry(2), // Retry up to 2 times catchError((error: HttpErrorResponse) => { console.error('Error fetching user:', error); return throwError(() => new Error('Failed to load user')); }) ); } ``` ## Loading States Pattern ```typescript @Component({ template: ` @switch (dataResource.status()) { @case ('idle') { <p>Enter a search term</p> } @case ('loading') { <app-spinner /> } @case ('reloading') { <app-data [data]="dataResource.value()" /> <app-spinner size="small" /> } @case ('resolved') { <app-data [data]="dataResource.value()" /> } @case ('error') { <app-error [error]="dataResource.error()" (retry)="dataResource.reload()" /> } } `, }) export class Data { query = signal(''); dataResource = httpResource<Data[]>(() => this.query() ? `/api/search?q=${this.query()}` : undefined ); } ``` For advanced patterns, see [references/http-patterns.md](references/http-patterns.md).
Auf GitHub ansehen