1

I am creating a SOAP request interceptor for AngularJS

It looks something like this:

angular.module('myApp')

.factory('SoapInterceptor', ['$q', function ($q) {


    var soapRequest = function (url, SOAPAction, requestEnvelope, callback) {
        $.soap({
            url: url,
            appendMethodToURL: false,
            SOAPAction: SOAPAction,
            enableLogging: false,
            data: requestEnvelope,
            success: function (SOAPResponse) { callback(SOAPResponse.toJSON()); },
            error: function (SOAPResponse) { throw new Error(SOAPResponse); }
        });
    }

    return {
        'request': function (config) {
            if (config.data && config.data.isSoap) {
                var deferred = $q.defer();
                soapRequest(config.url, config.data.soapaction, config.data.requestEnvelope, function (data) {
                    angular.extend(data, config);
                    deferred.resolve(data);
                });
                return deferred.promise;
            }
            return config;
        },
        'response': function (response) {
            // I somehow want this returned response to be my soap response
            // which i have got in request but of course it's no use there
            return response;
        }
    }
}]);

So I can consume it inside a datastore's method like this:

var deferred = $q.defer();

$http.post("http://myapi.com/service.asmx",
    {
        isSoap: true,
        requestEnvelope: reqXml,
        soapaction: "http://myapi.com/CampaignsGetList"
    })
    .success(function (data) {
        deferred.resolve(data);
    });

return deferred.promise;

When isSoap is true the request correctly passed it to my soapRequest but how can I pass the response I get back to be returned by the response function so my consumer can happily use the promise?

Any help is appreciated.

makeitmorehuman
  • 11,287
  • 3
  • 52
  • 76
  • Are you trying to handle the $http call yourself by using interceptors? Could you please have a look at my answer and let me know if there is something here that I'm missing? Thanks! – Josep Oct 22 '14 at 22:33

1 Answers1

1

If I understood this correctly what you are trying to do is to override the behaviour of the $http service when the data of the request content has the flag isSoap set to true. Looking at your code it seems that you actually want to handle the $http call yourself by using interceptors.

The problem is that interceptors are not meant to be used like that, what interceptors are supposed to do is handle things before and/or after the http request happens, but they are not supposed to handle the http request themselves.

However, I think that what you want is something like this:

Define your own "HttpSoap Service", like this:

app.service('HttpSoap', ['$q', function ($q) {        
    return function (url, SOAPAction, requestEnvelope) {
            var deferred = $q.defer();
            $.soap({
                url: url,
                appendMethodToURL: false,
                SOAPAction: SOAPAction,
                enableLogging: false,
                data: requestEnvelope,
                success: function (SOAPResponse) { deferred.resolve(SOAPResponse.toJSON()); },
                error: function (SOAPResponse) { deferred.reject(SOAPResponse) }
            });
            return deferred.promise;
        }
}]);

And use it like this:

app.controller('myController', function ($scope, HttpSoap) {
    // other code here where I assume that you will define  
    // the reqXml variable
    HttpSoap("http://proxy-send.concep.com/service.asmx", "http://new.cl.truelogic.com.au/CampaignsGetList", reqXml)
        .then(function (jsonData) {
            //things went well
        }, function (errorResponse) {
            //something bad happened
        });
});

A couple other things that I would like to point out:

  1. What you are doing in the second code snipped of your question is a "deferred anti-pattern" which is a very common bad practice that tends to happen among people who are starting to get familiar with promises. I used to fall for that all the time when I got started with Angular.

  2. Notice that I got rid of the callback parameter that you had inside the function of your factory, since it's a bad idea to use callbacks in Angular, it's much better to use a $q promise instead.

Community
  • 1
  • 1
Josep
  • 12,926
  • 2
  • 42
  • 45
  • Hi Josep, Thank you for taking the time. Your proposed answer is how my project is working right now. But I thought it would be much better if such handling of http call be abstracted away behind $http itself. and my next step after that would be to work a little more on datatype handling to remove the isSoap flag so in the end I can just give a soap envelope and an action to $http and it would know how to handle it. Plus I can ship that to github and such solution doesn't exist and would be nice if people can download it. – makeitmorehuman Oct 23 '14 at 07:40
  • Then again I guess I could package this up as a service inside a module and people can include that in their project – makeitmorehuman Oct 23 '14 at 08:21