Search code examples
javascriptangulartypescriptangular-httpclient

Angular HttpClient, setting map type dynamically


I have a method on an service to handle all backend requests. Instead of writing a whole bunch of different calls using the HttpClient, I thought I might write one single function that could connect to my backend and pass it arguments to handle different types of data.

Consider this function

public postRequest(token: string, url: string, body: any, headers: Object = {}) : Observable<any> {
//create new header object
const httpOptions = {
  headers: new HttpHeaders()
    .set('Authorization', token)
};
//add the headers if any
for(let index in headers){
  httpOptions.headers.set(index, headers[index]);
}
//connect to the backend and return the repsonse
return this.http.post( this.config.BASE_SERVER_URL + url, body , httpOptions)
  .pipe(
    map((res) => {
      return res;
    }),
    catchError(this.handleError)
  );
}

It works well except I wanted to be able to set the response type dynamically. Thus I could set the method to use one of my model types.

Here's what I'm trying to accomplish. Hopefully this makes sense.

map(res: "Attendee") => {}
//or
map(res: typeof(typeInput)) => {}

Is it possible to pas a "dynamic" type to the http map method so I can map the different responses to a model of my choice?


Solution

  • I can achieve this by using generic methods.

    you can use this approach.

    my-own.service.ts

    userAuthentication<T>(userName: string, password: string): Observable<T> {
        const url = `http://my-own.url`;
        const targetData = {
          'emailId': userName,
          'password': password
        };
        return this.http.post<CommonResponse<T>>(url, targetData, httpOptions).pipe(
          retry(3),
          map((data: CommonResponse<T>) => {
            if (data.status) {
              if (!data.result[0]) {
                this.showMessage('You are not authorized for login');
                return null;
              }
              return data.result[0] as T;
            }
            this.showMessage(data.message);
            return null;
          }),
          tap((userProfile: T) => {
            console.log('UserLogin ');
          }),
          catchError(this.handleError<T>('unable to logged in')));
      }
    

    CommonResponse model

    export class CommonResponse<T> {
      autherizationExpires: string;
      autherizationKey: string;
      message: string;
      result: T | T[];
      status: boolean;
    }
    

    So, when you call this method like myOwnService.userAuthentication < LoginModel >(...params).subscribe(/ * your codes * /); It will inherited to the map as well.

    let me know if I am not get your question.