Request Handler - Axios
When we want to create our lightweight SDK without using any third-party libraries, we might want to create a request handler to handle the api requests in a controllable and predictable way.
In this article, we will refactor ms365-graph-api-auth npm package by creating a request handler.
tip
Checkout this PR to see the detailed refactoring process.
There are two key benefits of using a request handler:
- It will be easier to follow the convention if someone wants to contribute to the project.
 - It is easier to handle the error.
 - It is more type-safe and predictable since we can define the type of the response data.
 
Create a request handler helper function
This helper function can take a request function and return a function that can handle the request and return a response with the corresponding type.
packages/ms365-graph-api-auth/utils/requestHandler.ts
import { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios";
type BaseRequest<U, T = AxiosRequestConfig> = (
  params?: T
) => Promise<AxiosResponse<U>>;
type BaseResponse<U, E = AxiosError> = Promise<
  SuccessResponse<U> | ErrorResponse<E>
>;
type SuccessResponse<U> = {
  success: true;
  data: U;
};
type ErrorResponse<E> = {
  success: false;
  error: E;
};
type RequestHandler = <U, T = AxiosRequestConfig, E = AxiosError>(
  request: BaseRequest<U, T>
) => (params?: T) => BaseResponse<U, E>;
export const getRequestHandler: RequestHandler =
  <U, T = AxiosRequestConfig, E = AxiosRequestConfig>(
    request: BaseRequest<U, T>
  ) =>
  async (params?: T): BaseResponse<U, E> => {
    try {
      const response = await request(params);
      return {
        success: true,
        data: response.data,
      };
    } catch (error) {
      return {
        success: false,
        error: error as E,
      };
    }
  };
Use the request handler helper function
packages/ms365-graph-api-auth/src/fetch.ts
  // ...
  aasync getSites(siteName?: string): Promise<ISites> {
    const baseApiUrl = "https://graph.microsoft.com/";
    const getSharePointSites = getRequestHandler<ISites>((params) =>
      axios.get(baseApiUrl + "v1.0/sites", params)
    );
    const params: AxiosRequestConfig = {
      headers: {
        Authorization: `Bearer ${this.accessToken}`,
      },
    };
    const res = await getSharePointSites(params);
    //                 ^^^^^ getSharePointSites: (params?: AxiosRequestConfig<any> | undefined) => BaseResponse<ISites, AxiosError<unknown, any>>
    if (!res.success) throw Error("ERROR: getSites - " + res.error.message);
    let sites = res.data;
    if (siteName)
      sites = {
        ...sites,
        value: sites.value.filter((site) => site.name === siteName),
      };
    return sites;
  }
  // ...