@secondcloset/api-utils

api utils is second closet's wrapper service of axios library

Usage no npm install needed!

<script type="module">
  import secondclosetApiUtils from 'https://cdn.skypack.dev/@secondcloset/api-utils';
</script>

README

api-utils v2

api utils is second closet's wrapper service of axios library

Setup

To use api functionality we first need to setup our api util locally. Create an api.ts/js file under lib/utils folder and add the following.

import { setupAPI, getCancellableRequest } from "@secondcloset/api-utils";
import { reportAPI } from "./sentry";
import Cookie from "./cookie";

const { getAPIFromDomain } = setupAPI({
  baseURL: String(process.env.REACT_APP_API),
  getToken: Cookie.getUserToken,
  interceptors: {
    response: {
      onFulfilled: (response) => {
        // do something when a request is fulfilled
        return response;
      },
      onRejected: (error) => {
        // do something when a request fails
        reportAPI(error); // like reporting to sentry
        return error;
      },
    },
  },
});

export { getAPIFromDomain, getCancellableRequest };
export * from "@secondcloset/api-utils/dist/types"; // re-export types optional for ts

Usage

You can now import getAPIFromDomain and getCancellableRequest from your local api util.

Basics

getAPIFromDomain is a function that accepts a domain and returns an axios instance

export const fetchOrderDetails = async (
  key: string,
  orderID: string
): Promise<Fulfillment.Order> => {
  const api = getAPIFromDomain("fulfillment");
  const url = `/orders/${orderID}`;
  const { data: order } = await api.get(url);
  return order;
};

*Note: main difference from v1 is instead of const api = new API("fulfillment"); it's now const api = getAPIFromDomain("fulfillment");

Cancellable Request

getCancellableRequest is a wrapper function that accepts an async function and returns that with a cancel method that react-query uses for query cancellation or you can manually invoke

React-Query

/* your api service file */
export const fetchOrderDetails = getCancellableRequest<Fulfillment.Order>(
  async (key: string, orderID: string, config: APIRequestConfig) => {
    const api = getAPIFromDomain("fulfillment");
    const url = `/orders/${orderID}`;
    const response = await api.get(url, config);
    return response.data;
  }
);

/* your component */
const orderDetails = useQuery(["order", orderID], fetchOrderDetails);

Legacy/Manual Cancellation

/* your api service file */
export const useOrderDetails = () => {
  const [data, setData] = useState<Fulfillment.Order>();
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState("");

  const fetchOrderDetails = (orderID: string) => {
    const url = `/orders/${orderID}`;
    const api = getAPIFromDomain("fulfillment");

    setError("");
    setLoading(true);

    return getCancellableRequest((config) => {
      return api
        .get(url, config)
        .then((res) => {
          const order = res.data;
          setData(order);
          return order;
        })
        .catch((error) => {
          setError(error);
          return error;
        })
        .finally(() => setLoading(false));
    })();
  };

  const orderDetails = { data, isLoading: loading, error };

  return { orderDetails, fetchOrderDetails };
};

/* your component */
const { orderDetails, fetchOrderDetails } = useOrderDetails();

// this example is cancelling request when component unmounts
useEffect(() => {
  const promise = fetchOrderDetails(orderID);
  return () => {
    //@ts-ignore
    promise.cancel();
  };
}, [orderID]);

Custom config/headers

Because api is now an instance of axios we can now easily cusomize request config

const api = getAPIFromDomain("fulfillment");
const url = `/files/${fileID}`;
const config = {
  headers: {
    "Content-Type": "multipart/form-data",
  },
};
const response = await api.get(url, config);