httpParams remove undefined params

Viewed 2456

I need to send params in my URL to get filtered data from the server.

I set params like this

const queryParams = new HttpParams(
      {
        fromObject: {
          page: this.paginator.pageIndex.toString(),
          pageSize: this.paginator.pageSize.toString(),
          search: this.searchKey,
          sortBy: this.selectedFilterByStatusValue,
          sortByType: this.selectedFilterSortByValue
        }
      });

And in my service

 getData(params: HttpParams) {
    return this.apiService.get<IResponseList<IData>>(`${this.url}/list`, params);
  }

Problem is, when some filter is not selected, because I don't need them, and it is set like undefined, but this is not correct... I need to remove undefined params.

Here is console.log for queryParams

cloneFrom: null
encoder: HttpUrlEncodingCodec {}
map: Map(5)
  [[Entries]]
  0: {"page" => Array(1)}
  1: {"pageSize" => Array(1)}
      key: "pageSize"
      value: ["3"]
  2: {"search" => Array(1)}
  3: {"sortBy" => Array(1)}
  4: {"sortByType" => Array(1)}

I try to use .set("page", this.paginator.pageIndex) and also .append(...) but I always get same structure

Also, I try directly in service fix this, but this not working, I again get undefined

this.httpClient.get(`${this.url}/list`, { 
  params: Object.entries(queryParameterObject).reduce((queryParams, [key, value]) => queryParams.set(key, value), new HttpParams());
});

Thnx

3 Answers

Here is a one-liner that I think might work for you :


const newQueryParameterObject = Object.entries(queryParameterObject).reduce(
    (acc, [key, value]) => ({ ...acc, ...((value != null) & { [key]: value }) }),
    {}
);

this.httpClient.get(`${this.url}/list`, { params: new HttpParams({fromObject:newQueryParameterObject}) });

It will clean the variables with null or undefined values.

try to skip them in the reduce.

this.httpClient.get(`${this.url}/list`, { 
  params: queryParameterObject ? queryParameterObject.keys().reduce((queryParams, key) => {
  // getting value from map
  let value: any = queryParameterObject.get(key);

  // extracting value if it's an array
  value = Array.isArray(value) ? value[0] : value;

  // adding only defined values to the params
  if (value !== undefined && value !== null) {
    queryParams[key] = value;
  }

  return queryParams;
}, {}) : {};
});

Automatically stripping out undefined params using an interceptor or some kind of catch-all could lead to hidden bugs. For example, if you didn't handle that a variable could be undefined, it will silently remove the property from your request altogether and the bug/error will go unhandled. You'd have to inspect the request body when debugging to figure out what happened.

This begs the question, what SHOULD we do if a param value is undefined? According to most REST APIs, query params are optional, but to your front end the answer may be that you require their use for this call.

  1. If it's undefined but required by your front-end, maybe we should actually treat that like an error and not make the request at all. In that case we'd just type check the variable and do some conditional logic.
if (myparam === undefined) {
    // my app requires the use of this query param!
    alert('Something is wrong!');
    // handle the issue
    return;
}
  1. If it's undefined but optional, then the following spread solution makes it really obvious and is a good solution.

This solution can prevent undefined params being passed in, and make it obvious at the call site that undefined values will not be included in the request:

const myParamA = undefined;
const myParamB = 'foo';
this.http.get(someUrl, {
    params: {
        ...(myParamA === undefined ? {} : { myParamA }),
        ...(myParamB === undefined ? {} : { myParamB }),
    },
})

We make use of the spread operator to either spread in our object with our param, or we spread in an empty object (i.e. don't add any properties). In the above example params will be { myParamB: 'foo' }.

Related