Why do most classes of the HttpClient API define immutable objects?
Asked Answered
S

1

4

The documentation for HttpClient states the following about immutability:

Interceptors exist to examine and mutate outgoing requests and incoming responses. However, it may be surprising to learn that the HttpRequest and HttpResponse classes are largely immutable.

This is for a reason: because the app may retry requests, the interceptor chain may process an individual request multiple times. If requests were mutable, a retried request would be different than the original request. Immutability ensures the interceptors see the same request for each try.

I find it hard to understand this explanation. Can someone please provide an explanation?

Simonides answered 21/12, 2017 at 17:48 Comment(2)
I was kinda waiting for somebody to add this resource in SO, as the question has appeared multiple times here and in the issue tracker of the angular repo on githubBootlick
@Jota.Toledo, yeah, this question bugged me for some time as well. I'm finishing a big article now that explains how interceptors work under the hood and figured out this question as part of my investigation.Simonides
S
11

This explanation is very difficult to understand without knowing the source code. It's explained in depth in the article Insider’s guide into interceptors and HttpClient mechanics in Angular.

When you call any method of http, like get, Angular creates a request. Then this request is used to start an observable sequence and when subscribed this request is passed through interceptors chain. This is done as part of sequence processing (very simplified code):

function get() {
    let req: HttpRequest<any> = new HttpRequest<any>();
    const events$ = of(req).pipe(concatMap((req: HttpRequest<any>) => {
        // running request through interceptors chain
        this.handler.handle(req);
    }));
    return $events;
}

Here is the comment from the sources:

Start with an Observable.of() the initial request, and run the handler (which includes all interceptors) inside a concatMap(). This way, the handler runs inside an Observable chain, which causes interceptors to be re-run on every subscription (this also makes retries re-run the handler, including interceptors).

So the $events stream is what is returned from http request methods and can be retried. The interceptors should always start with the original request. If the request is mutable and can be modified during the previous run of interceptors, this condition can't be met. So the request and all its constituent parts should be immutable.

Simonides answered 21/12, 2017 at 17:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.