mirror of https://github.com/ghostfolio/ghostfolio
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5.4 KiB
5.4 KiB
HTTP communication with HttpClient and httpResource
Use Angular's HTTP APIs for backend communication so requests participate in dependency injection, interceptors, transfer cache, and security features.
Setup
In Angular v21 and later, HttpClient is available for injection by default. Add provideHttpClient(...) only when an app needs to configure HTTP features for a specific injector:
import {provideHttpClient, withInterceptors} from '@angular/common/http';
export const appConfig = {
providers: [provideHttpClient(withInterceptors([authInterceptor]))],
};
HttpClientuses the fetch backend by default.- Use
withXhr()only when upload progress events are required. Do not usewithXhr()for server-side rendering. - Use
provideHttpClient(...)for feature configuration such as interceptors, XSRF options, XHR, or parent-request delegation. - Calling
provideHttpClient()with no features is not required for basic HTTP requests, but it configures the default HTTP feature set for that injector, including Angular's XSRF interceptor. - Prefer
provideHttpClient(...)overHttpClientModulefor feature configuration, especially with multiple injectors. - Use
withRequestsMadeViaParent()when a child injector should add interceptors while still delegating to the parent HTTP chain.
HttpClient
Encapsulate backend calls in injectable services, not components:
import {HttpClient} from '@angular/common/http';
import {Service, inject} from '@angular/core';
@Service()
export class UserService {
private readonly http = inject(HttpClient);
getUser(id: string) {
return this.http.get<User>(`/api/users/${id}`);
}
}
Important rules:
HttpClientrequests are coldObservables. No request is sent until theObservableis subscribed to. Multiple subscriptions send multiple backend requests.- Subscribe to mutation requests (
post,put,patch,delete) so they execute. - The generic type parameter is a type assertion only. Validate unknown backend data at runtime when the shape is not trusted.
- Use literal values for
responseTypeandobserve; if options are extracted, write values likeresponseType: 'text' as const. HttpHeadersandHttpParamsare immutable; use the returned instance from.set()or.append().- Fetch options such as
timeout,cache,priority,mode,redirect,credentials,keepalive,referrer,referrerPolicy, andintegrityare supported where the backend supports them.withCredentials: trueoverridescredentials. - Handle failures through
HttpErrorResponse. Network and timeout failures use status0; backend failures use the server status code. - Prefer the
asyncpipe ortoSignalfor component reads so subscriptions are cleaned up.
Interceptors
Prefer functional interceptors configured with withInterceptors.
import {
HttpHandlerFn,
HttpRequest,
provideHttpClient,
withInterceptors,
} from '@angular/common/http';
export function authInterceptor(req: HttpRequest<unknown>, next: HttpHandlerFn) {
return next(req.clone({setHeaders: {Authorization: 'Bearer token'}}));
}
export const appConfig = {
providers: [provideHttpClient(withInterceptors([authInterceptor]))],
};
- Interceptors run in the order listed.
- Request and response objects are mostly immutable; clone before changing them.
- Request and response bodies are not deeply immutable. Avoid in-place body mutation because retries can run the same interceptor again.
- Use
inject()inside functional interceptors for services. - Use
HttpContextTokenfor per-request metadata that interceptors need but the backend should not receive. - Use DI-based interceptors only for existing code, and enable them with
withInterceptorsFromDi().
Security
HttpClientstrips the XSSI prefix from JSON responses when present.provideHttpClient()configures XSRF protection by default for mutating relative and same-origin requests. It reads theXSRF-TOKENcookie and sends theX-XSRF-TOKENheader.- The backend must set the XSRF cookie and verify the header. Customize names with
withXsrfConfiguration(...); disable only deliberately withwithNoXsrfProtection().
httpResource
Use httpResource to create an asynchronous derivation that fetches data over HTTP and exposes the result as reactive signals.
import {httpResource} from '@angular/common/http';
import {input} from '@angular/core';
export class UserProfile {
readonly userId = input.required<string>();
readonly user = httpResource(() => `/api/users/${this.userId()}`);
}
httpResourceis eager. It sends a request when its reactive request computation runs, not when anObservableis subscribed.- When a dependency changes, it cancels the pending request and sends the next one.
- Return
undefinedfrom the request function to skip a backend request. - Prefer
httpResourcefor reads. UseHttpClientdirectly for mutations such asPOST,PUT,PATCH, andDELETE. - Guard
value()reads withhasValue(); readingvalue()while the resource is in an error state throws. - Use
httpResource.text,httpResource.blob, orhttpResource.arrayBufferfor non-JSON responses. - Use the
parseoption to validate or transform responses with a runtime schema. - Read
headers(),statusCode(), andprogress()when response metadata or download progress is needed. SetreportProgress: truefor progress events.