简体   繁体   中英

Angular Best Practice on creating Generic method

I am designing Api endpoints in Angular using HttpClient. This is a single service class which will handle all the Rest calls, it will be called from other service classes(which are currently making Rest calls).

What is the best practice to make a generic Rest method.

getApi(url: string, options?: object): Observable<any> {
    return this.http.get<any>(url, options).pipe(
      catchError((error: HttpErrorResponse) => {
        return throwError(error);
    })
  )
}

Or

getApi<T>(url: string, options?: object): Observable<T> {
    return this.http.get<T>(url, options).pipe(
      catchError((error: HttpErrorResponse) => {
        return throwError(error);
    })
  )
}

Will any of the above be able to handle: HttpEvent, HttpResponse or other such response?

Should I make multiple methods to handle?

Please note, the answer is very opinion-based.

Before I will show my solution, I want to share the idea beneath it. So, when I am working with TS I expect to have as strict types as possible . So, using any , object , or something like this is distracting in this context. I also want to avoid any extra typecast because it will lead to an error somewhere.

Luckily, TS is quite smart to help me with this goal, because it can identify types depending on the usage.

Based on this we can build something like this:

A very generic class that can everything we need (it can be extended with passing params to fetch, logging, counter whatever you need)

class HttpService {
    get<TData, TResult>(url: string, data?: TData): Promise<TResult> {
        return fetch(url, data)
            .then(x => x.json())
            .catch((err) => console.log(err));
    }
}

But this class should not be used directly. I would advise creating a more strict and specialized service that will isolated fetch logic and provide strict types instead of generics.

type User = {
    name: string;
}

class MyDataService {

    constructor(private readonly _transportService: HttpService) { }
    fetchUserInfo(userId: number): Promise<User> {
        return this._transportService.get('/some/url', userId);
    }
}

Now, I can use MyDataService without any typecasting and type guessing. One more benefit is that this service is very easily testable because you can substitute the transport module however you want.

Hopefully, my answer helped you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM