Giter VIP home page Giter VIP logo

loopback-connector-soap's Introduction

loopback-connector-soap

CI Build Status Coverage Status

The SOAP connector enables LoopBack applications to interact with SOAP-based web services described using WSDL.

For more information, see the LoopBack documentation.

Installation

In your application root directory, enter:

$ npm install loopback-connector-soap --save

This will install the module from npm and add it as a dependency to the application's  package.json file.

Overview

There are two ways to use the SOAP connector:

  • Use the LoopBack CLI lb soap command to automatically create a set of models based on a SOAP service WSDL file. Often, this will be the easiest way to connect to a SOAP web service, but may not be suitable for all applications. For more information, see SOAP generator.
  • Write the code manually, calling the loopback-connector-soap and data source APIs directly. This is the approach illustrated here.

While both approaches use the loopback-connector-soap data source connector, they appear quite different.

SOAP data source properties

The following table describes the SOAP data source properties you can set in datasources.json.

Property Type Description
url String URL to the SOAP web service endpoint. If not present, defaults to the location attribute of the SOAP address for the service/port from the WSDL document; for example below it is http://www.webservicex.net/periodictable.asmx:
<wsdl:service name="periodictable">
<wsdl:port name="periodictableSoap" binding="tns:periodictableSoap">
<soap:address location="http://www.webservicex.net/periodictable.asmx"/>
</wsdl:port>
</wsdl:service>
wsdl String HTTP URL or local file system path to the WSDL file. Default is ?wsdl. In the example above, it would be http://www.webservicex.net/periodictable.asmx?wsdl.
wsdl_options Object Indicates additonal options to pass to the SOAP connector, for example allowing self signed certificates. For example:
wsdl_options: {
  rejectUnauthorized: false,
  strictSSL: false,
  requestCert: true,
}
wsdl_headers Object Indicates additonal headers to pass to the SOAP connector, for example for sending http authorizations header. For example:
wsdl_headers: {
  Authorization: "Basic UGVyc29uYWwgYWNjb3VudDpORVdsazIwMTVAKSEl"
}
remotingEnabled Boolean Indicates whether the operations are exposed as REST APIs. To expose or hide a specific method, override with:
<Model>.<method>.shared = true | false;
operations Object Maps WSDL binding operations to Node.js methods. Each key in the JSON object becomes the name of a method on the model. See operations property below.
security Object security configuration. See security property below.
soapHeaders Array of objects. Custom SOAP headers. An array of header properties. For example:
soapHeaders: [{
element: {myHeader: 'XYZ'}, // The XML element in JSON object format
  prefix: 'p1', // The XML namespace prefix for the header
  namespace: 'http://ns1' // The XML namespace URI for the header
}]
httpHeaders Object Custom HTTP headers. An object of header properties. For example:
httpHeaders: {
  "custom-header": "value of custom-header",
  "custom-header-2": "value of custom-header-2"
}

operations property

The operations property value is a JSON object that has a property (key) for each method being defined for the model. The corresponding value is an object with the following properties:

Property Type Description
service String WSDL service name
port String WSDL port name
operation String WSDL operation name

Here is an example operations property for the periodic table service:

operations: {
  // The key is the method name
  periodicTable: {
    service: 'periodictable', // The WSDL service name
    port: 'periodictableSoap', // The WSDL port name
    operation: 'GetAtomicNumber' // The WSDL operation name
  }
}

IMPORTANT: When using the CLI data source generator, you must supply the "stringified JSON" value for this property. For example:

{"getAtomicWeight":{"service":"periodictable","port":"periodictableSoap","operation":"GetAtomicWeight"},"getAtomicNumber":{"service":"periodictable","port":"periodictableSoap","operation":"GetAtomicNumber"}}

To generate the stringified value, you can use the following code (for example):

var operations = {
  "operations": {
    "getAtomicWeight": {
      "service": "periodictable",
      "port": "periodictableSoap",
      "operation": "GetAtomicWeight"
    },
    "getAtomicNumber": {
      "service": "periodictable",
      "port": "periodictableSoap",
      "operation": "GetAtomicNumber"
    }
  }
};

var stringifiedOps = JSON.stringify (operations);
console.log(stringifiedOps);

security property

The security property value is a JSON object with a scheme property. The other properties of the object depend on the value of scheme. For example:

security: {
    scheme: 'WS',
    username: 'test',
    password: 'testpass',
    passwordType: 'PasswordDigest'
}
Scheme Description Other properties
WS WSSecurity scheme
  • username: the user name
  • password: the password
  • passwordType: default is 'PasswordText'
BasicAuth1 Basic auth scheme
  • username: the user name
  • password: the password
ClientSSL ClientSSL scheme
  • keyPath: path to the private key file
  • certPath: path to the certificate file

1 currently unsupported, use "wsdl_headers": { "Authorization": "Basic …" }, instead, details: issue #92.

Creating a model from a SOAP data source

Instead of defining a data source with datasources.json, you can define a data source in code; for example:

ds.once('connected', function () {

  // Create the model
  var PeriodictableService = ds.createModel('PeriodictableService', {});

  // External PeriodTable WebService operation exposed as REST APIs through LoopBack
  PeriodictableService.atomicnumber = function (elementName, cb) {
    PeriodictableService.GetAtomicNumber({ElementName: elementName || 'Copper'}, function (err, response) {
      var result = response;
      cb(err, result);
    });
  };
...
}

Extending a model to wrap and mediate SOAP operations

You can extend a LoopBack model to wrap or mediate SOAP operations and define new methods. The following example simplifies the GetAtomicNumber operation:

periodictableperiodictableSoap.GetAtomicNumber = function(GetAtomicNumber, callback) {
    periodictableperiodictableSoap.GetAtomicNumber(GetAtomicNumber, function (err, response) {
      var result = response;
      callback(err, result);
    });
}

Creating a model from a SOAP data source

The SOAP connector loads WSDL documents asynchronously. As a result, the data source won't be ready to create models until it's connected. The recommended way is to use an event handler for the 'connected' event; for example as shown below.

Once you define the model, you can extend it to wrap or mediate SOAP operations and define new methods. The example below shows adding a LoopBack remote method for the SOAP service's GetAtomicNumber operation.

...
ds.once('connected', function () {

  // Create the model
  var PeriodictableService = ds.createModel('PeriodictableService', {});

  // External PeriodTable WebService operation exposed as REST APIs through LoopBack
  PeriodictableService.atomicnumber = function (elementName, cb) {
    PeriodictableService.GetAtomicNumber({ElementName: elementName || 'Copper'}, function (err, response) {
      var result = response;
      cb(err, result);
    });
  };

  // Map to REST/HTTP
  loopback.remoteMethod(
      PeriodictableService.atomicnumber, {
        accepts: [
          {arg: 'elementName', type: 'string', required: true,
            http: {source: 'query'}}
        ],
        returns: {arg: 'result', type: 'object', root: true},
        http: {verb: 'get', path: '/GetAtomicNumber'}
      }
  );
})
...

Example

For a complete example using the LoopBack SOAP connector in LoopBack 4, see SOAP calculator tutorial.

loopback-connector-soap's People

Contributors

0candy avatar achrinza avatar agnes512 avatar amir-61 avatar bajtos avatar candytangnb avatar crandmck avatar davidcheung avatar deepakrkris avatar dhmlau avatar gunjpan avatar howardengelhart avatar ilijaz avatar kjdelisle avatar marioestradarosa avatar mikevalstar avatar nabdelgadir avatar rashmihunt avatar raymondfeng avatar realetive avatar renovate[bot] avatar ritch avatar rmg avatar sam-github avatar shimks avatar siddhipai avatar simonhoibm avatar superkhau avatar virkt25 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

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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

loopback-connector-soap's Issues

[EPIC] Rewrite node-soap module

There are many issues with https://github.com/vpulim/node-soap, especially in the area of XML namespace mapping/handling based on XML schemas.

The rewrite will:

  • Use ES6
  • Add fine grained WSDL/XSD/SOAP model classes
  • Support more XSD constructs
  • Improve XSD Element/Type description
  • Improve XML/JSON conversion

Task list:

  • Initial rewrite - done by Raymond
  • Fix 87 test cases which are failing currently with Initial re-write of Raymond's code

[Question/Need Support] AuthN + AuthZ on models created with soap connector.

I already have several methods working using createModel

var WeatherService = ds.createModel('WeatherService', {});

The problem is that these models are created programmatically and i cannot create a model.json with the ACL access list maybe because these models are not created at the time that the ACL is parsed.

  1. How can I get my soap models to work with authorization and authentication?
    I am using this documentation but its only for models: http://loopback.io/doc/en/lb2/Controlling-data-access.html

  2. Can you implement authZ for the whole datasource instead per models?

Thank you very much.

You are a great team and your product is awesome.

Can't connect to soap api using loopback connector as with the soap module

var soap = require('soap');
var url = 'http://api.daft.ie/v2/wsdl.xml';

soap.createClient(url, function(err, client) {
  var args = {
    'api_key': '...', // i can send this via email if needed
  };
  client['search_sale'](args, function(err, result) {
    if (err) {
      console.log(err);
      return;
    }
    console.log(result);
  });
});
$ node soap.js
{ results:
   { search_sentence: 'properties for sale anywhere in Ireland entered by',
     pagination:
      { total_results: 35,
        results_per_page: 10,
        num_pages: 4,
        current_page: 1,
        first_on_page: 1,
        last_on_page: 10 },
     ads:
      [ [Object],
        [Object],
...
        [Object],
        [Object] ] } }
var loopback = require('loopback');
var path = require('path');

var ds = loopback.createDataSource('soap', {
    connector: 'loopback-connector-soap',
    // remotingEnabled: true,
    url: 'http://api.daft.ie/v2/wsdl.xml',
    // wsdl: 'http://api.daft.ie/v2/wsdl.xml',
    operations: {
      searchSale: {
        service: 'DaftAPIService',
        port: 'DaftAPIService',
        operation: 'search_sale'
      }
    }
  });

var args = {'api_key': '...'}; // i can send this via email if needed

// Unfortunately, the methods from the connector are mixed in asynchronously
// This is a hack to wait for the methods to be injected
ds.once('connected', function () {
// Create the model
  var DaftService = ds.createModel('DaftAPIService', {});

  DaftService.searchSale(args, function (err, response) {
    if (err) {
      console.log('error: %j', err);
      return;
    }
    console.log('response: %j', response);
  });

});
$ node daft.ie.soap.js
Connection fails:  [Error: Invalid WSDL URL: http://api.daft.ie/v2/wsdl.xml?wsdl

 Code: 404

 Response Body: <!DOCTYPE html

Nested Header XML Blocks

Hi there,

Not sure if this is a limitation/bug, or my lack of understanding.

I am trying to configure a custom header in loopback-connector-soap.

Value should look as follows:

<com:AccessToken xmlns:com="http://thalesgroup.com/RTTI/2010-11-01/ldb/commontypes">
   <com:TokenValue>nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn</com:TokenValue>
</com:AccessToken>

I can't figure out for the life of me how to format this in my loopback datasources configuration. I've got to the below but am completely stuck.

 "soapHeaders": [
      {
        "",
        "element": {"TokenValue": "nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn"},
        "prefix": "com", 
        "namespace": "http://thalesgroup.com/RTTI/2010-11-01/ldb/commontypes" 
      }

Is it possible to create the header I am looking to create?

Response Namespace Mapping

/to @raymondfeng
/cc @ShubhraKar @sumitha @cgole

When connecting to an external soap service, a loopback remote method created by the soap connector should respond as if it was a regular loopback method.

For example, calling a sharepoint service from a loopback REST api the response looks like this:

{
  "d": {
    "results": []
}

The connector should support an option that maps this to the conventional loopback response. Making the response body look like this:

[]

In general, loopback should add support for adding metadata in the body which is useful for clients that don't have access to read headers (where the metadata would otherwise exist).

Default empty namespace absent

Hello,
I have a service that has a schema that requires the following XML for actionA:

<actionA xmlns="http://ws.example.com/">
    <param1 xmlns="">ABC</uid>
    <param2 xmlns="">123</vendor>
    <param3 xmlns="">5</authentication>
</actionA>

The action element has a namespace, whereas the parameters are simply strings.
If I don't provide an empty namespace for them, they will take on the parent namespace (unless I'm misunderstanding XSD).
In any case, this is how my service expects the payload and this is how wizdler generates the skeletons, with an empty namespace.
However loopback generates the following which returns an exception:

<actionA xmlns="http://ws.example.com/">
    <param1>ABC</uid>
    <param2>123</vendor>
    <param3>5</authentication>
</actionA>

I'm dead sure that this is the only issue. When I simply add xmlns="" on the params it works.

How can I get loopback do that?

Thank you

Free to use?

Hello,
I'm looking at the pricing list and I'm not sure I understand exactly where this package fits in.
Is this free to use?

I'm mainly using the SOAP connector:

var loopback = require('loopback');

var ds = loopback.createDataSource('soap',
  {
    connector: require('./index'),
    wsdl: 'http://www.webservicex.net/currencyconvertor.asmx?wsdl' // The url to WSDL
  });

Thank you

AssertionError: setRootDir: Intl dir not found under

> require('loopback-connector-soap')
AssertionError: *** setRootDir: Intl dir not found under: /Users/rfeng/Demos/d1/node_modules/loopback-connector-soap
    at Object.setRootDir (/Users/rfeng/Demos/d1/node_modules/strong-globalize/lib/helper.js:153:3)
    at Function.SetRootDir (/Users/rfeng/Demos/d1/node_modules/strong-globalize/index.js:48:13)
    at Object.<anonymous> (/Users/rfeng/Demos/d1/node_modules/loopback-connector-soap/index.js:7:4)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)

CI failure due to external site issue

Work

  • Modify the test case to handle if the external WSDL location is unavailable http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL

  • Add new example stockquote service to strong-soap

  • Update strong-soap blog changing the code snippets and text to use stoquote web service instead of weather web service and send it to Dave Whitely.

CI log
https://cis-jenkins.swg-devops.com/job/ds/job/loopback-connector-soap~3.x/51/consoleFull#-207526304206f8fc75-e0b9-479e-b471-e8fe633361ff

Unexpected Element generated (__cachedRelations included in payload message)

Bug or feature request

  • Bug
  • Feature request

Description of feature (or steps to reproduce if bug)

I have a existed web service. and I followed the tutorial Connecting to SOAP web services. And When I invoke a simple operation. It gave me the unexpected element exception. I looked up the documentation and could not find a option to disable generating these internal properties.

I use Wireshark to capture the related packets

POST /apiws/services/API HTTP/1.1
User-Agent: loopback-connector-soap/3.0.1
Accept: text/html,application/xhtml+xml,application/xml,text/xml;q=0.9,*/*;q=0.8
Accept-Encoding: none
Accept-Charset: utf-8
Connection: close
Host: mail.ynu.edu.cn:9900
Content-Length: 17821
Content-Type: text/xml; charset=utf-8
SOAPAction: ""

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header/>
  <soap:Body>
    <ns1:authenticate xmlns:ns1="http://coremail.cn/apiws">
      <__cachedRelations/>
      <__data>
        <user_at_domain>my_mail_address</user_at_domain>
        <password>my_mail_password</password>
      </__data>
      <__dataSource/>
      <__strict>false</__strict>
      <__persisted>false</__persisted>
      <user_at_domain>my_mail_address</user_at_domain>
      <password>my_mail_password</password>
      <_initProperties>function (data, options) {
  var self = this;
  var ctor = this.constructor;

  if (typeof data !== 'undefined' &amp;&amp; data.constructor &amp;&amp;
      typeof (data.constructor) !== 'function') {
    throw new Error(g.f('Property name "{{constructor}}" is not allowed in %s data', ctor.modelName));
  }

  if (data instanceof ctor) {
    // Convert the data to be plain object to avoid pollutions
    data = data.toObject(false);
  }
  var properties = _extend({}, ctor.definition.properties);
  data = data || {};

  if (typeof ctor.applyProperties === 'function') {
    ctor.applyProperties(data);
  }

  options = options || {};
  var applySetters = options.applySetters;
  var applyDefaultValues = options.applyDefaultValues;
  var strict = options.strict;

  if (strict === undefined) {
    strict = ctor.definition.settings.strict;
  } else if (strict === 'throw') {
    g.warn('Warning: Model %s, {{strict mode: `throw`}} has been removed, ' +
      'please use {{`strict: true`}} instead, which returns' +
      '{{`Validation Error`}} for unknown properties,', ctor.modelName);
  }

  var persistUndefinedAsNull = ctor.definition.settings.persistUndefinedAsNull;

  if (ctor.hideInternalProperties) {
    // Object.defineProperty() is expensive. We only try to make the internal
    // properties hidden (non-enumerable) if the model class has the
    // `hideInternalProperties` set to true
    Object.defineProperties(this, {
      __cachedRelations: {
        writable: true,
        enumerable: false,
        configurable: true,
        value: {},
      },

      __data: {
        writable: true,
        enumerable: false,
        configurable: true,
        value: {},
      },

      // Instance level data source
      __dataSource: {
        writable: true,
        enumerable: false,
        configurable: true,
        value: options.dataSource,
      },

      // Instance level strict mode
      __strict: {
        writable: true,
        enumerable: false,
        configurable: true,
        value: strict,
      },

      __persisted: {
        writable: true,
        enumerable: false,
        configurable: true,
        value: false,
      },
    });

    if (strict) {
      Object.defineProperty(this, '__unknownProperties', {
        writable: true,
        enumerable: false,
        configrable: true,
        value: [],
      });
    }
  } else {
    this.__cachedRelations = {};
    this.__data = {};
    this.__dataSource = options.dataSource;
    this.__strict = strict;
    this.__persisted = false;
    if (strict) {
      this.__unknownProperties = [];
    }
  }

  if (options.persisted !== undefined) {
    this.__persisted = options.persisted === true;
  }

  if (data.__cachedRelations) {
    this.__cachedRelations = data.__cachedRelations;
  }

  var keys = Object.keys(data);

  if (Array.isArray(options.fields)) {
    keys = keys.filter(function(k) {
      return (options.fields.indexOf(k) != -1);
    });
  }

  var size = keys.length;
  var p, propVal;
  for (var k = 0; k &lt; size; k++) {
    p = keys[k];
    propVal = data[p];
    if (typeof propVal === 'function') {
      continue;
    }

    if (propVal === undefined &amp;&amp; persistUndefinedAsNull) {
      propVal = null;
    }

    if (properties[p]) {
      // Managed property
      if (applySetters || properties[p].id) {
        self[p] = propVal;
      } else {
        self.__data[p] = propVal;
      }
    } else if (ctor.relations[p]) {
      var relationType = ctor.relations[p].type;

      var modelTo;
      if (!properties[p]) {
        modelTo = ctor.relations[p].modelTo || ModelBaseClass;
        var multiple = ctor.relations[p].multiple;
        var typeName = multiple ? 'Array' : modelTo.modelName;
        var propType = multiple ? [modelTo] : modelTo;
        properties[p] = {name: typeName, type: propType};
        /* Issue #1252
        this.setStrict(false);
        */
      }

      // Relation
      if (relationType === 'belongsTo' &amp;&amp; propVal != null) {
        // If the related model is populated
        self.__data[ctor.relations[p].keyFrom] = propVal[ctor.relations[p].keyTo];

        if (ctor.relations[p].options.embedsProperties) {
          var fields = fieldsToArray(ctor.relations[p].properties,
            modelTo.definition.properties, modelTo.settings.strict);
          if (!~fields.indexOf(ctor.relations[p].keyTo)) {
            fields.push(ctor.relations[p].keyTo);
          }
          self.__data[p] = new modelTo(propVal, {
            fields: fields,
            applySetters: false,
            persisted: options.persisted,
          });
        }
      }

      self.__cachedRelations[p] = propVal;
    } else {
      // Un-managed property
      if (strict === false || self.__cachedRelations[p]) {
        self[p] = self.__data[p] =
          (propVal !== undefined) ? propVal : self.__cachedRelations[p];

        // Throw error for properties with unsupported names
        if (/\./.test(p)) {
          throw new Error(g.f(
            'Property names containing dot(s) are not supported. ' +
            'Model: %s, dynamic property: %s',
            this.constructor.modelName, p
          ));
        }
      } else {
        if (strict !== 'filter') {
          this.__unknownProperties.push(p);
        }
      }
    }
  }

  keys = Object.keys(properties);

  if (Array.isArray(options.fields)) {
    keys = keys.filter(function(k) {
      return (options.fields.indexOf(k) != -1);
    });
  }

  size = keys.length;

  for (k = 0; k &lt; size; k++) {
    p = keys[k];
    propVal = self.__data[p];
    var type = properties[p].type;

    // Set default values
    if (applyDefaultValues &amp;&amp; propVal === undefined) {
      var def = properties[p]['default'];
      if (def !== undefined) {
        if (typeof def === 'function') {
          if (def === Date) {
            // FIXME: We should coerce the value in general
            // This is a work around to {default: Date}
            // Date() will return a string instead of Date
            def = new Date();
          } else {
            def = def();
          }
        } else if (type.name === 'Date' &amp;&amp; def === '$now') {
          def = new Date();
        }
        // FIXME: We should coerce the value
        // will implement it after we refactor the PropertyDefinition
        self.__data[p] = propVal = def;
      }
    }

    // Set default value using a named function
    if (applyDefaultValues &amp;&amp; propVal === undefined) {
      var defn = properties[p].defaultFn;
      switch (defn) {
        case undefined:
          break;
        case 'guid':
        case 'uuid':
          // Generate a v1 (time-based) id
          propVal = uuid.v1();
          break;
        case 'uuidv4':
          // Generate a RFC4122 v4 UUID
          propVal = uuid.v4();
          break;
        case 'now':
          propVal = new Date();
          break;
        case 'shortid':
          propVal = shortid.generate();
          break;
        default:
          // TODO Support user-provided functions via a registry of functions
          g.warn('Unknown default value provider %s', defn);
      }
      // FIXME: We should coerce the value
      // will implement it after we refactor the PropertyDefinition
      if (propVal !== undefined)
        self.__data[p] = propVal;
    }

    if (propVal === undefined &amp;&amp; persistUndefinedAsNull) {
      self.__data[p] = propVal = null;
    }

    // Handle complex types (JSON/Object)
    if (!BASE_TYPES[type.name]) {
      if (typeof self.__data[p] !== 'object' &amp;&amp; self.__data[p]) {
        try {
          self.__data[p] = JSON.parse(self.__data[p] + '');
        } catch (e) {
          self.__data[p] = String(self.__data[p]);
        }
      }

      if (type.prototype instanceof ModelBaseClass) {
        if (!(self.__data[p] instanceof type) &amp;&amp;
            typeof self.__data[p] === 'object' &amp;&amp;
            self.__data[p] !== null) {
          self.__data[p] = new type(self.__data[p]);
        }
      } else if (type.name === 'Array' || Array.isArray(type)) {
        if (!(self.__data[p] instanceof List) &amp;&amp;
            self.__data[p] !== undefined &amp;&amp;
            self.__data[p] !== null) {
          self.__data[p] = List(self.__data[p], type, self);
        }
      }
    }
  }
  this.trigger('initialize');
}</_initProperties>
      <getPropertyType>function (propName) {
  return this.constructor.getPropertyType(propName);
}</getPropertyType>
      <toObject>function (onlySchema, removeHidden, removeProtected) {
  if (onlySchema === undefined) {
    onlySchema = true;
  }
  var data = {};
  var self = this;
  var Model = this.constructor;

  // if it is already an Object
  if (Model === Object) {
    return self;
  }

  var strict = this.__strict;
  var schemaLess = (strict === false) || !onlySchema;
  var persistUndefinedAsNull = Model.definition.settings.persistUndefinedAsNull;

  var props = Model.definition.properties;
  var keys = Object.keys(props);
  var propertyName, val;

  for (var i = 0; i &lt; keys.length; i++) {
    propertyName = keys[i];
    val = self[propertyName];

    // Exclude functions
    if (typeof val === 'function') {
      continue;
    }
    // Exclude hidden properties
    if (removeHidden &amp;&amp; Model.isHiddenProperty(propertyName)) {
      continue;
    }

    if (removeProtected &amp;&amp; Model.isProtectedProperty(propertyName)) {
      continue;
    }

    if (val instanceof List) {
      data[propertyName] = val.toObject(!schemaLess, removeHidden, true);
    } else {
      if (val !== undefined &amp;&amp; val !== null &amp;&amp; val.toObject) {
        data[propertyName] = val.toObject(!schemaLess, removeHidden, true);
      } else {
        if (val === undefined &amp;&amp; persistUndefinedAsNull) {
          val = null;
        }
        data[propertyName] = val;
      }
    }
  }

  if (schemaLess) {
    // Find its own properties which can be set via myModel.myProperty = 'myValue'.
    // If the property is not declared in the model definition, no setter will be
    // triggered to add it to __data
    keys = Object.keys(self);
    var size = keys.length;
    for (i = 0; i &lt; size; i++) {
      propertyName = keys[i];
      if (props[propertyName]) {
        continue;
      }
      if (propertyName.indexOf('__') === 0) {
        continue;
      }
      if (removeHidden &amp;&amp; Model.isHiddenProperty(propertyName)) {
        continue;
      }
      if (removeProtected &amp;&amp; Model.isProtectedProperty(propertyName)) {
        continue;
      }
      if (data[propertyName] !== undefined) {
        continue;
      }
      val = self[propertyName];
      if (val !== undefined) {
        if (typeof val === 'function') {
          continue;
        }
        if (val !== null &amp;&amp; val.toObject) {
          data[propertyName] = val.toObject(!schemaLess, removeHidden, true);
        } else {
          data[propertyName] = val;
        }
      } else if (persistUndefinedAsNull) {
        data[propertyName] = null;
      }
    }
    // Now continue to check __data
    keys = Object.keys(self.__data);
    size = keys.length;
    for (i = 0; i &lt; size; i++) {
      propertyName = keys[i];
      if (propertyName.indexOf('__') === 0) {
        continue;
      }
      if (data[propertyName] === undefined) {
        if (removeHidden &amp;&amp; Model.isHiddenProperty(propertyName)) {
          continue;
        }
        if (removeProtected &amp;&amp; Model.isProtectedProperty(propertyName)) {
          continue;
        }
        var ownVal = self[propertyName];
        // The ownVal can be a relation function
        val = (ownVal !== undefined &amp;&amp; (typeof ownVal !== 'function')) ? ownVal : self.__data[propertyName];
        if (typeof val === 'function') {
          continue;
        }

        if (val !== undefined &amp;&amp; val !== null &amp;&amp; val.toObject) {
          data[propertyName] = val.toObject(!schemaLess, removeHidden, true);
        } else if (val === undefined &amp;&amp; persistUndefinedAsNull) {
          data[propertyName] = null;
        } else {
          data[propertyName] = val;
        }
      }
    }
  }

  return data;
}</toObject>
      <toJSON>function () {
  return this.toObject(false, true, false);
}</toJSON>
      <fromObject>function (obj) {
  for (var key in obj) {
    this[key] = obj[key];
  }
}</fromObject>
      <reset>function () {
  var obj = this;
  for (var k in obj) {
    if (k !== 'id' &amp;&amp; !obj.constructor.dataSource.definitions[obj.constructor.modelName].properties[k]) {
      delete obj[k];
    }
  }
}</reset>
      <inspect>function (depth) {
  if (INSPECT_SUPPORTS_OBJECT_RETVAL)
    return this.__data;

  // Workaround for older versions
  // See also https://github.com/joyent/node/commit/66280de133
  return util.inspect(this.__data, {
    showHidden: false,
    depth: depth,
    colors: false,
  });
}</inspect>
      <getDataSource>function () {
  return this.__dataSource || this.constructor.dataSource;
}</getDataSource>
      <setStrict>function (strict) {
  this.__strict = strict;
}</setStrict>
      <trigger>function trigger(actionName, work, data, callback) {
  var capitalizedName = capitalize(actionName);
  var beforeHook = this.constructor['before' + capitalizedName] ||
    this.constructor['pre' + capitalizedName];
  var afterHook = this.constructor['after' + capitalizedName] ||
    this.constructor['post' + capitalizedName];
  if (actionName === 'validate') {
    beforeHook = beforeHook || this.constructor.beforeValidation;
    afterHook = afterHook || this.constructor.afterValidation;
  }
  var inst = this;

  if (actionName !== 'initialize') {
    if (beforeHook)
      deprecateHook(inst.constructor, ['before', 'pre'], capitalizedName);
    if (afterHook)
      deprecateHook(inst.constructor, ['after', 'post'], capitalizedName);
  }

  // we only call "before" hook when we have actual action (work) to perform
  if (work) {
    if (beforeHook) {
      // before hook should be called on instance with two parameters: next and data
      beforeHook.call(inst, function() {
        // Check arguments to next(err, result)
        if (arguments.length) {
          return callback &amp;&amp; callback.apply(null, arguments);
        }
        // No err &amp; result is present, proceed with the real work
        // actual action also have one param: callback
        work.call(inst, next);
      }, data);
    } else {
      work.call(inst, next);
    }
  } else {
    next();
  }

  function next(done) {
    if (afterHook) {
      afterHook.call(inst, done);
    } else if (done) {
      done.call(this);
    }
  }
}</trigger>
      <isValid>function (callback, data, options) {
  options = options || {};
  var valid = true, inst = this, wait = 0, async = false;
  var validations = this.constructor.validations;

  var reportDiscardedProperties = this.__strict &amp;&amp;
    this.__unknownProperties &amp;&amp; this.__unknownProperties.length;

  // exit with success when no errors
  if (typeof validations !== 'object' &amp;&amp; !reportDiscardedProperties) {
    cleanErrors(this);
    if (callback) {
      this.trigger('validate', function(validationsDone) {
        validationsDone.call(inst, function() {
          callback(valid);
        });
      }, data, callback);
    }
    return valid;
  }

  Object.defineProperty(this, 'errors', {
    enumerable: false,
    configurable: true,
    value: new Errors,
  });

  this.trigger('validate', function(validationsDone) {
    var inst = this,
      asyncFail = false;

    var attrs = Object.keys(validations || {});

    attrs.forEach(function(attr) {
      var attrValidations = validations[attr] || [];
      attrValidations.forEach(function(v) {
        if (v.options &amp;&amp; v.options.async) {
          async = true;
          wait += 1;
          process.nextTick(function() {
            validationFailed(inst, attr, v, options, done);
          });
        } else {
          if (validationFailed(inst, attr, v)) {
            valid = false;
          }
        }
      });
    });

    if (reportDiscardedProperties) {
      for (var ix in inst.__unknownProperties) {
        var key = inst.__unknownProperties[ix];
        var code = 'unknown-property';
        var msg = defaultMessages[code];
        inst.errors.add(key, msg, code);
        valid = false;
      }
    }

    if (!async) {
      validationsDone.call(inst, function() {
        if (valid) cleanErrors(inst);
        if (callback) {
          callback(valid);
        }
      });
    }

    function done(fail) {
      asyncFail = asyncFail || fail;
      if (--wait === 0) {
        validationsDone.call(inst, function() {
          if (valid &amp;&amp; !asyncFail) cleanErrors(inst);
          if (callback) {
            callback(valid &amp;&amp; !asyncFail);
          }
        });
      }
    }
  }, data, callback);

  if (async) {
    // in case of async validation we should return undefined here,
    // because not all validations are finished yet
    return;
  } else {
    return valid;
  }
}</isValid>
    </ns1:authenticate>
  </soap:Body>
</soap:Envelope>HTTP/1.1 500 Internal Server Error
Server: Apache-Coyote/1.1
Content-Type: text/xml;charset=UTF-8
Content-Length: 323
Date: Thu, 08 Jun 2017 02:40:26 GMT
Connection: close

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><soap:Fault><faultcode>soap:Client</faultcode><faultstring>Unmarshalling Error: 意外的元素 (uri:"", local:"__cachedRelations")。所需元素为&lt;{}password>,&lt;{}user_at_domain> </faultstring></soap:Fault></soap

Link to sample repo to reproduce issue (if bug)

Expected result

Actual result (if bug)

Additional information (Node.js version, LoopBack version, etc)

WSDL url http auth

Hi guys, I have a problem getting the WSDL because the endpoint has to http basic auth. and i don't have idea where put the credentials for to generate the api. (in the model or datasource json file)

(sorry my english).

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

github-actions
.github/workflows/continuous-integration.yml
  • actions/checkout v3
  • actions/setup-node v4
  • actions/checkout v3
  • actions/setup-node v4
  • actions/checkout v3
  • github/codeql-action v3
  • github/codeql-action v3
npm
package.json
  • debug ^4.0.1
  • request ^2.88.0
  • strong-globalize ^6.0.5
  • strong-soap ^4.0.0
  • @commitlint/cli ^19.0.0
  • @commitlint/config-conventional ^19.0.0
  • loopback-datasource-juggler ^5.0.0
  • mocha ^10.1.0
  • nyc ^15.1.0
  • should ^13.2.3
  • node >=18
travis
.travis.yml
  • node 10
  • node 12
  • node 14
  • node 16

  • Check this box to trigger a request for Renovate to run again on this repository

node-soap 0.9.4 doesn't work

Hi,
The new release from node-soap is not working with loopback-connector-soap
Can you temporarily fixed the version to 0.9.3 ?

Thanks,

order of input params maintained?

I'm having incredible issues with node-soap atm, since input param order is not guaranteed therefore tripping sequence encodings in wsdl.

Is input param order guaranteed with loopback-connector?

Ability to define SOAP datasources and models using loopback's json definition format

It seems the only way to define a SOAP datasource and model at the moment is to do it in a boot script, which is inconsistent with the way that the rest of our app is defined using Loopback's json definition files. This means that the definition of our datasources and models is now spread around the codebase rather than being consolidated in a single place (/datasources.json, /model-config.json and /common/models), which isn't ideal.

Can the soap connector be made to support the standard way of defining models and datasources too?

Attachments?

Does this connector support attachments? I have a soap endpoint that I am hitting, but the node-soap library that I'm using doesn't support attachments. Is there any way to do that here?

Cheers.

TypeError: Cannot read property 'pfx' of null

Security enables throws 'pfx' of null from soap-connector.js:100:20.

To enable security

'security': {
        'scheme': 'ClientSSL'
}
/lib/soap-connector.js:100
            if (sec.pfx) {
                   ^

TypeError: Cannot read property 'pfx' of null
    at /Volumes/Data/work/OpenBanking/git/aisp/ob-aisp-account-info-enterprise-direct-api/node_modules/loopback-connector-soap/lib/soap-connector.js:100:20

in soap-connector.js line no 79 var sec = null; and line no 100 check for if (sec.pfx) {} so its throws error.

line no 79 need to changes as var sec = {};

I fixed the issue, I will give the pull request

I get a xml, but I don't know how convert to json?

My WCF xml is:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/ICustomerActionService/Register</Action>
  </s:Header>
  <s:Body>
    <Register xmlns="http://tempuri.org/">
      <registerInfo xmlns:d4p1="http://schemas.datacontract.org/2004/07/MYun.BPC.Contract.CustomerMgmt.Data" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <d4p1:BirthDay>2016-01-15T13:30:00</d4p1:BirthDay>
        <d4p1:CellPhoneNo>123</d4p1:CellPhoneNo>
        <d4p1:CustomerFrom i:nil="true" />
        <d4p1:CustomerLevel>0</d4p1:CustomerLevel>
        <d4p1:CustomerSource>0</d4p1:CustomerSource>
        <d4p1:Gender>Male</d4p1:Gender>
        <d4p1:HeadPicture i:nil="true" />
        <d4p1:LoginPassword>123</d4p1:LoginPassword>
        <d4p1:Name>123</d4p1:Name>
        <d4p1:StoreName i:nil="true" />
        <d4p1:WangwangNo i:nil="true" />
      </registerInfo>
      <invitationCode>123</invitationCode>
    </Register>
  </s:Body>
</s:Envelope>

node-soap v0.6.1

Can I suggest you to update node-soap to v0.6.1 ?
I need the enhancement $xml that allow to give a plain XML.

Thanks

RangeError: Maximum call stack size exceeded

I am getting a stack size error while using the CLI lb soap command, while trying to access my OMS web services. My lb common models have already been created via the mssql connector, if that matters at all. The OMS can be viewed at https://smapromail.cgraphics.com/pmomsws/oms.asmx?WSDL.

      throw er; // Unhandled 'error' event
      ^

RangeError: Maximum call stack size exceeded
    at Array.indexOf (<anonymous>)
    at checkAndConvertToNumber (/usr/local/lib/node_modules/loopback-cli/node_modules/loopback-soap/lib/codegen/generator-soap.js:438:25)
    at buildElementProperties (/usr/local/lib/node_modules/loopback-cli/node_modules/loopback-soap/lib/codegen/generator-soap.js:321:13)
    at buildElementProperties (/usr/local/lib/node_modules/loopback-cli/node_modules/loopback-soap/lib/codegen/generator-soap.js:327:7)
    at buildElementProperties (/usr/local/lib/node_modules/loopback-cli/node_modules/loopback-soap/lib/codegen/generator-soap.js:327:7)
    at buildElementProperties (/usr/local/lib/node_modules/loopback-cli/node_modules/loopback-soap/lib/codegen/generator-soap.js:327:7)
    at buildElementProperties (/usr/local/lib/node_modules/loopback-cli/node_modules/loopback-soap/lib/codegen/generator-soap.js:327:7)
    at buildElementProperties (/usr/local/lib/node_modules/loopback-cli/node_modules/loopback-soap/lib/codegen/generator-soap.js:327:7)
    at buildElementProperties (/usr/local/lib/node_modules/loopback-cli/node_modules/loopback-soap/lib/codegen/generator-soap.js:327:7)
    at buildElementProperties (/usr/local/lib/node_modules/loopback-cli/node_modules/loopback-soap/lib/codegen/generator-soap.js:327:7)
    at buildElementProperties (/usr/local/lib/node_modules/loopback-cli/node_modules/loopback-soap/lib/codegen/generator-soap.js:327:7)
    at buildElementProperties (/usr/local/lib/node_modules/loopback-cli/node_modules/loopback-soap/lib/codegen/generator-soap.js:327:7)
    at buildElementProperties (/usr/local/lib/node_modules/loopback-cli/node_modules/loopback-soap/lib/codegen/generator-soap.js:327:7)
    at buildElementProperties (/usr/local/lib/node_modules/loopback-cli/node_modules/loopback-soap/lib/codegen/generator-soap.js:327:7)
    at buildElementProperties (/usr/local/lib/node_modules/loopback-cli/node_modules/loopback-soap/lib/codegen/generator-soap.js:327:7)
    at buildElementProperties (/usr/local/lib/node_modules/loopback-cli/node_modules/loopback-soap/lib/codegen/generator-soap.js:327:7)
Emitted 'error' event at:
    at Immediate.<anonymous> (/usr/local/lib/node_modules/loopback-cli/node_modules/yeoman-generator/lib/base.js:446:16)
    at runCallback (timers.js:696:18)
    at tryOnImmediate (timers.js:667:5)
    at processImmediate (timers.js:649:5)
    at process.topLevelDomainCallback (domain.js:121:23)

Additional information

darwin x64 10.3.0

├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]

NPM hosted version needs updating

The latest version of this package currently on NPM is behind several commits and doesn’t work. The fix that it absolutely needs was done in cfab932. As it stands now, the _methodName method is broken on NPM.

[BUG] invalid message definition for rpc style binding

When a soap method has no parameters, the soap nodejs client fails and return an error:

invalid message definition for rpc style binding

I think i hit that problem:

http://stackoverflow.com/questions/22021944/node-js-soap-invalid-message-definition-for-rpc-style-binding

I did a project to reproduce the problem:
GetMasterList is a method that takes no arguments and return only one.

https://github.com/mercuriete/loopback-example-connector/tree/soap

steps to reproduce:

  1. git clone -b soap https://github.com/mercuriete/loopback-example-connector.git
  2. npm install
  3. node weather-rest.js
  4. go to loopback-explorer
  5. try to send something to GetMasterList
  6. You get the error.

Im using latest libraries as you can see in package.json

I need support in order to workaround this problem if is possible.

Thanks.

PS: Your work is awesome.

Bump version to 1.3.0 ?

Hi,
Due to the upgrade of node-soap 0.8->0.9, maybe we should also bump the version of the connector ?

definitions is not defined

Hello, I'm having the following problem:

 ...\node_modules\strong-soap\src\parser\wsdl\operation.js:74
        headers.addElement(part.element.describe(definitions));
                                                 ^

ReferenceError: definitions is not defined
    at ...\node_modules\strong-soap\src\parser\wsdl\operation.js:74:50

What I'm trying:

var loopback = require('loopback');
var path = require('path');
var lcs = require('loopback-connector-soap');

var ds = loopback.createDataSource('soap', {
		connector : lcs,
		remotingEnabled : false,
		wsdl : '.../saphws.asmx?WSDL' //It's valid, just ommited the address
	});

ds.once('connected', function () {
	var myservice = ds.createModel('SAPHWS', {});

	myservice.LoadStuff({
		dbUser : '...',
		codServidor : 1
	}, function (err, response) {
		console.log("Retorno WS : %j", response);
		var result = (!err && response.LoadStuffResult.Success) ?
		response.LoadStuffResult : [];
		cb(err, result);
	});
});

The error occurs when I call myservice.LoadStuff(...).

A valid service body is:

<x:Envelope xmlns:x="http://schemas.xmlsoap.org/soap/envelope/" xmlns:www="...">
    <x:Header>
        <www:WsAuth>
            <www:usr>abc</www:usr>
            <www:pas>pass</www:pas>
        </www:WsAuth>
    </x:Header>
    <x:Body>
        <www:LoadStuff>
            <www:dbuser>...</www:dbuser>
            <www:codServidor>1</www:codServidor>
        </www:LoadStuff>
    </x:Body>
</x:Envelope>

Do you have any ideas?
Thanks in advance!

Problem consuming a SOAP WCF

is there a way to consume WCF using this SOAP connector?

i'm facing the below problem:

node_modules/soap/lib/client.js:233
result = obj.Body[output.$name];

TypeError: Cannot read property 'ConsultarPorEmailResponse' of undefined

Some clues?
Very thx!

Escape special characters

Description:
Whenever you send a json with bad characters for xml you get an error because the <,> are forbiden in xml. (usually you get the error on the response of the backend)

Solution:
Go recursive to all json and replace <, > and others chars to the equivalent in xml.

Reproducible always. version "loopback-connector-soap": "^2.5.0",

Thank you very much.
Your work is awesome!

application does not start if a wsdl is down

Hi i have a API with loopback versión 3.0 when execute NODE_ENV=local slc run

Connection failed: Error: Invalid WSDL URL: http://myurlservice.com/Service.asmx?wsdl

 Code: 503

 Response Body: "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\"http://www.w3.org/TR/html4/strict.dtd\">\r\n<HTML><HEAD><TITLE>Service Unavailable</TITLE>\r\n<META HTTP-EQUIV=\"Content-Type\" Content=\"text/html; charset=us-ascii\"></HEAD>\r\n<BODY><h2>Service Unavailable</h2>\r\n<hr><p>HTTP Error 503. The service is unavailable.</p>\r\n</BODY></HTML>\r\n"

It will be retried for the next request

events.js:183
      throw er; // Unhandled 'error' event

I need the application to start even if the service is not available

wsdl_options property not being used

It appears that the wsdl_options property is not being interpreted. When I try to connect to a soap service over HTTPS, I receive the following error with the strictSSL and rejectUnauthorized properties set to false :
{ "error": { "statusCode": 500, "name": "Error", "message": "unable to verify the first certificate", "code": "UNABLE_TO_VERIFY_LEAF_SIGNATURE", "stack": "Error: unable to verify the first certificate\n at Error (native)\n at TLSSocket.<anonymous> (_tls_wrap.js:1092:38)\n at emitNone (events.js:86:13)\n at TLSSocket.emit (events.js:185:7)\n at TLSSocket._finishInit (_tls_wrap.js:610:8)\n at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:440:38)" } }

However, if I add these as options to the ClientSSL security param then the certificate is bypassed, as expected. From looking at the implementation in soap-connector.js is appears that the wsdl_options are possibly not being interpreted.

Steps to Reproduce

  1. Attempt to connect to a https soap service, bypassing the certificate with the following wsdl_options params:
    { "strictSSL": false, "rejectUnauthorized": false }

using promise when datasource is ready

Hi ,
is it possible to return a promise when ds is ready to create model as against using the ds.once and wrapping supposed method calls that (could be exposed to other modules) inside ds.once() . for instance

var ds=loopback.createDataSource('soap',
{
connector: require('../index'),
remotingEnabled: true,
// wsdl: 'http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL' // The url to WSDL
wsdl: path.join(__dirname, './weather.wsdl')
}).then(function(){
return ds.createModel('WeatherService', {});
});

loopback soap connector - add xmlns to a namespace

Hello,
Is it possible to add a xmlns attribute to a specific namespace with loopback soap connector ?
Issue : when converting a json to xml, loopback doesn't add the xmlns attribute to a tag which is an array.

How to send dynamic values in soap headers?

I am only able to set the header values for the soap header when the loopback application boots. Is there any way to set the header on the fly when the call happens depending on some logic?

How to print soap request which is sent to SOAP server?

i am using this code, its working fine for me.

    var service=ds.createModel('service',{});
        service.GetBundleList({getBundleList : {CountryCode:'USA',BrandCode:'UVA',LanguageCode:'En',ICCID:'8901260842140591893',MSISDN:'14252833121'}},function(err,response){
          console.log(response);
        });

It printing the response but i want to print the request to actually determine the payload of SOAP request.

soap headers

I would like to pass soap headers in this format:

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
soap:Header

< user >user</ user >
< password >password</ password >

</soap:Header>
soap:Body

</soap:Body>
</soap:Envelope>

this is how I am providing:
soapHeaders: [{
element: {inCredentials:{user: 'user', password: 'password'}},
namespace: 'http://sss'
}]

but for some reason it is not working and giving me invalid credentials in header when calling api, I test the API in postman and works fine. Am I doing something wrong in the soapheaders?

The `ModelDefinition` instance is not valid; `name` is invalid

I am getting an error generating from the following WSDL: https://access.uat.oup.com/eacWebService/services/access-service-v2.0.wsdl

Creating model definition for soap_access-service-v2.0Soap11...
Creating model definition for ValidatePasswordCredentialsRequest...
Creating model definition for PasswordCredential...
Creating model definition for ValidatePasswordCredentialsResponse...
Creating model definition for GetFullUserEntitlementsRequest...
Creating model definition for wsUserId...
Creating model definition for Identifier...
Creating model definition for InternalIdentifier...
Creating model definition for ExternalIdentifier...
Creating model definition for GetFullUserEntitlementsResponse...
Creating model definition for ErrorStatus...
Updating model definition for User...
Creating model definition for Identifiers...
Creating model definition for FullProductEntitlementGroup...
Creating model definition for FullProductEntitlement...
Creating model definition for FullProductDetails...
Creating model definition for LicenceDetails...
Creating model definition for ExtendedLicenceDetails...
Creating model definition for RollingLicenceDetail...
Creating model definition for ConcurrencyLicenceDetails...
Creating model definition for UsageLicenceDetails...
Creating model definition for LicenceInfo...
Creating model definition for AuthenticateRequest...
Creating model definition for Credential...
Creating model definition for IPCredential...
Creating model definition for AuthenticateResponse...
Creating model definition for CreateUserAccountRequest...
Creating model definition for CreateUser...
Creating model definition for CreateUserAccountResponse...
Creating model definition for userStatusType...
Creating model definition for UpdateUserAccountRequest...
Creating model definition for UpdateUser...
Creating model definition for UpdateUserAccountResponse...
Validation error: invalid ModelDefinition
 - name: is invalid

events.js:163
      throw er; // Unhandled 'error' event
      ^
ValidationError: The `ModelDefinition` instance is not valid. Details: `name` is invalid (value: "soap_access-service-v2.0Soap11").
 

Any clues? Thanks

SOAP connector - correct examples, etc, in README

README is there for a good reason. Mammoths like IBM and MS fell behind & now piggy backing on open source to pollute the waters.

Has anyone successfully ran examples?

Is it worth digging into it or just use node to write custom connector?

Error: Could not find package.json up from: /

Getting the following error trying to run this module behind Passenger Nginx after upgrading to the latest version:

/home/app/node_modules/loopback-connector-soap/node_modules/strongloop-license/lib/approot.js:22
throw new Error('Could not find package.json up from: ' + dir);
^
Error: Could not find package.json up from: /
at find (/home/app/node_modules/loopback-connector-soap/node_modules/strongloop-license/lib/approot.js:22:11)
at find (/home/app/node_modules/loopback-connector-soap/node_modules/strongloop-license/lib/approot.js:27:10)
at find (/home/app/node_modules/loopback-connector-soap/node_modules/strongloop-license/lib/approot.js:27:10)
at find (/home/app/node_modules/loopback-connector-soap/node_modules/strongloop-license/lib/approot.js:27:10)
at find (/home/app/node_modules/loopback-connector-soap/node_modules/strongloop-license/lib/approot.js:27:10)
at readRootPackage (/home/app/node_modules/loopback-connector-soap/node_modules/strongloop-license/lib/approot.js:31:13)
at Object. (/home/app/node_modules/loopback-connector-soap/node_modules/strongloop-license/index.js:14:18)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Module.require (module.js:365:17)
at require (module.js:384:17)
at Object. (/home/app/node_modules/loopback-connector-soap/index.js:1:63)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)

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.