Today I learned how to create a URL with query string parameters with HttpParams class in Angular.
I wanted to construct a URL with some query string parameters like:
https://api.something.com?id=someid&name=johndoe
I tried:
import { HttpParams } from '@angular/common/http';
...
const baseURL = 'https://api.something.com';
const params = new HttpParams();
params.set('id', 'someid');
params.set('name', 'johndoe');
const fullURL = `${baseURL}?${params.toString()}`;
console.log({ fullURL });
The URL didn’t contain any parameters.
But when I chained .set()
with new HttpParams()
, it works.
const params = new HttpParams()
.set('id', 'someid');
.set('name', 'johndoe');
const fullURL = `${baseURL}?${params.toString()}`;
console.log({ fullURL });
My gotcha moment was then I found out that HttpParams
class in Angular is immutable.
This means params.set()
method doesn’t modify an existing params
object —
it returns a new HttpParams
instance.
The same goes to append()
and delete()
methods.
append(param: string, value: string): HttpParams;
set(param: string, value: string): HttpParams;
delete(param: string, value?: string): HttpParams;
So if I want the params
object with a new parameter in it,
I have to put it in a variable, or reassign to itself.
let params = new HttpParams();
params = params.set('id', 'someid');
params = params.set('name', 'johndoe');
It is opposed to the native URLSearchParams
object,
or the deprecated URLSearchParams
class in @angular/http
module,
which are both mutable.
Why Immutable?
I looked up on Google search to find why Angular team decided to make HttpParams class immutable.
I found this post from Sparkles Blog
which leads to the official document about immutability of HttpRequest
and HttpResponse
classes.
[…] They are immutable for a good reason: the app may retry a request several times before it succeeds, which means that the interceptor chain may re-process the same request multiple times.
If an interceptor could modify the original request object, the re-tried operation would start from the modified request rather than the original. Immutability ensures that interceptors see the same request for each try.
Source - Http Guide, Angular.io
Then it is kind of make sense too if the HttpParams
class should be also immutable.
It just feels a bit strange though when a .set()
method doesn’t actually set something to the caller object.
However, we still cannot always assume that everything is immutable,
as mentioned in another API document page:
Instances of HttpRequest class should not be assumed to be immutable.
Updated: This is no longer true. Now in the docs they stated instances of HttpParams should be assumed to be immutable.
Hmm.. 🤔