Creating a custom AJAX POST wrapper in JavaScript

I’m working on an AngularJS project and I’ve made a custom ajaxService that wraps around $http.post(). My goal is to have a service that shows an alert when there’s an error, but I want this alert to appear even if someone overwrites the .error() function.

At first, I just returned the $http.post() promise, but that removed my error handling when .error() was overwritten. Here’s what I tried:

function sendRequest(endpoint, payload) {
  var result = {
    onSuccess: function(data) {},
    onError: function(error) {}
  };

  fetchData(endpoint, payload)
    .then(function(response) {
      if (typeof response === 'string' && response.includes('error-debug')) {
        showErrorPopup(response);
        result.onError(response);
      } else {
        result.onSuccess(response);
      }
    })
    .catch(function(error) {
      showErrorPopup(error);
      result.onError(error);
    });

  return result;
}

But when I call sendRequest(), it returns undefined instead of the result object. What’s causing this and how can I fix it?

I’ve encountered a similar issue in my AngularJS projects. The problem arises because your function is asynchronous, yet you return the result object immediately. When the promise resolves later, the result object has already been returned as undefined, so your error handling doesn’t work as intended.

A solution is to wrap your asynchronous code in a new Promise that resolves with your custom result object. In this modified approach, you ensure that the result is provided only after handling both success and error cases. This way, your error alerts always trigger, even if someone overwrites the error callback.

Here’s an example:

function sendRequest(endpoint, payload) {
  return new Promise(function(resolve) {
    var result = {
      onSuccess: function(data) {},
      onError: function(error) {}
    };

    fetchData(endpoint, payload)
      .then(function(response) {
        if (typeof response === 'string' && response.includes('error-debug')) {
          showErrorPopup(response);
          result.onError(response);
        } else {
          result.onSuccess(response);
        }
        resolve(result);
      })
      .catch(function(error) {
        showErrorPopup(error);
        result.onError(error);
        resolve(result);
      });
  });
}

This approach preserves your error handling while still allowing consumers of the API to provide their own callbacks.

I’ve dealt with similar challenges in my projects. One approach that’s worked well for me is using a deferred object. It gives you more control over when and how you resolve or reject the promise.

Here’s a rough idea of how you could implement it:

function sendRequest(endpoint, payload) {
  var deferred = $q.defer();
  var result = {
    onSuccess: function(data) {},
    onError: function(error) {}
  };

  $http.post(endpoint, payload)
    .then(function(response) {
      if (typeof response.data === 'string' && response.data.includes('error-debug')) {
        showErrorPopup(response.data);
        result.onError(response.data);
      } else {
        result.onSuccess(response.data);
      }
      deferred.resolve(result);
    })
    .catch(function(error) {
      showErrorPopup(error);
      result.onError(error);
      deferred.resolve(result);
    });

  return deferred.promise;
}

This way, you maintain control over when the promise resolves, ensuring your error handling always runs. It’s been pretty reliable in my experience.

hey jackhero, i think i get ur problem. have u tried using a promise chain? somethin like this:

return $http.post(endpoint, payload)
  .then(handleResponse)
  .catch(handleError)
  .finally(() => result);

this way, ur error handling stays intact even if someone overwrites .error(). just define handleResponse and handleError funcs to do ur stuff.