Home > Software design >  Return the fetch response from another file
Return the fetch response from another file

Time:03-27

I am trying to call a function that calls fetch to an API from a React component in a separate file and am not finding the correct solution to get the correct response back.

When I debug, the result returns before the updateAccount function has completed and the final result is never returned to my update function.

Inside the fetch, the API returns the correct response whether it is successful or has validation errors and those results are correctly assigned to result.success and result.errors but the result doesn't get returned from the function so that the caller can make use of those values.

Inside of my React component:

import { updateAccount } from '../services/requests';
...
const update = (account: EditAccountModel) => {
  const result = updateAccount(account);
  if(result.errors.length > 0) {
    // will notify of errors
    console.log(result.errors); // is an empty array instead of validation errors
  } else {
    // will notify of success
    console.log(result.success); // is an empty string instead of success message
  }
}
...

My request file

export const updateAccount = (account: EditAccountModel | undefined): EditAccountResponseModel => {
  const result = new EditAccountResponseModel();
  fetch(baseUrl, {
    method: 'PUT',
    body: JSON.stringify(account),
    headers 
  })
  .then(response => {
    if (!response.ok) {
      return Promise.reject(response);
    }
    result.success = `${account?.name} was updated successfully!`
  })
  .catch(error => {
    if (typeof error.json === "function") {
      error.json().then(jsonError => {
        result.errors.push(jsonError);
      }).catch(genericError => {
        result.errors.push(genericError);
      });
    }
  });
  return result;
}

CodePudding user response:

The result reassignment happens inside then catch but it won’t be affective in the way you expected. The guaranteed way to return correct result is via a callback() passed to your updateAccount() if you could afford it:


export const updateAccount = (
  account: EditAccountModel | undefined,
  callback: Function
): EditAccountResponseModel => {

  const result = new EditAccountResponseModel();

  fetch(baseUrl, {
    method: 'PUT',
    body: JSON.stringify(account),
    headers 
  })
  .then(response => {
    if (!response.ok) {
      return Promise.reject(response);
    }

    result.success = `${account?.name} was updated successfully!`
    callback(result);
  })
  .catch(error => {
    if (typeof error.json === "function") {
      error.json().then(jsonError => {
        result.errors.push(jsonError);
        callback(result);
      }).catch(genericError => {
        result.errors.push(genericError);
        callback(result);
      });
    }
    

  });
}

And inside your React component:

const update = (account: EditAccountModel) => {
  const handleResult = (res) => {
    // your result callback code
    // ...
  };

  updateAccount(account, handleResult);
  // ...
}

Alternative way that keeps your current structure is to change your current updateAccount() to an async function, then return await fetch().

CodePudding user response:

You need to wait for the response . I'll let read more about how Promise work in JavaScript. I wouldn't code updateAccount the same way you did, especially where you use the variable result and update it inside the flow of the promise (you really don't need that). You're also using React so you can use the state to store and update the result of the update function. But let's fix your problem first:

export const updateAccount = async (account: EditAccountModel | undefined): EditAccountResponseModel => {
  const result = new EditAccountResponseModel();
  await fetch(baseUrl, {
    method: 'PUT',
    body: JSON.stringify(account),
    headers 
  })
  .then(response => {
    if (!response.ok) {
      return Promise.reject(response);
    }
    result.success = `${account?.name} was updated successfully!`
  })
  .catch(error => {
    if (typeof error.json === "function") {
      error.json().then(jsonError => {
        result.errors.push(jsonError);
      }).catch(genericError => {
        result.errors.push(genericError);
      });
    }
  });
  return result;
}

First make your function updateAccount async then await the result of the promise.

Now the same thing for the function update:

const update = async (account: EditAccountModel) => {
  const result = await updateAccount(account);
  if(result.errors.length > 0) {
    // will notify of errors
  } else {
    // will notify of success
  }
}
  • Related