Giter VIP home page Giter VIP logo

strong-soap's Introduction

strong-soap

CI Build Status Coverage Status

This module provides a Node.js SOAP client for invoking web services and a mock-up SOAP server capability to create and test your web service. This module is based on node-soap module.

Overview

Features:

  • Full SOAP Client capability and mock-up SOAP server capability
  • Handles both RPC and Document styles
  • Handles both SOAP 1.1 and SOAP 1.2 Fault
  • APIs to parse XML into JSON and JSON into XML
  • API to describe WSDL document
  • Support for both synchronous and asynchronous method handlers
  • WS-Security (currently only UsernameToken and PasswordText encoding is supported)

Install

Node.js version 10, 12, and 14 are officially supported. We dropped version 8 support in 3.0.0.

Install with npm:

npm install strong-soap

Client

Start with the WSDL for the web service you want to invoke. For example, the stock quote service http://www.webservicex.net/stockquote.asmx and the WSDL is http://www.webservicex.net/stockquote.asmx?WSDL

Create a new SOAP client from WSDL URL using soap.createClient(url[, options], callback). Also supports a local file system path. An instance of Client is passed to the soap.createClient callback. It is used to execute methods on the soap service.

"use strict";

var soap = require('strong-soap').soap;
// wsdl of the web service this client is going to invoke. For local wsdl you can use, url = './wsdls/stockquote.wsdl'
var url = 'http://www.webservicex.net/stockquote.asmx?WSDL';

var requestArgs = {
  symbol: 'IBM'
};

var options = {};
soap.createClient(url, options, function(err, client) {
  var method = client['StockQuote']['StockQuoteSoap']['GetQuote'];
  method(requestArgs, function(err, result, envelope, soapHeader) {
    //response envelope
    console.log('Response Envelope: \n' + envelope);
    //'result' is the response body
    console.log('Result: \n' + JSON.stringify(result));
  });
});

As well as creating a client via a url, an existing WSDL object can be passed in via options.WSDL_CACHE.

var soap = require('strong-soap').soap;
var WSDL = soap.WSDL;

var url = 'http://www.webservicex.net/stockquote.asmx?WSDL';

// Pass in WSDL options if any

var options = {};
WSDL.open(url,options,
  function(err, wsdl) {
    // You should be able to get to any information of this WSDL from this object. Traverse
    // the WSDL tree to get  bindings, operations, services, portTypes, messages,
    // parts, and XSD elements/Attributes.

    // Set the wsdl object in the cache. The key (e.g. 'stockquotewsdl')
    // can be anything, but needs to match the parameter passed into soap.createClient()
    var clientOptions = {
      WSDL_CACHE : {
        stockquotewsdl: wsdl
      }
    };
    soap.createClient('stockquotewsdl', clientOptions, function(err, client) {
      var method = client['StockQuote']['StockQuoteSoap']['GetQuote'];
      method(requestArgs, function(err, result, envelope, soapHeader) {

      //response envelope
      console.log('Response Envelope: \n' + envelope);
      //'result' is the response body
      console.log('Result: \n' + JSON.stringify(result));
    });
  });
});

The Request envelope created by above service invocation:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header/>
  <soap:Body>
    <ns1:GetQuote xmlns:ns1="http://www.webserviceX.NET/">
      <ns1:symbol>IBM</ns1:symbol>
    </ns1:GetQuote>
  </soap:Body>
</soap:Envelope>

This WSDL operation is defined as document/literal-wrapped style. Hence the request in soap is wrapped in operation name. Refer to test cases server-client-document-test and server-client-rpc-test to understand document and rpc styles and their Request, Response and Fault samples.

The options argument allows you to customize the client with the following properties:

  • endpoint: to override the SOAP service's host specified in the .wsdl file.
  • request: to override the request module.
  • httpClient: to provide your own http client that implements request(rurl, data, callback, exheaders, exoptions).
  • envelopeKey: to set specific key instead of
    <soap:Body></soap:Body>
  • wsdl_options: custom options for the request module on WSDL requests.
  • wsdl_headers: custom HTTP headers to be sent on WSDL requests.

Note: for versions of node >0.10.X, you may need to specify {connection: 'keep-alive'} in SOAP headers to avoid truncation of longer chunked responses.

Extra headers (optional)

User can define extra HTTP headers to be sent on the request.

var clientOptions = {};
soap.createClient(url, clientOptions, function(err, client) {
  var customRequestHeader = {customheader1: 'test1'};
  // Custom request header
  client.GetQuote(requestArgs, function(err, result, envelope) {
    // Result in SOAP envelope body which is the wrapper element.
    // In this case, result object corresponds to GetCityForecastByZIPResponse.
    console.log(JSON.stringify(result));
  }, null, customRequestHeader);
});

Client.describe()

Describes services, ports and methods as a JavaScript object.

// Describes the entire WSDL in a JSON tree object form.
var description = client.describe();
// Inspect GetQuote operation. You can inspect Service: {Port: {operation: {
console.log(JSON.stringify(description.StockQuote.StockQuoteSoap.GetQuote));

Client.setSecurity(security)

Use the specified security protocol.

Refer to test case ssl-test for an example of using this API.

Client.method(args, callback)

Call method on the SOAP service.

  client.MyFunction({name: 'value'}, function(err, result, envelope, soapHeader) {
      // Result is a javascript object
      // Envelope is the response envelope from the Web Service
      // soapHeader is the response soap header as a JavaScript object
  })

A method can also be called as a promise.

  client.MyFunction({name: 'value'}).then(function({result, envelope, soapHeader}){
    // ...
  }, function(err) {
    // ...
  });

  // in async/await flavor
  try {
    const {result, envelope, soapHeader} = await client.MyFunction({name: 'value'});
  } catch(err) {
    // handle error
  }

Client.service.port.method(args, callback[, options[, extraHeaders]])

Call a method using a specific service and port.

  client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
      // Result is a JavaScript object
  })

Options (optional)

Accepts any option that the request module accepts, see request module.

For example, you could set a timeout of 5 seconds on the request like this:

  client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
      // result is a javascript object
  }, {timeout: 5000})

You can measure the elapsed time on the request by passing the time option:

  client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
      // client.lastElapsedTime - the elapsed time of the last request in milliseconds
  }, {time: true})

Alternative method call using callback-last pattern

To align method call signature with Node's standard callback-last pattern and eventually allow promisification of method calls, the following method signatures are also supported:

client.MyService.MyPort.MyFunction({name: 'value'}, options, function (err, result) {
  // result is a javascript object
})

client.MyService.MyPort.MyFunction({name: 'value'}, options, extraHeaders, function (err, result) {
  // result is a javascript object
})

Client.lastRequest

The property that contains last full soap request for client logging.

Client.setEndpoint(url)

Overwrites the SOAP service endpoint address.

Client events

Client instances emit the following events:

  • request - Emitted before a request is sent. The event handler receives the entire Soap request (Envelope) including headers.
  • message - Emitted before a request is sent. The event handler receives the Soap body contents. Useful if you don't want to log /store Soap headers.
  • soapError - Emitted when an erroneous response is received. Useful if you want to globally log errors.
  • response - Emitted after a response is received. The event handler receives the SOAP response body as well as the entire IncomingMessage response object. This is emitted for all responses (both success and errors).

For an example of using this API, see ssl-test.

Here is an example of 'soapError' event

soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', function (err, client) {
  var didEmitEvent = false;
  client.on('soapError', function(err) {
    didEmitEvent = true;
    assert.ok(err.root.Envelope.Body.Fault);
  });
  client.MyOperation({}, function(err, result) {
    assert.ok(didEmitEvent);
    done();
  });
}, baseUrl);

Security

strong-soap has several default security protocols. You can easily add your own as well. The interface is quite simple. Each protocol defines two methods:

  • addOptions - Method that accepts an options arg that is eventually passed directly to request
  • toXML - Method that returns a string of XML.

BasicAuthSecurity

  client.setSecurity(new soap.BasicAuthSecurity('username', 'password'));

BearerSecurity

  client.setSecurity(new soap.BearerSecurity('token'));

ClientSSLSecurity

Note: If you run into issues using this protocol, consider passing these options as default request options to the constructor:

  • rejectUnauthorized: false
  • strictSSL: false
  • secureOptions: constants.SSL_OP_NO_TLSv1_2 (this is likely needed for node >= 10.0)
  client.setSecurity(new soap.ClientSSLSecurity(
    '/path/to/key'
    , '/path/to/cert'
    , {/*default request options*/}
  ));

WSSecurity

WSSecurity implements WS-Security. UsernameToken and PasswordText/PasswordDigest is supported.

  var wsSecurity = new WSSecurity(username, password, options)
    //the 'options' object is optional and contains properties:
    //passwordType: 'PasswordDigest' or 'PasswordText' default is PasswordText
    //hasTimeStamp: true or false, default is true
    //hasTokenCreated: true or false, default is true
  client.setSecurity(wsSecurity);

WSSecurityCert

WS-Security X509 Certificate support.

  var privateKey = fs.readFileSync(privateKeyPath);
  var publicKey = fs.readFileSync(publicKeyPath);
  var password = ''; // optional password
  var wsSecurity = new soap.WSSecurityCert(privateKey, publicKey, password, 'utf8');
  client.setSecurity(wsSecurity);

Note: Optional dependency 'ursa' is required to be installed successfully when WSSecurityCert is used.

ClientSSLSecurityPFX

  const pfxSecurity = new soap.ClientSSLSecurityPFX(pathToPfxOrFileBuffer, passphrase)
  client.setSecurity(pfxSecurity)

XML attributes

Handling XML attributes, value, and XML (wsdlOptions)

To override the default behavior of strong-soap, use the wsdlOptions object, passed in the createClient() method. The wsdlOptions has the following properties:

var wsdlOptions = {
  attributesKey: 'theAttrs',
  valueKey: 'theVal',
  xmlKey: 'theXml'
}

If you call createClient() with no options (or an empty Object {}), strong-soap defaults to the following:

  • attributesKey : '$attributes'
  • valueKey : '$value'
  • xmlKey : '$xml'

Overriding the value key

By default, strong-soap uses $value as key for any parsed XML value which may interfere with your other code as it could be some reserved word, or the $ in general cannot be used for a key to start with.

You can define your own valueKey by passing it in the wsdl_options to the createClient call like so:

var wsdlOptions = {
  valueKey: 'theVal'
};

soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) {
  // your code
});

Overriding the xml key

As valueKey, strong-soap uses $xml as key. The xml key is used to pass XML Object without adding namespace or parsing the string.

Example :

dom = {
     $xml: '<parentnode type="type"><childnode></childnode></parentnode>'
};
<tns:dom>
    <parentnode type="type">
          <childnode></childnode>
    </parentnode>
</tns:dom>

You can define your own xmlKey by passing it in the wsdl_options to the createClient call like this:

var wsdlOptions = {
  xmlKey: 'theXml'
};

soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) {
  // your code
});

Overriding the attributes key

You can achieve attributes like:

<parentnode>
  <childnode name="childsname">
  </childnode>
</parentnode>

By attaching an attributes object to a node.

{
  parentnode: {
    childnode: {
      $attributes: {
        name: 'childsname'
      }
    }
  }
}

However, "attributes" may be a reserved key for some systems that actually want a node:

<attributes>
</attributes>

In this case you can configure the attributes key in the wsdlOptions like this:

var wsdlOptions = {
  attributesKey: '$attributes'
};

Adding xsiType

soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) {
  client.*method*({
    parentnode: {
      childnode: {
        $attributes: {
          $xsiType: "{xmlnsTy}Ty"
        }
      }
    }
  });
});

Removing the xsiType. The resulting Request shouldn't have the attribute xsiType

soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) {
  client.*method*({
    parentnode: {
      childnode: {
        $attributes: {

        }
      }
    }
  });
});

To see it in practice, consider the sample in: test/request-response-samples/addPets__force_namespaces

XMLHandler

XMLHandler enables you to to convert a JSON object to XML and XML to a JSON object. It can also parse an XML string or stream into the XMLBuilder tree.

API to convert JSON object to XML and XML to JSON object:

var soap = require('..').soap;
var XMLHandler = soap.XMLHandler;
var xmlHandler = new XMLHandler();
var util = require('util');
var url = 'http://www.webservicex.net/stockquote.asmx?WSDL';

var requestArgs = {
  symbol: 'IBM'
};

var options = {};
var clientOptions = {};
soap.createClient(url, clientOptions, function(err, client) {
  var customRequestHeader = {customheader1: 'test1'};
  client.GetQuote(requestArgs, function(err, result, envelope, soapHeader) {
    // Convert 'result' JSON object to XML
    var node = xmlHandler.jsonToXml(null, null,
      XMLHandler.createSOAPEnvelopeDescriptor('soap'), result);
    var xml = node.end({pretty: true});
    console.log(xml);

    // Convert XML to JSON object
    var root = xmlHandler.xmlToJson(null, xml, null);
    console.log('%s', util.inspect(root, {depth: null}));

  }, options, customRequestHeader);
});

Parse XML string or stream into the XMLBuilder tree:

var root = XMLHandler.parseXml(null, xmlString);

WSDL

wsdl.open(wsdlURL, options, callback(err, wsdl))

Loads WSDL into a tree form. Traverse through WSDL tree to get to bindings, services, ports, operations, and so on.

Parameters:

  • wsdlURL WSDL url to load.
  • options WSDL options
  • callback Error and WSDL loaded into object tree.
var soap = require('..').soap;
var WSDL = soap.WSDL;
var path = require('path');

// Pass in WSDL options if any

var options = {};
WSDL.open('./wsdls/stockquote.wsdl',options,
  function(err, wsdl) {
    // You should be able to get to any information of this WSDL from this object. Traverse
    // the WSDL tree to get  bindings, operations, services, portTypes, messages,
    // parts, and XSD elements/Attributes.

    var getQuoteOp = wsdl.definitions.bindings.StockQuoteSoap.operations.GetQuote;
    // print operation name
    console.log(getQuoteOp.$name);
    var service = wsdl.definitions.services['StockQuote'];
    //print service name
    console.log(service.$name);
});

wsdl.openSync(wsdlURL, options)

Loads WSDL into a tree form directly from memory. It traverses through WSDL tree to get to bindings, services, ports, operations, and so on as long as you have your dependent WSDLs and schemas are loaded and available in the options.WSDL_CACHE. If any I/O is required to retrieve any dependencies this call will throw an error.

Parameters:

  • wsdlURL WSDL url to load as named in the cache.
  • options WSDL options

An example of loading WSDLs into your options.WSDL_CACHE and calling wsdl.loadSync() can be found in the test test/wsdl-load-from-memory-test

Server

soap.listen(server, path, services, wsdl)

Creates a new SOAP server that listens on path and provides services.

wsdl is an xml string that defines the service.

  var myService = {
      MyService: {
          MyPort: {
              MyFunction: function(args) {
                  return {
                      name: args.name
                  };
              },

              // This is how to define an asynchronous function.
              MyAsyncFunction: function(args, callback) {
                  // do some work
                  callback({
                      name: args.name
                  });
              },

              // This is how to receive incoming headers
              HeadersAwareFunction: function(args, cb, headers) {
                  return {
                      name: headers.Token
                  };
              },

              // You can also inspect the original `req`
              reallyDetailedFunction: function(args, cb, headers, req) {
                  console.log('SOAP `reallyDetailedFunction` request from ' + req.connection.remoteAddress);
                  return {
                      name: headers.Token
                  };
              }
          }
      }
  };

  var xml = require('fs').readFileSync('myservice.wsdl', 'utf8'),
      server = http.createServer(function(request,response) {
          response.end("404: Not Found: " + request.url);
      });

  server.listen(8000);
  soap.listen(server, '/wsdl', myService, xml);

An example of using the SOAP server is in test/server-client-document-test

Options

You can pass in server and WSDL Options using an options hash.

var xml = require('fs').readFileSync('myservice.wsdl', 'utf8');

soap.listen(server, {
    // Server options.
    path: '/wsdl',
    services: myService,
    xml: xml,

    // WSDL options.
    attributesKey: 'theAttrs',
    valueKey: 'theVal',
    xmlKey: 'theXml'
});

Server logging

If the log method is defined it will be called with 'received' and 'replied' along with data.

  server = soap.listen(...)
  server.log = function(type, data) {
    // type is 'received' or 'replied'
  };

Server events

Server instances emit the following events:

  • request - Emitted for every received messages. The signature of the callback is function(request, methodName).
  • headers - Emitted when the SOAP Headers are not empty. The signature of the callback is function(headers, methodName).

The sequence order of the calls is request, headers and then the dedicated service method.

    test.soapServer.on('request', function requestManager(request, methodName) {
      assert.equal(methodName, 'GetLastTradePrice');
      done();
    });

An example of using the SOAP server is in test/server-test

SOAP Fault

A service method can reply with a SOAP Fault to a client by throwing an object with a Fault property.

Example SOAP 1.1 Fault:

    test.service = {
      DocLiteralWrappedService: {
        DocLiteralWrappedPort: {
          myMethod: function (args, cb, soapHeader) {
            throw {
              Fault: {
                  faultcode: "sampleFaultCode",
                  faultstring: "sampleFaultString",
                  detail:
                    { myMethodFault:
                      {errorMessage: 'MyMethod Business Exception message', value: 10}
                    }
                }
            }
          }
        }
      }
    }

SOAP 1.2 Fault:

    test.service = {
      DocLiteralWrappedService: {
        DocLiteralWrappedPort: {
          myMethod: function (args, cb, soapHeader) {
            throw {
              Fault: {
                Code: {
                  Value: "soap:Sender",
                  Subcode: { Value: "rpc:BadArguments" }
                },
                Reason: { Text: "Processing Error" },
                Detail:
                {myMethodFault2:
                   {errorMessage2: 'MyMethod Business Exception message', value2: 10}
                }
              }
            }
          }
        }
      }
    }

Examples of SOAP 1.1/SOAP 1.2 Fault response can be found in test test/server-client-document-test

Server security example using PasswordDigest

If server.authenticate is not defined then no authentication will take place.

  server = soap.listen(...)
  server.authenticate = function(security) {
    var created, nonce, password, user, token;
    token = security.UsernameToken, user = token.Username,
            password = token.Password, nonce = token.Nonce, created = token.Created;
    return user === 'user' && password === soap.passwordDigest(nonce, created, 'password');
  };

Server connection authorization

The server.authorizeConnection method is called prior to the soap service method. If the method is defined and returns false then the incoming connection is terminated.

  server = soap.listen(...)
  server.authorizeConnection = function(req) {
    return true; // or false
  };

SOAP headers

Received SOAP headers

A service method can look at the SOAP headers by providing a third arguments.

  {
      HeadersAwareFunction: function(args, cb, headers) {
          return {
              name: headers.Token
          };
      }
  }

It is also possible to subscribe to the 'headers' event. The event is triggered before the service method is called, and only when the SOAP Headers are not empty.

  server = soap.listen(...)
  server.on('headers', function(headers, methodName) {
    // It is possible to change the value of the headers
    // before they are handed to the service method.
    // It is also possible to throw a SOAP Fault
  });

First parameter is the Headers object; second parameter is the name of the SOAP method that will called (in case you need to handle the headers differently based on the method).

Outgoing SOAP headers

Both client and server can define SOAP headers that will be added to what they send. They provide the following methods to manage the headers.

addSoapHeader(value, qname)

Adds soapHeader to soap:Header node.

Parameters:

  • value JSON object representing {headerName: headerValue} or XML string.
  • qname qname used for the header
addSoapHeader(value, qname, options);

Returns the index where the header is inserted.

changeSoapHeader(index, value, qname)

Changes an existing soapHeader.

Parameters:

  • index index of the header to replace with provided new value
  • value JSON object representing {headerName: headerValue} or XML string.
  • qname qname used for the header

getSoapHeaders()

Returns all defined headers.

clearSoapHeaders()

Removes all defined headers.

Examples of using SOAP header API are in: test/server-test and test/server-test

soap-stub

Unit testing services that use SOAP clients can be very cumbersome. To get around this you can use soap-stub in conjunction with sinon to stub soap with your clients.

Example

var sinon = require('sinon');
var soapStub = require('strong-soap/soap-stub');

var urlMyApplicationWillUseWithCreateClient = './example/stockquote.wsdl';
var clientStub = {
  SomeOperation: sinon.stub()
};

clientStub.SomeOperation.respondWithError = soapStub.createRespondingStub({error: 'error'});
clientStub.SomeOperation.respondWithSuccess = soapStub.createRespondingStub({success: 'success'});
// or if you are using promises
clientStub.SomeOperation.respondWithError = soapStub.createRespondingStubAsync({error: 'error'});
clientStub.SomeOperation.respondWithSuccess = soapStub.createRespondingStubAsync({success: 'success'});


soapStub.registerClient('my client alias', urlMyApplicationWillUseWithCreateClient, clientStub);


var fs = require('fs'),
  assert = require('assert'),
  request = require('@cypress/request'),
  http = require('http'),
  lastReqAddress;

describe('myService', function() {
  var clientStub;
  var myService;

  beforeEach(function() {
    clientStub = soapStub.getStub('my client alias');
    soapStub.reset();
    myService = clientStub;
  });

  describe('failures', function() {
    beforeEach(function() {
      clientStub.SomeOperation.respondWithError();
    });

    it('should handle error responses', function() {
      myService.SomeOperation(function(err, response) {
        // handle the error response.
      });
    });
  });
});

Contributors

strong-soap's People

Contributors

0candy avatar achrinza avatar aheckmann avatar alanbly avatar aleung avatar ankush-garg avatar arnaudm avatar arthurschreiber avatar atwong avatar bhoriuchi avatar crandmck avatar deepakrkris avatar dhmlau avatar herom avatar jameskyburz avatar jannyhou avatar jbuchbinder avatar jonrober-80 avatar jsdevel avatar kaven276 avatar mdhooge avatar mik13 avatar milewise avatar rashmihunt avatar raymondfeng avatar renovate-bot avatar renovate[bot] avatar rmg avatar scrib3r avatar vpulim avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

strong-soap's Issues

WSDL attribute not parsed

Attributes are ignored while parsing complexType WSDL element

Explanation from the example in this repo:

If we modify the local WSDL to include an attribute named "facade" in the request GetCityWeatherByZIP

<s:element name="GetCityWeatherByZIP"> <s:complexType> <s:sequence> <s:element minOccurs="0" maxOccurs="1" name="ZIP" type="s:string"/> </s:sequence> <s:attribute name="facade" fixed="fixedtext" type="string"/> </s:complexType> </s:element>

The added attribute will be ignored and nothing will be added to the element in the final request.

The expected output for this modification is something like:

<s11:Envelope xmlns:s11=\"http: //schemas.xmlsoap.org/soap/envelope/"> <s11:Body> <ns1:GetCityWeatherByZIP xmlns:ns1='http://ws.cdyne.com/WeatherWS/' facade='fixedtext'> <ns1:ZIP>?XXX?</ns1:ZIP> </ns1:GetCityWeatherByZIP> </s11:Body> </s11:Envelope>

Clarification on custom namespaces

Using the attached wsdl, I'm unable to get the correct namespaces going.
I'm making a request like:

client.GetClasses({
    'GetClassesRequest': {
      'PageInfo': {
        'Page' : 2,
        'PageSize': 1,
      }
    }
  }

The request is successful, but PageInfo, Page, and PageSize should all have the req: namespace; instead, they no namespace at all.
The request XML looks like:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <x509Thumbprint xmlns="http://JonasFitness.com/CompeteDataService/2013/04/01">REDACTED</x509Thumbprint>
    <CompanyID xmlns="http://JonasFitness.com/CompeteDataService/2013/04/01">REDACTED</CompanyID>
  </soap:Header>
  <soap:Body>
    <ns1:GetClasses xmlns:ns1="http://JonasFitness.com/CompeteDataService/v2_0/ClassService">
      <ns1:GetClassesRequest>
        <!--WRONG PART HERE-->
        <PageInfo>
          <Page>2</Page>
          <PageSize>1</PageSize>
        </PageInfo>
        <!--END WRONG PART-->
      </ns1:GetClassesRequest>
    </ns1:GetClasses>
  </soap:Body>
</soap:Envelope>

I'm also confused why the other namespace definitions aren't added to the envelope. Those should be:
xmlns:clas="http://JonasFitness.com/CompeteDataService/v2_0/ClassService"
xmlns:req="http://JonasFitness.com/CompeteDataService/v2_0/Requests"
xmlns:com="http://JonasFitness.com/CompeteDataService/v2_0/Common"

My questions are:

  1. How do I add custom namespace definitions to the envelope? I assumed those would get added by consumption of the wsdl.
  2. How do I ensure the correct namespaces are used for the specified tags?

I reviewed all the tests of this repo to try to find this info myself, but everything appears to "just work" via consumption of the wsdls (e.g. this one that has custom n and c namespaces).

ClassService.svc.txt (note GH didn't let me upload an XML, so I renamed this to a txt file)

What happended to overrideRootElement?

The overrideRootElement option seems to have been removed. Is there an alternative way of changing the soap:body to include nested elements?

Instead of:

  const requestArgs = {
    customer: 123
  }

having:

  <soap:Body>
    <customer>123</customer>
  </soap:Body>

I want the body to have:

  <soap:Body>
    <method>
      <request>
        <customer>123</customer>
      </request>
    </method>
  </soap:Body>

Complex data

Hello all,

How do I configure something like this:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wrap="http://wrappers.webservice.appservices.core.inteqnet.com" xmlns:xsd="http://beans.webservice.appservices.core.inteqnet.com/xsd"> <soapenv:Header/> <soapenv:Body> <wrap:getSQLQueryResults> <wrap:credentials> <xsd:userName>xxxxxx</xsd:userName> <xsd:userPassword>xxxxxx</xsd:userPassword> </wrap:credentials> <wrap:extendedSettings> <xsd:responseFormat>JSON</xsd:responseFormat> </wrap:extendedSettings> <wrap:declareSection></wrap:declareSection> <wrap:sqlSelect>SELECT DISTINCT slice,ccti_category FROM VIC_CATEGORIZATION</wrap:sqlSelect> <wrap:orderByClause></wrap:orderByClause> </wrap:getSQLQueryResults> </soapenv:Body> </soapenv:Envelope>

I don´t know how.

Regards

ReferenceError: descriptor is not defined

I'm using strong-soap v1.1.0 to acces this service: http://www.citram.es:50081/VENTAPREPAGOTITULO/VentaPrepagoTitulo.svc?wsdl
I'm getting the following error:

ReferenceError: descriptor is not defined
    at Attribute.describe (…/node_modules/strong-soap/src/parser/xsd/attribute.js:33:7)
    at ComplexType.describe (…/node_modules/strong-soap/src/parser/xsd/complexType.js:23:31)
    at Extension.describe (…/node_modules/strong-soap/src/parser/xsd/extension.js:18:38)
    at ComplexContent.describe (…/node_modules/strong-soap/src/parser/xsd/complexContent.js:16:31)
    at ComplexType.describe (…/node_modules/strong-soap/src/parser/xsd/complexType.js:23:31)
    at Extension.describe (…/node_modules/strong-soap/src/parser/xsd/extension.js:18:38)
    at ComplexContent.describe (…/node_modules/strong-soap/src/parser/xsd/complexContent.js:16:31)
    at ComplexType.describe (…/node_modules/strong-soap/src/parser/xsd/complexType.js:23:31)
    at Element.describe (…/node_modules/strong-soap/src/parser/xsd/element.js:49:40)
    at Sequence.describeChildren (…/node_modules/strong-soap/src/parser/xsd/xsdElement.js:18:31)
    at Sequence.describe (…/node_modules/strong-soap/src/parser/xsd/xsdElement.js:27:17)
    at ComplexType.describe (…/node_modules/strong-soap/src/parser/xsd/complexType.js:23:31)
    at Element.describe (…/node_modules/strong-soap/src/parser/xsd/element.js:49:40)
    at Sequence.describeChildren (…/node_modules/strong-soap/src/parser/xsd/xsdElement.js:18:31)
    at Sequence.describe (…/node_modules/strong-soap/src/parser/xsd/xsdElement.js:27:17)
    at ComplexType.describe (…/node_modules/strong-soap/src/parser/xsd/complexType.js:23:31)
    at Element.describe (…/node_modules/strong-soap/src/parser/xsd/element.js:70:39)
    at Operation.describe (…/node_modules/strong-soap/src/parser/wsdl/operation.js:118:39)
    at Binding.describe (…/node_modules/strong-soap/src/parser/wsdl/binding.js:69:36)
    at Service.describe (…/node_modules/strong-soap/src/parser/wsdl/service.js:36:34)
    at WSDL.describeServices (…/node_modules/strong-soap/src/parser/wsdl.js:204:32)
    at Client.describe (…/node_modules/strong-soap/src/client.js:33:22)
    at TTPPlugin._callee$ (…/src/plugins/ttp-plugin.js:18:31)
    at tryCatch (…/node_modules/regenerator-runtime/runtime.js:64:40)
    at Generator.invoke [as _invoke] (…/node_modules/regenerator-runtime/runtime.js:355:22)
    at Generator.prototype.(anonymous function) [as next] (…/node_modules/regenerator-runtime/runtime.js:116:21)
    at step (…/node_modules/babel-runtime/helpers/asyncToGenerator.js:17:30)
    at …/node_modules/babel-runtime/helpers/asyncToGenerator.js:28:13
    at process._tickCallback (internal/process/next_tick.js:103:7)

This is happening both in describe() and in any of the service methods. This particular trace is from a describe(), though.

Allow security to be set for the initial request

Hi there!

I'm in a situation where a WSDL is 100% protected–even from the initial request–by WSSecurityCert. I'm finding that strong-soap only allows one to set the security of the client after it's been created, meaning that the initial "discovery" request is unsecured (and thus gets blocked).
Any advice on securing the initial wsdl request?

Thanks for this lib; it's very useful!

Add linting rules

Looks like JSHint is somewhat there but not configured correctly and the rules are not being followed.

Is there any way to override the namespace?

Hey! Good afternoon. I'm almost there to get the client working! The only issue I'm having is that the namespace for the body RQ is not the right one. Is there any way to override it?

I think there has to be a way for strong-soap to get the proper namespace though, since SOAPUI gets it OK. strong-soap is way better than soap-node anyway: strong-soap understands very well which nodes require namespace and which don't.

Would it be useful if I sent the wsdl?

A million thanks in advance.

[IMPORTANT] add an xsi type ?

hi

i m creating an EDI for my work with another enterprise and search how to force an xsi type

if i print the sended xml from src/client.js now i have for exemple

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header/>
  <soap:Body>
    <ns1:EDIContact.SendBDC xmlns:ns1="something">
      <LoginWS>something.</LoginWS>
      <PasswordWS>something</PasswordWS>
      <OrderNumber>something</OrderNumber>
      <XMLOrder>a base64string</XMLOrder>
    </ns1:EDIContact.SendBDC>
  </soap:Body>
</soap:Envelope>

and i want if possible

<XMLOrder xsi:type="xsd :base64Binary">... a base64string...

if i read the doc i have to make something in wsdlOptions passed to create client right ?

thanks !!

Missing element in server response

Im not sure if this is mandatory or bug, but I have following spec in wsdl schema:

...
            <xs:element name="verifyProductAvailabilityRequest">
                <xs:complexType>
                    <xs:complexContent>
                        <xs:extension base="tns:abstractRequest">
                            <xs:sequence>
                                <xs:element name="productId" type="tns:productId"/>
                                <xs:element name="customerLanguage" type="tns:customerLanguage"/>
                            </xs:sequence>
                        </xs:extension>
                    </xs:complexContent>
                </xs:complexType>
            </xs:element>

            <xs:element name="verifyProductAvailabilityResponse">
                <xs:complexType>
                    <xs:complexContent>
                        <xs:extension base="tns:abstractResponse">
                            <xs:sequence>
                                <xs:element name="siteName" type="tns:siteName"/>
                                <xs:element name="siteCurrency" type="tns:siteCurrency"/>
                                <xs:element name="siteLanguage" type="tns:siteLanguage"/>
                                <xs:element name="productList" type="tns:productList"/>
                            </xs:sequence>
                        </xs:extension>
                    </xs:complexContent>
                </xs:complexType>
            </xs:element>
...

When I was using node-soap module, response looked like:
...<soap:Body><verifyProductAvailabilityResponse xmlns="xxx"><productList><product>...

But with strong-soap response look like this:
...<soap:Body><productList><product>...

Feature proposal: Soap Headers should be at request level and not at client level

Hey!

I'd like to suggest, and code if approved, a feature for moving header handling from the client to the request. Actually for setting a header, the methods addSoapHeader or changeSoapHeader have to be used. These methods modify the client. Considering that, if the invoked web services use the headers for specifying session or technical data, each time a web service is invoked, the client has to be modified to specify the new values of the headers.

I really think the headers of the request should work exactly as the body of the request: they should be specified request by request, and the client should remain the same no matter what the request has.

As an example, I use several web services from Sabre, and they look like the following one:

http://webservices.sabre.com/wsdl/tpfc/OTA_AirAvailLLS2.3.0RQ.wsdl

If you use SOAPUI to create a request for that WSDL, you'll see that it has a very big header and most of its data changes dynamically from request to request, so modifying the client for each request wouldn't be the best option.

Please let me know if something like this would be accepted.

A million thanks in advance.

Feature Proposal: Validate requestArgs against XSD

From the client example:

      var requestArgs = {
        ZIP: '94306'
      };
      var options = {};

      soap.createClient(url, options, function(err, client) {
        client.GetCityWeatherByZIP(requestArgs, function(err, result, envelope) {

It would be nice if there was a method to validate that the requestArgs matches the schema, i.e. if ZIP was spelled incorrectly in the above case, and to generate an example request argument.

My POC approach would be xsd -> json schema and then validate it and use json-schema-faker to generate examples.

How do I change the prefix?

Specifically does anyone know how I change the namespace from <soap:Header> to <soapenv:Header> and similarly attributes to something like soapenv:mustUnderstand="1" ?

My code currently looks something like this:

const soap = require('soap');
const url = 'https://staging.identitymanagement.lexisnexis.com/identity-proofing/services/identityProofingServiceWS/v2?wsdl';

soap.createClient(url, function(err, client) {
  if(err) {
    console.log('Error', err);
  }
  client.setSecurity(new soap.WSSecurity('username', 'password', { 'mustUnderstand': 1}));
  client.invokeIdentityService({ 'workFlow': 'SOME_FLOW' }, (err, result, raw, soapHeader) => {
    console.log('Error======================');
    console.log(err);
    console.log('Result=============================');
    console.log(result);
    console.log('raw==============================');
    console.log(raw);
    console.log('soapHeader', soapHeader);
  });
});

It produces XML that looks something like this...

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns1="http://cxf.apache.org/bindings/xformat" xmlns:tns="http://ws.identityproofing.idm.risk.lexisnexis.com/" xmlns:survey="http://ns.lexisnexis.com/survey/1.0" xmlns:identity="http://ns.lexisnexis.com/identity-proofing/1.0" xmlns:ns0="http://ns.lexisnexis.com/identity-proofing/1.0">
<soap:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1">
    <wsu:Timestamp wsu:Id="Timestamp-2017-03-04T01:58:02Z">
        <wsu:Created>2017-03-04T01:58:02Z</wsu:Created>
        <wsu:Expires>2017-03-04T02:08:02Z</wsu:Expires>
    </wsu:Timestamp>
    <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-2017-03-04T01:58:02Z">
    <wsse:Username>username</wsse:Username>
    <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
    <wsu:Created>2017-03-04T01:58:02Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
<soap:Body>
    <tns:invokeIdentityService xmlns:ns2="http://tempuri.org/" xmlns:ns3="http://sillypets.com/xsd">
    <workFlow>SOME_FLOW</workFlow>
</tns:invokeIdentityService>
</soap:Body>
</soap:Envelope>

Thanks!

WSDL error

Something wrong with wsdl parsing. I get this error msgs. Server side.

Element {http://schemas.xmlsoap.org/wsdl/}wsdl:part is not allowed within "wsdl:message"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:part is not allowed within "wsdl:message"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:part is not allowed within "wsdl:message"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:part is not allowed within "wsdl:message"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:part is not allowed within "wsdl:message"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:part is not allowed within "wsdl:message"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:part is not allowed within "wsdl:message"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:part is not allowed within "wsdl:message"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:part is not allowed within "wsdl:message"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:part is not allowed within "wsdl:message"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:operation is not allowed within "wsdl:portType"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:input is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:output is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:operation is not allowed within "wsdl:portType"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:input is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:output is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:operation is not allowed within "wsdl:portType"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:input is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:output is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:operation is not allowed within "wsdl:portType"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:input is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:output is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:operation is not allowed within "wsdl:portType"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:input is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:output is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/soap/}soap:binding is not allowed within "wsdl:binding"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:operation is not allowed within "wsdl:binding"
Element {http://schemas.xmlsoap.org/wsdl/soap/}soap:operation is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:input is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/soap/}soap:body is not allowed within "wsdl:input"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:output is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/soap/}soap:body is not allowed within "wsdl:output"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:operation is not allowed within "wsdl:binding"
Element {http://schemas.xmlsoap.org/wsdl/soap/}soap:operation is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:input is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/soap/}soap:body is not allowed within "wsdl:input"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:output is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/soap/}soap:body is not allowed within "wsdl:output"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:operation is not allowed within "wsdl:binding"
Element {http://schemas.xmlsoap.org/wsdl/soap/}soap:operation is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/}wsdl:input is not allowed within "wsdl:operation"
Element {http://schemas.xmlsoap.org/wsdl/soap/}soap:body is not allowed within "wsdl:input"

ReferenceError: definitions is not defined

Hi!

This module seems like the perfect fit for a project I'm working on.

However, when trying to run a simple client.describe() on the wsdl which you can access here, I get this error:

ReferenceError: definitions is not defined
    at /Users/____/dev/_____/skl-test/node_modules/strong-soap/lib/parser/wsdl/operation.js:271:52
    at Array.forEach (native)
    at Function.describeHeaders (/Users/____/dev/_____/skl-test/node_modules/strong-soap/lib/parser/wsdl/operation.js:268:21)
    at Operation.describe (/Users/____/dev/_____/skl-test/node_modules/strong-soap/lib/parser/wsdl/operation.js:191:36)
    at Binding.describe (/Users/____/dev/_____/skl-test/node_modules/strong-soap/lib/parser/wsdl/binding.js:88:38)
    at Service.describe (/Users/____/dev/_____/skl-test/node_modules/strong-soap/lib/parser/wsdl/service.js:54:36)
    at WSDL.describeServices (/Users/____/dev/_____/skl-test/node_modules/strong-soap/lib/parser/wsdl.js:201:34)
    at Client.describe (/Users/____/dev/_____/skl-test/node_modules/strong-soap/lib/client.js:57:24)
    at /Users/____/dev/_____/skl-test/strongsoap.js:25:22
    at /Users/____/dev/_____/skl-test/node_modules/strong-soap/lib/soap.js:54:5

Here is the script in it's fully:

const soap = require('strong-soap').soap;
const url = 'https://sit-sob.test.1177.se/sob-application-api/GetProcessesResponderService?wsdl';

soap.createClient(url, (err, client) => {
  console.log(client.describe());
});

Any ideas?

Thanks!

strong-soap Client works with WSDL but others don't

I did a simple service with this library and tested it with the client, which worked. But trying this with the SOAPClient from PHP didn't. Somehow the types of my method are all UNKNOWN.

Maybe I have some error in my WSDL and the strong-soap client doesn't care as much as the PHP one.

<?xml version="1.0"?>
<definitions 
  name="MyData"
  targetNamespace="http://example.com/dataservice.wsdl"
  xmlns:this="http://example.com/dataservice.wsdl"
  xmlns:type="http://example.com/dataservice.xsd"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns="http://schemas.xmlsoap.org/wsdl/">

  <types>
    <schema
      targetNamespace="http://example.com/dataservice.xsd"
      xmlns="http://www.w3.org/2000/10/XMLSchema">

      <element name="dataPosition">
        <complexType>
          <all>
            <element name="serialNo" type="string"/>
            <element name="dataDate" type="string"/>
            <element name="dataTime" type="string"/>
            <element name="driveNo" type="string"/>
            <element name="driveStatus" type="string"/>
          </all>
        </complexType>
      </element>

      <element name="Result">
        <complexType>
          <all>
            <element name="code" type="int"/>
            <element name="msg" type="string"/>
          </all>
        </complexType>
      </element>

    </schema>
  </types>

  <message name="sendPositionInput">
    <part name="body" element="type:dataPosition"/>
  </message>

  <message name="sendPositionOutput">
    <part name="body" element="type:Result"/>
  </message>

  <portType name="dataPortType">
    <operation name="sendPosition">
      <input message="this:sendPositionInput"/>
      <output message="this:sendPositionOutput"/>
    </operation>
  </portType>

  <binding name="dataBinding" type="this:dataPortType">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="sendPosition">
      <soap:operation soapAction="%SERVICE_LOCATION%/sendPosition"/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>

  <service name="MyDataService">
    <port name="dataPort" binding="this:dataBinding">
      <soap:address location="%SERVICE_LOCATION%"/>
    </port>
  </service>

</definitions>

Maybe the vaildator is missing something?

Escaping back slash

I was trying to access the SOAP service, and following were the code tried:

    var wsdlURL             = './payments/XiPayWS3x.wsdl';
    var options = {
        wsdl_headers :{
            user : 'domain\\user_name',
            password : xipay_password
        },
        endpoint: xipay_serviceURL
    };
    soap.createClient(wsdlURL, options, function(err, client) {
        console.log(client.httpClient.options);
    });

You can see in the above code I have given my user name with '\' two slash, actually in the user name only one slash is there, I was trying to escape here. But after escaping like this also when I print the httpClientOptions it shows two slashes. And when I tried with removing the one slash, in the httpClientOptions there is no slash at all.

Due to this reason when ever I try to access a SOAP service I am getting 401 Error.

Thanks for the help.

Getting InvalidSecurity faultstring when calling WCF web service

Hi,

I need to call a WCF service, I have a username and password, searching on the web it appears I need to use WS-Security. Here's my code:

var soap = require('strong-soap').soap;
var url = '<addr>/Common.svc?wsdl';
var requestArgs = {
    arg: 'value'
};
var options = {};

soap.createClient(url, options, function(err, client) {
    client.setSecurity(new soap.WSSecurity('<username>', '<password>'));
    client['<api>'](requestArgs, function(err, result, envelope) {
        cosole.log(err);
        console.log(JSON.stringify(result));
    });
});

And I'm getting the same error as not setting security:

Error: faultcode: a:InvalidSecurity faultstring: An error occurred when verifying security for the message.
    at XMLHandler.xmlToJson (/node_modules/strong-soap/src/parser/xmlHandler.js:626:23)

Any advice is very much appreciated.

Babel script doesn't run in one of the CI build targets

Strong-soap installs and tests strongloop-soap-connector as well as part of it’s CI build ' [cis-jenkins] downstream: loopback-connector-soap@master” Babel script seem to have not run for strong-soap in this case.

Error: Cannot find module './lib/security/index'
at Function.Module._resolveFilename (module.js:325:15)
at Function.Module._load (module.js:276:25)
at Module.require (module.js:353:17)
at require (internal/module.js:12:17)
at Object. (/home/jenkins/workspace/ds/loopback-connector-soap~master/node_modules/strong-soap/index.js:10:23)

https://cis-jenkins.swg-devops.com/job/ds/job/loopback-connector-soap~master/126/
https://cis-jenkins.swg-devops.com/job/ds/job/loopback-connector-soap~master/126/consoleFull#-207526304206f8fc75-e0b9-479e-b471-e8fe633361ff

Issue with complexTypes and XSI extensions if you don't define $xsiType as an object

If I have json like this:

let element = {
    someChild: {
        $attributes: {
            $xsiType: '{http://namespace.com}Type'
        }
    }
}

The xml generated will not namespace the extension elements correctly. If you instead define the json like this:

let element = {
    someChild: {
        $attributes: {
            $xsiType: {
                xmlns: 'http://namespace.com',
                type: 'Type'
            }
        }
    }
}

Then the generated xml has the extension nodes namespaced correctly.

I was able to trace this behavior down to xmlHandler.js line 151 as follows:
let extension = descriptor.refOriginal.typeDescriptor.inheritance[child.type];

child is a string in the first json example I gave, so child.type is undefined and thus the extension doesn't get added.

Thanks,
Andreas

Please add use of obj to parameters for requesting info

In my case I'm requesting info from a soap server, like this below...

var requestArgs = {
  authUserName: 'user',
  authPassword: 'pass',
  username: 'user',
  requestedValues: {
      string: 'userid',
      string: 'Email',
      string: 'DisplayName'
  }
};

But it seems that the result is only returning the last index of the obj in requestedValues (DisplayName), It does not seem to run through the obj when making the xml request. Please let me know if maybe I'm
doing this wrong or if it is not actually implemented yet.

Thanks.

Add debug support

  • Add debug statements to all of the main code paths.
  • Remove any console.log statements

Missing Request Tag in Method

When I look at the Request Body it looks like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header/>
  <soap:Body>
    <ns1:MyMethod xmlns:ns1="http://webServices/">
      <param1>1.0</param1>
      <param2>Peaches</param2>
    </ns1:MyMethod>
  </soap:Body>
</soap:Envelope>

The <request> tag is missing. Ie it should look like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header/>
  <soap:Body>
    <ns1:MyMethod xmlns:ns1="http://webServices/">
      <request>
        <param1>1.0</param1>
        <param2>Peaches</param1>
      </request>
    </ns1:MyMethod>
  </soap:Body>
</soap:Envelope>

The call fails because of this. How do I get the <request> tag back in there?

Response not properly mapped

I am testing strong-soap and facing a "Uncaught error: Cannot read property 'qname' of undefined" when getting the following response:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
   <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <MemberGetProfileResponse ExceptionCode="0" LoginId="[email protected]" MemberType="20" FamilyName="abc" FirstName="test" Birthday="19840101" Gender="1" Zipcode="0010013" AddressPrefecture="北海道" AddressCityTown="札幌市北区 北十三条西)" AddressHouse="" TelephoneNumber1="00000000000" Email="[email protected]" FamilyNameFurigana="" FirstNameFurigana="" Language="" ConsumerType="" Referable="false" CounterReferals="0" CounterRemainingReferrals="0" OptInEmail="1" OptInDM="1" IsDraft="false" UserSequence="0000001" xmlns="http://www.b-i.com/ns/LoyaltyWebservice/"/>
   </s:Body>
</s:Envelope>

I have fixed that by editing the client.js file line 304 this way:

        //result = obj.Body[outputBodyDescriptor.elements[0].qname.name];
        var resultContainer = outputBodyDescriptor.elements[0] || outputBodyDescriptor;
        result = obj.Body[resultContainer.qname.name];

Support for WS-Reliable Messaging (WS-RM)

I got this error when I send a message:

The action xxx is not supported by this endpoint. Only WS-ReliableMessaging February 2005 messages are processed by this endpoint.

Please add cookie security

Working with the vSphere API which requires cookie security

The following works for me, but it would be a nice enhancement to have CookieSecurity added to the ones supported by the project.

export class CookieSecurity {
  constructor (cookie, options) {
    this.cookie = cookie
  }
  addHttpHeaders (headers) {
    headers.Cookie = this.cookie
  }
}

fix warning messages

mocha test run outputs a lot of warning messages.
some investigation is needed to check the root cause

Change array prototype cause unhandled exception

Hi,

i've tried this module in my project and it worked properly.
Than in my code i've added to the Array prototype one function like:

Array.prototype.sampleFunction = function() {
	return "Sample function!";
};

and now the module raise an unhandled exception that cause node.js exit

TypeError: this.faults[f].postProcess is not a function
    at Operation.postProcess (..\node_modules\strong-soap\src\parser\wsdl\operation.js:59:22)
    at PortType.postProcess (..\node_modules\strong-soap\src\parser\wsdl\portType.js:17:13)
    at Binding.postProcess (..\node_modules\strong-soap\src\parser\wsdl\binding.js:27:16)
    at Service.postProcess (..\node_modules\strong-soap\src\parser\wsdl\service.js:20:19)
    at ..\node_modules\strong-soap\src\parser\wsdl.js:67:25
    at ..\node_modules\strong-soap\src\parser\wsdl.js:183:9
    at WSDL._processNextInclude (..\node_modules\strong-soap\src\parser\wsdl.js:151:14)
    at ..\node_modules\strong-soap\src\parser\wsdl.js:182:12
    at ..\node_modules\strong-soap\src\parser\wsdl.js:99:9
    at WSDL._processNextInclude (..\node_modules\strong-soap\src\parser\wsdl.js:151:14)
    at WSDL.processIncludes (..\node_modules\strong-soap\src\parser\wsdl.js:197:10)
    at ..\node_modules\strong-soap\src\parser\wsdl.js:54:12
    at _combinedTickCallback (internal/process/next_tick.js:67:7)
    at process._tickCallback (internal/process/next_tick.js:98:9)

if I remove my sampleFunction from Array the module start working again.

Send SOAP response with RelatesTo header when MessageID is passed in the request

Dear developers,

When a soap request is issued with a MessageID in the header, the reponse must contain a response with the ReplyTo containing the same value as the message id conveyed.

For instance, the request:

<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">/BootNotification</a:Action>
<a:MessageID>urn:uuid:bcd39999-8fbe-4610-84ce-7241fbc676c7</a:MessageID>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
...
</s:Body>
</s:Envelope>

Response:

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:RelatesTo>urn:uuid:bcd39999-8fbe-4610-84ce-7241fbc676c7</a:RelatesTo>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
...
</s:Body>
</s:Envelope>

Thanks!

Cheers,
Serge.

Use XSD schema rules

One of the biggest issue of node-soap and strong-soap libs is it doesn't follow XSD schema at all.

Current implementation of strong-soap just passing data as JSON to xmlbuilder-js lib. Unfortunately xmlbuilder-js doesn't provide any functionality to read and handle XSD schema. On the other hand, strong-soap seems to be able to read and parse schema.

What is happening now
When strong-soap receives JSON object/XML data, it iterates thru it and build XML (via xmlbuilder-js)/JSON.

Causes

  • XML request and response might contain elements and structures that are not part of XSD.
  • Wrong order of sequences, extensions and complex elements.
  • Values might not be valid according to XSD.
    These causes makes both libraries unusable in many cases.

What it should do
When strong-soap receive JSON object/XML data, it should iterate thru XSD schema object and do custom mapping to build XML from received JSON object/build JSON from received XML.

Cannot read property 'setSecurity' of undefined - Node JS, Strong-Soap

I try to deploy my node application inside the "IIS 8". I have installed iisnode.

The basic application is running perfectly.

But I go with SOAP, I am getting below error.

Application has thrown an uncaught exception and is terminated:
TypeError: Cannot read property 'setSecurity' of undefined
    at C:\inetpub\iisnode\www\salesorder\so.js:32:11
    at C:\inetpub\iisnode\www\salesorder\node_modules\strong-soap\src\soap.js:48:5
    at C:\inetpub\iisnode\www\salesorder\node_modules\strong-soap\src\soap.js:30:16
    at ReadFileContext.callback (C:\inetpub\iisnode\www\salesorder\node_modules\strong-soap\src\parser\wsdl.js:370:11)
    at FSReqWrap.readFileAfterOpen [as oncomplete] (fs.js:336:13)

Code:

var express = require('express');
var app = express();

app.get('/node/salesorder/myapp/salesorderquery', function(req, res){
    var json = req.query;
  var soap = require('strong-soap').soap;
  var url = '../wsdl/SalesOrderQuery.wsdl';
  var requestArgs = {
    SalesOrderByElementsQuery_sync : {
      ProcessingConditions : {
        QueryHitsMaximumNumberValue : 2 , //json.QueryHitsMaximumNumberValue,
        QueryHitsUnlimitedIndicator : false,
        LastReturnedObjectID : "0000000000011ED18B8B8EA6C678AAE6"
      }
    }
  };
  var options = {
    attributesKey: '$attributes'
  };

  soap.createClient(url, options, function(err, client) {
    client.setSecurity(new soap.BasicAuthSecurity("**APP","******"));
     client.FindByElements(requestArgs, function(err, result, envelope) {
      res.send(JSON.stringify(result));
    });
  });
})
app.listen(process.env.PORT);

Please help me solve this problem.

Regards Sankaran A

jsonToXml don't serialize Date value as ISO8601 format.

I found strong-soap's XMLHandler use toString, not toISOString for serializing xsd:dateTime value in request arguments.
I think string format for xsd:dateTime is ISO8601. (format: [-]CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm])
http://books.xmlschemata.org/relaxng/ch19-77049.html

Here is my sample code:

var handler = new soap.XMLHandler();
var node = handler.jsonToXml(null, null, soap.XMLHandler.createSOAPEnvelopeDescriptor("soap"), {"date": new Date()});
var xml = node.end({pretty: true});
console.log(xml);

Expect:

<date>2017-04-18T15:24:26.871Z</date>

Actual:

<date>Wed Apr 19 2017 00:24:26 GMT+0900 (JST)</date>

Do I need to include a WSDL file?

I'm trying to recreate this PHP with node

$username = 'ADMINISTRATOR';
$password = 'ADMINISTRATOR';
$host = "localhost";
$soapport = 7878;
$command = "server info";
$client = new SoapClient(NULL,
array(
    "location" => "http://$host:$soapport/",
    "uri" => "urn:MaNGOS",
    "style" => SOAP_RPC,
    'login' => $username,
    'password' => $password
));
try {
    $result = $client->executeCommand(new SoapParam($command, "command"));
    echo "Command succeeded! Output:<br />\n";
    echo $result;
}
catch (Exception $e)
{
    echo "Command failed! Reason:<br />\n";
    echo $e->getMessage();
}

But I keep on having to pass in a wsdl url to createClient which returns 405 which this does not use WSDL any suggestions?

Wsdl correctly parsed in windows but not in ubuntu

Hi guys , thank you for this package, actually i'm a using as a alternative to node-soap to consume this wsdl , my code is simple like this :

 var soap = require("strong-soap").soap;
  soap.createClient("https://www.sunat.gob.pe/ol-it-wsconscpegem/billConsultService?wsdl", function   (err, client) {
    if (err) {
        console.error(err);
    } else { 
       console.log(client);
        client.getStatusCdr({
            serieComprobante: "",
            numeroComprobante: "",
            tipoComprobante: "",
            rucComprobante: ""
        }, function (err, response) {
            if (err) {
                console.error(err.toString());
            } else {
                //console.log(response);
            }
        })
    }
});

In windows it works , but when run the same code in ubuntu its output is : getStatusCdr is not defined , I was trying to find some error so i checked client instance:

Windows : 
 Definitions {
        services: [Object],
// Function inside services exists
Ubuntu : 
 Definitions {
        services: [],
// Function inside services doesnt exist

Weird stuff , Im using ubuntu 14.04 and strong-soap 0.1.2 , in addition i could say that node-soap output is :

Cannot find dispatch method for {}getStatusCdr

If someone could help me to find a way to check this issue i would appreciate it.

How do I get these extra headers

Dear developpers,

I do not manage to add the extra headers of soap namespace 'addressing' (see below).

Request that works:

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
  **<s:Header>
    **<a:Action s:mustUnderstand="1">/Reset</a:Action>**
    <h:chargeBoxIdentity xmlns:h="urn://Ocpp/Cp/2010/08/" xmlns="urn://Ocpp/Cp/2010/08/">EV_CHARGER_4</h:chargeBoxIdentity>
    <a:From>
      <a:Address>http://localhost/CentralSystemService12</a:Address>
    </a:From>
    <a:MessageID>urn:uuid:e540992d-e4d2-4fbe-9325-490c87fe4691</a:MessageID>
    <a:ReplyTo>
      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo>
    <a:To s:mustUnderstand="1">http://127.0.0.1:8081/ChargeBox/Ocpp</a:To>
  </s:Header>**
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <resetRequest xmlns="urn://Ocpp/Cp/2010/08/">
      <type>Hard</type>
    </resetRequest>
  </s:Body>
</s:Envelope>

Request with strong-soap

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Header/>
  <soap:Body>
    <ns1:resetRequest xmlns:ns1="urn://Ocpp/Cp/2010/08/">
      <ns1:type>Hard</ns1:type>
    </ns1:resetRequest>
  </soap:Body>
</soap:Envelope>

The Code

      // Create client
      var options = {};
      var requestArgs = {
        resetRequest: {
          type : "Hard"
        }
      };
      var requestHeader = {
        action: {
          type : "Reset"
        }
      };
      soap.createClient(chargingStationWdsl12URL, options, function(err, client) {
        client.on("request", function(request) {
          console.log(request);
        });
        // client.setEndpoint("http://127.0.0.1:8081/ChargeBox/Ocpp");
        client.Reset(requestArgs, function(err, result, envelope) {
          console.log(err.message+"\n\n");
          console.log(JSON.stringify(result));
        }, null, requestHeader);
      }, "http://127.0.0.1:8081/ChargeBox/Ocpp");

Thanks for your help in advance.

Best regards,
Serge.

Error when method does not return an object

I am using strong-soap with the vSphere API and getting an error during logout. Logout does not return an object an the stack trace I am seeing is seems to indicate that it is unable to find any elements in the output body.

Logout Method

Stack trace

/***/node_modules/strong-soap/src/client.js:304
        result = obj.Body[outputBodyDescriptor.elements[0].qname.name];
                                                          ^
TypeError: Cannot read property 'qname' of undefined
    at /***/node_modules/strong-soap/src/client.js:304:59
    at Request._callback (/***/node_modules/strong-soap/src/http.js:112:7)
    at Request.self.callback (/***/node_modules/request/request.js:187:22)
    at emitTwo (events.js:106:13)
    at Request.emit (events.js:191:7)
    at Request.<anonymous> (/***/node_modules/request/request.js:1048:10)
    at emitOne (events.js:96:13)
    at Request.emit (events.js:188:7)
    at IncomingMessage.<anonymous> (/***/node_modules/request/request.js:969:12)
    at emitNone (events.js:91:20)

substitutionGroup Handling?

I've come across a problem with strong-soap that I suspect is related to the handling of substitutionGroup in the XSD.

The XSD references an element that is a substitutionGroup of the main element in that particular XSD. When I try to reference it as part of an object, there is no namespace prefix applied. However, when I reference the original, non-substitute element, the correct prefix is applied. I had a quick look at this repo's code and it appears that something is not working correctly?

src/parser/xsd/element.js

  postProcess(defintions) {
    var schemas = defintions.schemas;
    if (this.$ref) {
      this.ref = this.resolveSchemaObject(schemas, 'element', this.$ref);
    } else if (this.$type) {
      this.type = this.resolveSchemaObject(schemas, 'type', this.$type);
    }
    **if (this.substitutionGroup) {
      this.substitutionGroup = this.resolveSchemaObject(
        schemas, 'element', this.$substitutionGroup);
    }**
  } 

Shouldn't that be this.**$**substitutionGroup ? and after the property is applied, what does strong-soap do with it?

base64 sended as ansi not utf8

hi

i m creating an EDI for my work with another enterprise, they tell me that my encoded base64 xml is encoded in ANSI on their server

i have an xml string then do

let xmlData = Buffer.from(xmlTemplate, 'utf8').toString('base64')

then just send it thru client ... how can i force utf8 ? (or they are doing a mistake when writing it as a file?)

thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.