Having trouble creating a wrapper function for api calls

Viewed 60

So essentially I have a pattern I will like to use throughout my api calls. It's essentially a try catch finally block where I dispatch a series of actions. Instead of copying and pasting this pattern everywhere, I'd like to create a wrapper function where all I pass in are the necessary parameters, api function, and dispatch actions.

My try call block function looks like this:

export function getTokenAPI(username, password) {
  return async function action(dispatch) {
    try {

      dispatch(loadingActions.loadingInProgress(true));


      const { data } = await API.authGetToken(username, password);
      const { success } = data;

      console.log('get token api data', data);
      if (success) {


        dispatch(setData(data));

        dispatch(setTokenSuccess());
      } else if (!success) {
        const { errorMessage } = data;
        throw Error(errorMessage || 'You broke it, not my fault');
      }
    } catch (e) {
      dispatch(errorActions.addError(e.message));
      dispatch(errorActions.removeError());
    } finally {
      dispatch(loadingActions.loadingInProgress(false));
    }
  };
}

So the wrapper I tried to create looks like this:

function wrapper(apiFunction, dispatchAction) {
  return async function action(dispatch) {
    try {
      dispatch(loadingActions.loadingInProgress(true));
      const { data } = await apiFunction(arg1, arg2);
      const { success } = data;
      if (success) {
        dispatch(dispatchAction(data));
      } else if (!success) {
        const { errorMessage } = data;
        throw Error(errorMessage || 'meh');
      }
    } catch (e) {
      dispatch(errorActions.addError(e.message));
      dispatch(errorActions.removeError());
    } finally {
      dispatch(loadingActions.loadingInProgress(false));
    }
  };
}

With that I can eventually just run

wrapper(apiFunction(username, password), setData)

but I'm getting a TypeError Cannot read property type of undefined. I'm wondering if I'm going about this the right way at all.

Any suggestions or recommendations?

2 Answers

wrapper is a high order function which expects two arguments apiFunction and dispatchAction and return an action creator which expects an action and have to be wrapped in a dispatch instance. So you should use wrapper like this

const Component = () =>{
    const dispatch = useDispatch()

    const onSubmit = () =>{
        dispatch(wrapper(apiFunction, dispatchAction)(action))
    }
}

wrapper(apiFunction, dispatchAction) evaluates to another function which expects an argument action and need to be explicitly executed. Is the equivalent of

const onSubmit = () =>{
    const actionCreator = wrapper(apiFunction, dispatchAction)
    dispatch(actionCreator(action))
}

So I fixed this by editing my wrapper a little bit more and by using Dupocas' answer as inspiration (needed to use dispatch).

Here's my wrapper and here's how I'm using it:

apiWrapper

import { loadingActions } from '_ducks/loading';
import { errorActions } from '_ducks/error';
import { Platform } from 'react-native';

const os = Platform === 'ios' ? 'iPhone' : 'Android';

const { loadingInProgress } = loadingActions;
const { addError, removeError } = errorActions;

export default function apiWrapper(
  apiFunction,
  dispatchActionData,
  dispatchActionStatus,
) {
  return async function action(dispatch) {
    try {
      dispatch(loadingInProgress(true));
      const { data } = await apiFunction;
      const { success } = data;
      console.log('D A T A', data);

      if (success) {
        dispatchActionData && dispatch(dispatchActionData(data));
        dispatchActionStatus && dispatch(dispatchActionStatus());
      } else if (!success) {
        const { errorMessage } = data;
        throw Error(
          errorMessage || `Sounds like a problem with your ${os} device`,
        );
      }
    } catch (e) {
      dispatch(addError(e.message));
      dispatch(removeError());
    } finally {
      dispatch(loadingInProgress(false));
    }
  };
}


apiWrapper use

export function submitLogIn(username, password) {
  return function action(dispatch) {
    dispatch(
      apiWrapper(
        API.getSTUFF(username, password),
        setUserData,
        setTokenSuccess,
      ),
    );
  };
}
Related