soap 0.20.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/.editorconfig +23 -23
  2. package/.jshintrc +29 -29
  3. package/.travis.yml +22 -22
  4. package/CONTRIBUTING.md +52 -58
  5. package/History.md +52 -2
  6. package/LICENSE +7 -7
  7. package/PUBLISHING.md +28 -28
  8. package/Readme.md +1062 -931
  9. package/coverage/coverage.json +1 -0
  10. package/coverage/lcov-report/base.css +212 -0
  11. package/coverage/lcov-report/index.html +119 -0
  12. package/coverage/lcov-report/node-soap/index.html +93 -0
  13. package/coverage/lcov-report/node-soap/index.js.html +74 -0
  14. package/coverage/lcov-report/node-soap/lib/client.js.html +1001 -0
  15. package/coverage/lcov-report/node-soap/lib/http.js.html +416 -0
  16. package/coverage/lcov-report/node-soap/lib/index.html +171 -0
  17. package/coverage/lcov-report/node-soap/lib/nscontext.js.html +734 -0
  18. package/coverage/lcov-report/node-soap/lib/security/BasicAuthSecurity.js.html +137 -0
  19. package/coverage/lcov-report/node-soap/lib/security/BearerSecurity.js.html +134 -0
  20. package/coverage/lcov-report/node-soap/lib/security/ClientSSLSecurity.js.html +296 -0
  21. package/coverage/lcov-report/node-soap/lib/security/ClientSSLSecurityPFX.js.html +218 -0
  22. package/coverage/lcov-report/node-soap/lib/security/WSSecurity.js.html +278 -0
  23. package/coverage/lcov-report/node-soap/lib/security/index.html +158 -0
  24. package/coverage/lcov-report/node-soap/lib/security/index.js.html +92 -0
  25. package/coverage/lcov-report/node-soap/lib/server.js.html +1139 -0
  26. package/coverage/lcov-report/node-soap/lib/soap.js.html +314 -0
  27. package/coverage/lcov-report/node-soap/lib/utils.js.html +161 -0
  28. package/coverage/lcov-report/node-soap/lib/wsdl.js.html +6275 -0
  29. package/coverage/lcov-report/prettify.css +1 -0
  30. package/coverage/lcov-report/prettify.js +1 -0
  31. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  32. package/coverage/lcov-report/sorter.js +158 -0
  33. package/coverage/lcov.info +3325 -0
  34. package/index.js +3 -3
  35. package/lib/client.js +434 -425
  36. package/lib/http.js +129 -129
  37. package/lib/nscontext.js +223 -223
  38. package/lib/security/BasicAuthSecurity.js +24 -24
  39. package/lib/security/BearerSecurity.js +23 -23
  40. package/lib/security/ClientSSLSecurity.js +82 -65
  41. package/lib/security/ClientSSLSecurityPFX.js +51 -51
  42. package/lib/security/WSSecurity.js +90 -90
  43. package/lib/security/WSSecurityCert.js +78 -78
  44. package/lib/security/index.js +10 -10
  45. package/lib/security/templates/wsse-security-header.ejs +12 -12
  46. package/lib/security/templates/wsse-security-token.ejs +3 -3
  47. package/lib/server.js +474 -444
  48. package/lib/soap.d.ts +220 -0
  49. package/lib/soap.js +110 -110
  50. package/lib/utils.js +30 -30
  51. package/lib/wsdl.js +2272 -2234
  52. package/package.json +8 -8
  53. package/soap-stub.js +148 -148
  54. package/.npmignore +0 -2
package/Readme.md CHANGED
@@ -1,931 +1,1062 @@
1
- # Soap [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Coveralls Status][coveralls-image]][coveralls-url] [![Gitter chat][gitter-image]][gitter-url]
2
-
3
- > A SOAP client and server for node.js.
4
-
5
- This module lets you connect to web services using SOAP. It also provides a server that allows you to run your own SOAP services.
6
-
7
- <!-- Run `npm run toc` to update below section -->
8
- <!-- START doctoc generated TOC please keep comment here to allow auto update -->
9
- <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
10
-
11
-
12
- - [Features:](#features)
13
- - [Install](#install)
14
- - [Why can't I file an issue?](#why-cant-i-file-an-issue)
15
- - [Where can I find help?](#where-can-i-find-help)
16
- - [Module](#module)
17
- - [soap.createClient(url[, options], callback) - create a new SOAP client from a WSDL url. Also supports a local filesystem path.](#soapcreateclienturl-options-callback---create-a-new-soap-client-from-a-wsdl-url-also-supports-a-local-filesystem-path)
18
- - [soap.createClientAsync(url[, options]) - create a new SOAP client from a WSDL url. Also supports a local filesystem path.](#soapcreateclientasyncurl-options---create-a-new-soap-client-from-a-wsdl-url-also-supports-a-local-filesystem-path)
19
- - [soap.listen(*server*, *path*, *services*, *wsdl*) - create a new SOAP server that listens on *path* and provides *services*.](#soaplistenserver-path-services-wsdl---create-a-new-soap-server-that-listens-on-path-and-provides-services)
20
- - [Options](#options)
21
- - [Server Logging](#server-logging)
22
- - [Server Events](#server-events)
23
- - [SOAP Fault](#soap-fault)
24
- - [Server security example using PasswordDigest](#server-security-example-using-passworddigest)
25
- - [Server connection authorization](#server-connection-authorization)
26
- - [SOAP Headers](#soap-headers)
27
- - [Received SOAP Headers](#received-soap-headers)
28
- - [Outgoing SOAP Headers](#outgoing-soap-headers)
29
- - [Client](#client)
30
- - [Client.describe() - description of services, ports and methods as a JavaScript object](#clientdescribe---description-of-services-ports-and-methods-as-a-javascript-object)
31
- - [Client.setSecurity(security) - use the specified security protocol](#clientsetsecuritysecurity---use-the-specified-security-protocol)
32
- - [Client.*method*(args, callback) - call *method* on the SOAP service.](#clientmethodargs-callback---call-method-on-the-soap-service)
33
- - [Client.*method*Async(args) - call *method* on the SOAP service.](#clientmethodasyncargs---call-method-on-the-soap-service)
34
- - [Client.*service*.*port*.*method*(args, callback[, options[, extraHeaders]]) - call a *method* using a specific *service* and *port*](#clientserviceportmethodargs-callback-options-extraheaders---call-a-method-using-a-specific-service-and-port)
35
- - [Overriding the namespace prefix](#overriding-the-namespace-prefix)
36
- - [Client.*lastRequest* - the property that contains last full soap request for client logging](#clientlastrequest---the-property-that-contains-last-full-soap-request-for-client-logging)
37
- - [Client.setEndpoint(url) - overwrite the SOAP service endpoint address](#clientsetendpointurl---overwrite-the-soap-service-endpoint-address)
38
- - [Client Events](#client-events)
39
- - [Security](#security)
40
- - [BasicAuthSecurity](#basicauthsecurity)
41
- - [BearerSecurity](#bearersecurity)
42
- - [ClientSSLSecurity](#clientsslsecurity)
43
- - [WSSecurity](#wssecurity)
44
- - [WSSecurityCert](#wssecuritycert)
45
- - [Handling XML Attributes, Value and XML (wsdlOptions).](#handling-xml-attributes-value-and-xml-wsdloptions)
46
- - [Overriding the `value` key](#overriding-the-value-key)
47
- - [Overriding the `xml` key](#overriding-the-xml-key)
48
- - [Overriding the `attributes` key](#overriding-the-attributes-key)
49
- - [Specifying the exact namespace definition of the root element](#specifying-the-exact-namespace-definition-of-the-root-element)
50
- - [Custom Deserializer](#custom-deserializer)
51
- - [Handling "ignored" namespaces](#handling-ignored-namespaces)
52
- - [Handling "ignoreBaseNameSpaces" attribute](#handling-ignorebasenamespaces-attribute)
53
- - [soap-stub](#soap-stub)
54
- - [Example](#example)
55
- - [Contributors](#contributors)
56
-
57
- <!-- END doctoc generated TOC please keep comment here to allow auto update -->
58
-
59
- ## Features:
60
-
61
- * Very simple API
62
- * Handles both RPC and Document schema types
63
- * Supports multiRef SOAP messages (thanks to [@kaven276](https://github.com/kaven276))
64
- * Support for both synchronous and asynchronous method handlers
65
- * WS-Security (currently only UsernameToken and PasswordText encoding is supported)
66
- * Supports [express](http://expressjs.com/) based web server(body parser middleware can be used)
67
-
68
- ## Install
69
-
70
- Install with [npm](http://github.com/isaacs/npm):
71
-
72
- ```
73
- npm install soap
74
- ```
75
-
76
- ## Why can't I file an issue?
77
-
78
- We've disabled issues in the repository and are now solely reviewing pull requests. The reasons why we disabled issues can be found here [#731](https://github.com/vpulim/node-soap/pull/731).
79
-
80
- ## Where can I find help?
81
-
82
- Community support can be found on gitter:
83
-
84
- [![Gitter chat][gitter-image]][gitter-url]
85
-
86
- If you're looking for professional help you can contact the maintainers through this [google form](https://docs.google.com/forms/d/e/1FAIpQLSdj5EXxd5flcukLInmpFQhEvQYeERaReFFh9F0nqC_4EUmeLg/viewform).
87
-
88
- ## Module
89
-
90
- ### soap.createClient(url[, options], callback) - create a new SOAP client from a WSDL url. Also supports a local filesystem path.
91
-
92
- ``` javascript
93
- var soap = require('soap');
94
- var url = 'http://example.com/wsdl?wsdl';
95
- var args = {name: 'value'};
96
- soap.createClient(url, function(err, client) {
97
- client.MyFunction(args, function(err, result) {
98
- console.log(result);
99
- });
100
- });
101
- ```
102
- This client has a built in WSDL cache. You can use the `disableCache` option to disable it.
103
-
104
- ### soap.createClientAsync(url[, options]) - create a new SOAP client from a WSDL url. Also supports a local filesystem path.
105
-
106
- ``` javascript
107
- var soap = require('soap');
108
- var url = 'http://example.com/wsdl?wsdl';
109
- var args = {name: 'value'};
110
- soap.createClientAsync(url).then((client) => {
111
- return client.MyFunctionAsync(args);
112
- }).then((result) => {
113
- console.log(result);
114
- });
115
- ```
116
-
117
- This client has a built in WSDL cache. You can use the `disableCache` option to disable it.
118
-
119
- #### Options
120
-
121
- The `options` argument allows you to customize the client with the following properties:
122
-
123
- - endpoint: to override the SOAP service's host specified in the `.wsdl` file.
124
- - envelopeKey: to set specific key instead of `<pre><<b>soap</b>:Body></<b>soap</b>:Body></pre>`.
125
- - escapeXML: escape special XML characters in SOAP message (e.g. `&`, `>`, `<` etc), default: `true`.
126
- - suppressStack: suppress the full stack trace for error messages.
127
- - returnFault: return an `Invalid XML` SOAP fault on a bad request, default: `false`.
128
- - forceSoap12Headers: to set proper headers for SOAP v1.2.
129
- - httpClient: to provide your own http client that implements `request(rurl, data, callback, exheaders, exoptions)`.
130
- - request: to override the [request](https://github.com/request/request) module.
131
- - wsdl_headers: custom HTTP headers to be sent on WSDL requests.
132
- - wsdl_options: custom options for the request module on WSDL requests.
133
- - disableCache: don't cache WSDL files, request them every time.
134
-
135
- 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.
136
-
137
- ### soap.listen(*server*, *path*, *services*, *wsdl*) - create a new SOAP server that listens on *path* and provides *services*.
138
- *server* can be a [http](https://nodejs.org/api/http.html) Server or [express](http://expressjs.com/) framework based server
139
- *wsdl* is an xml string that defines the service.
140
-
141
- ``` javascript
142
- var myService = {
143
- MyService: {
144
- MyPort: {
145
- MyFunction: function(args) {
146
- return {
147
- name: args.name
148
- };
149
- },
150
-
151
- // This is how to define an asynchronous function.
152
- MyAsyncFunction: function(args, callback) {
153
- // do some work
154
- callback({
155
- name: args.name
156
- });
157
- },
158
-
159
- // This is how to receive incoming headers
160
- HeadersAwareFunction: function(args, cb, headers) {
161
- return {
162
- name: headers.Token
163
- };
164
- },
165
-
166
- // You can also inspect the original `req`
167
- reallyDetailedFunction: function(args, cb, headers, req) {
168
- console.log('SOAP `reallyDetailedFunction` request from ' + req.connection.remoteAddress);
169
- return {
170
- name: headers.Token
171
- };
172
- }
173
- }
174
- }
175
- };
176
-
177
- var xml = require('fs').readFileSync('myservice.wsdl', 'utf8');
178
-
179
- //http server example
180
- var server = http.createServer(function(request,response) {
181
- response.end('404: Not Found: ' + request.url);
182
- });
183
-
184
- server.listen(8000);
185
- soap.listen(server, '/wsdl', myService, xml);
186
-
187
- //express server example
188
- var app = express();
189
- //body parser middleware are supported (optional)
190
- app.use(bodyParser.raw({type: function(){return true;}, limit: '5mb'}));
191
- app.listen(8001, function(){
192
- //Note: /wsdl route will be handled by soap module
193
- //and all other routes & middleware will continue to work
194
- soap.listen(app, '/wsdl', myService, xml);
195
- });
196
-
197
- ```
198
-
199
- ### Options
200
- You can pass in server and [WSDL Options](#handling-xml-attributes-value-and-xml-wsdloptions)
201
- using an options hash.
202
-
203
- ``` javascript
204
- var xml = require('fs').readFileSync('myservice.wsdl', 'utf8');
205
-
206
- soap.listen(server, {
207
- // Server options.
208
- path: '/wsdl',
209
- services: myService,
210
- xml: xml,
211
-
212
- // WSDL options.
213
- attributesKey: 'theAttrs',
214
- valueKey: 'theVal',
215
- xmlKey: 'theXml'
216
- });
217
- ```
218
-
219
- ### Server Logging
220
-
221
- If the `log` method is defined it will be called with 'received' and 'replied'
222
- along with data.
223
-
224
- ``` javascript
225
- server = soap.listen(...)
226
- server.log = function(type, data) {
227
- // type is 'received' or 'replied'
228
- };
229
- ```
230
-
231
- ### Server Events
232
-
233
- Server instances emit the following events:
234
-
235
- * request - Emitted for every received messages.
236
- The signature of the callback is `function(request, methodName)`.
237
- * headers - Emitted when the SOAP Headers are not empty.
238
- The signature of the callback is `function(headers, methodName)`.
239
-
240
- The sequence order of the calls is `request`, `headers` and then the dedicated
241
- service method.
242
-
243
- ### SOAP Fault
244
-
245
- A service method can reply with a SOAP Fault to a client by `throw`ing an
246
- object with a `Fault` property.
247
-
248
- ``` javascript
249
- throw {
250
- Fault: {
251
- Code: {
252
- Value: 'soap:Sender',
253
- Subcode: { value: 'rpc:BadArguments' }
254
- },
255
- Reason: { Text: 'Processing Error' }
256
- }
257
- };
258
- ```
259
-
260
- To change the HTTP statusCode of the response include it on the fault. The statusCode property will not be put on the xml message.
261
-
262
- ``` javascript
263
- throw {
264
- Fault: {
265
- Code: {
266
- Value: 'soap:Sender',
267
- Subcode: { value: 'rpc:BadArguments' }
268
- },
269
- Reason: { Text: 'Processing Error' },
270
- statusCode: 500
271
- }
272
- };
273
- ```
274
-
275
- ### Server security example using PasswordDigest
276
-
277
- If `server.authenticate` is not defined then no authentication will take place.
278
-
279
- ``` javascript
280
- server = soap.listen(...)
281
- server.authenticate = function(security) {
282
- var created, nonce, password, user, token;
283
- token = security.UsernameToken, user = token.Username,
284
- password = token.Password, nonce = token.Nonce, created = token.Created;
285
- return user === 'user' && password === soap.passwordDigest(nonce, created, 'password');
286
- };
287
- ```
288
-
289
- ### Server connection authorization
290
-
291
- The `server.authorizeConnection` method is called prior to the soap service method.
292
- If the method is defined and returns `false` then the incoming connection is
293
- terminated.
294
-
295
- ``` javascript
296
- server = soap.listen(...)
297
- server.authorizeConnection = function(req) {
298
- return true; // or false
299
- };
300
- ```
301
-
302
-
303
- ## SOAP Headers
304
-
305
- ### Received SOAP Headers
306
-
307
- A service method can look at the SOAP headers by providing a 3rd arguments.
308
-
309
- ``` javascript
310
- {
311
- HeadersAwareFunction: function(args, cb, headers) {
312
- return {
313
- name: headers.Token
314
- };
315
- }
316
- }
317
- ```
318
-
319
- It is also possible to subscribe to the 'headers' event.
320
- The event is triggered before the service method is called, and only when the
321
- SOAP Headers are not empty.
322
-
323
- ``` javascript
324
- server = soap.listen(...)
325
- server.on('headers', function(headers, methodName) {
326
- // It is possible to change the value of the headers
327
- // before they are handed to the service method.
328
- // It is also possible to throw a SOAP Fault
329
- });
330
- ```
331
-
332
- First parameter is the Headers object;
333
- second parameter is the name of the SOAP method that will called
334
- (in case you need to handle the headers differently based on the method).
335
-
336
- ### Outgoing SOAP Headers
337
-
338
- Both client & server can define SOAP headers that will be added to what they send.
339
- They provide the following methods to manage the headers.
340
-
341
-
342
- #### *addSoapHeader*(soapHeader[, name, namespace, xmlns]) - add soapHeader to soap:Header node
343
- ##### Parameters
344
- - `soapHeader` Object({rootName: {name: 'value'}}) or strict xml-string
345
-
346
- ##### Returns
347
- The index where the header is inserted.
348
-
349
- ##### Optional parameters when first arg is object :
350
- - `name` Unknown parameter (it could just a empty string)
351
- - `namespace` prefix of xml namespace
352
- - `xmlns` URI
353
-
354
- #### *changeSoapHeader*(index, soapHeader[, name, namespace, xmlns]) - change an already existing soapHeader
355
- ##### Parameters
356
- - `index` index of the header to replace with provided new value
357
- - `soapHeader` Object({rootName: {name: 'value'}}) or strict xml-string
358
-
359
- #### *getSoapHeaders*() - return all defined headers
360
-
361
- #### *clearSoapHeaders*() - remove all defined headers
362
-
363
-
364
- ## Client
365
-
366
- An instance of `Client` is passed to the `soap.createClient` callback. It is used to execute methods on the soap service.
367
-
368
- ### Client.describe() - description of services, ports and methods as a JavaScript object
369
-
370
- ``` javascript
371
- client.describe() // returns
372
- {
373
- MyService: {
374
- MyPort: {
375
- MyFunction: {
376
- input: {
377
- name: 'string'
378
- }
379
- }
380
- }
381
- }
382
- }
383
- ```
384
-
385
- ### Client.setSecurity(security) - use the specified security protocol
386
-
387
- ### Client.*method*(args, callback) - call *method* on the SOAP service.
388
-
389
- ``` javascript
390
- client.MyFunction({name: 'value'}, function(err, result, raw, soapHeader) {
391
- // result is a javascript object
392
- // raw is the raw response
393
- // soapHeader is the response soap header as a javascript object
394
- })
395
- ```
396
-
397
- The `args` argument allows you to supply arguments that generate an XML document inside of the SOAP Body section.
398
-
399
- ### Client.*method*Async(args) - call *method* on the SOAP service.
400
-
401
- ``` javascript
402
- client.MyFunctionAsync({name: 'value'}).then((result) => {
403
- // result is a javascript object
404
- })
405
- ```
406
-
407
- The `args` argument allows you to supply arguments that generate an XML document inside of the SOAP Body section.
408
-
409
- ##### Example with JSON for the `args`
410
- The example above uses `{name: 'value'}` as the args. This may generate a SOAP messages such as:
411
-
412
- ``` javascript
413
- <?xml version="1.0" encoding="utf-8"?>
414
- <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
415
- <soapenv:Body>
416
- <Request xmlns="http://www.example.com/v1">
417
- <name>value</name>
418
- </Request>
419
- </soapenv:Body>
420
- </soapenv:Envelope>
421
- ```
422
-
423
- Note that the "Request" element in the output above comes from the WSDL. If an element in `args` contains no namespace prefix, the default namespace is assumed. Otherwise, you must add the namespace prefixes to the element names as necessary (e.g., `ns1:name`).
424
-
425
- Currently, when supplying JSON args, elements may not contain both child elements and a text value, even though that is allowed in the XML specification.
426
-
427
- ##### Example with XML String for the `args`
428
- You may pass in a fully-formed XML string instead the individual elements in JSON `args` and attributes that make up the XML. The XML string should not contain an XML declaration (e.g., `<?xml version="1.0" encoding="UTF-8"?>`) or a document type declaration (e.g., `<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">`).
429
-
430
- ```
431
- var args = { _xml: "<ns1:MyRootElement xmlns:ns1="http://www.example.com/v1/ns1">
432
- <ChildElement>elementvalue</ChildElement>
433
- </ns1:MyRootElement>"
434
- };
435
- ```
436
- You must specify all of the namespaces and namespace prefixes yourself. The element(s) from the WSDL are not utilized as they were in the "Example with JSON as the `args`" example above, which automatically populated the "Request" element.
437
-
438
- ### Client.*service*.*port*.*method*(args, callback[, options[, extraHeaders]]) - call a *method* using a specific *service* and *port*
439
-
440
- ``` javascript
441
- client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
442
- // result is a javascript object
443
- })
444
- ```
445
-
446
- #### Options (optional)
447
- - Accepts any option that the request module accepts, see [here.](https://github.com/mikeal/request)
448
- - For example, you could set a timeout of 5 seconds on the request like this:
449
- ``` javascript
450
- client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
451
- // result is a javascript object
452
- }, {timeout: 5000})
453
- ```
454
-
455
- - You can measure the elapsed time on the request by passing the time option:
456
- ``` javascript
457
- client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
458
- // client.lastElapsedTime - the elapsed time of the last request in milliseconds
459
- }, {time: true})
460
- ```
461
-
462
- - Also, you could pass your soap request through a debugging proxy such as [Fiddler](http://www.telerik.com/fiddler) or [Betwixt](https://github.com/kdzwinel/betwixt).
463
- ``` javascript
464
- client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
465
- // client.lastElapsedTime - the elapsed time of the last request in milliseconds
466
- }, {proxy: 'http://localhost:8888'})
467
- ```
468
-
469
- - You can modify xml (string) before call:
470
- ``` javascript
471
- client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
472
- // client.lastElapsedTime - the elapsed time of the last request in milliseconds
473
- }, {postProcess: function(_xml) {
474
- return _xml.replace('text', 'newtext');
475
- }})
476
- ```
477
-
478
- #### Extra Headers (optional)
479
-
480
- Object properties define extra HTTP headers to be sent on the request.
481
-
482
- - Add custom User-Agent:
483
- ```javascript
484
- client.addHttpHeader('User-Agent', `CustomUserAgent`);
485
- ```
486
-
487
- #### Alternative method call using callback-last pattern
488
-
489
- To align method call signature with node' standard callback-last patter and event allow promisification of method calls, the following method signatures are also supported:
490
-
491
- ```javascript
492
- client.MyService.MyPort.MyFunction({name: 'value'}, options, function (err, result) {
493
- // result is a javascript object
494
- })
495
-
496
- client.MyService.MyPort.MyFunction({name: 'value'}, options, extraHeaders, function (err, result) {
497
- // result is a javascript object
498
- })
499
- ```
500
-
501
- ### Overriding the namespace prefix
502
- `node-soap` is still working out some kinks regarding namespaces. If you find that an element is given the wrong namespace prefix in the request body, you can add the prefix to it's name in the containing object. I.E.:
503
-
504
- ```javascript
505
- client.MyService.MyPort.MyFunction({'ns1:name': 'value'}, function(err, result) {
506
- // request body sent with `<ns1:name`, regardless of what the namespace should have been.
507
- }, {timeout: 5000})
508
- ```
509
-
510
- - Remove namespace prefix of param
511
-
512
- ```javascript
513
- client.MyService.MyPort.MyFunction({':name': 'value'}, function(err, result) {
514
- // request body sent with `<name`, regardless of what the namespace should have been.
515
- }, {timeout: 5000})
516
- ```
517
-
518
- ### Client.*lastRequest* - the property that contains last full soap request for client logging
519
-
520
- ### Client.setEndpoint(url) - overwrite the SOAP service endpoint address
521
-
522
- ### Client Events
523
- Client instances emit the following events:
524
-
525
- * request - Emitted before a request is sent. The event handler receives the
526
- entire Soap request (Envelope) including headers. The second parameter is the exchange id.
527
- * message - Emitted before a request is sent. The event handler receives the
528
- Soap body contents. Useful if you don't want to log /store Soap headers. The second parameter is the exchange id.
529
- * soapError - Emitted when an erroneous response is received.
530
- Useful if you want to globally log errors.
531
- The second parameter is the exchange id.
532
- * response - Emitted after a response is received. The event handler receives
533
- the SOAP response body as well as the entire `IncomingMessage` response object.
534
- The third parameter is the exchange id.
535
- This is emitted for all responses (both success and errors).
536
-
537
- An 'exchange' is a request/response couple.
538
- Event handlers receive the exchange id in all events.
539
- The exchange id is the same for the requests events and the responses events, this way you can use it to retrieve the matching request
540
- when an response event is received.
541
-
542
- By default exchange ids are generated by using node-uuid but you can use options in client calls to pass your own exchange id.
543
-
544
- Example :
545
-
546
- ```javascript
547
- client.MyService.MyPort.MyFunction(args , function(err, result) {
548
-
549
- }, {exchangeId: myExchangeId})
550
- ```
551
-
552
-
553
- ## Security
554
-
555
- `node-soap` has several default security protocols. You can easily add your own
556
- as well. The interface is quite simple. Each protocol defines 2 methods:
557
- * `addOptions` - a method that accepts an options arg that is eventually passed directly to `request`
558
- * `toXML` - a method that returns a string of XML.
559
-
560
- ### BasicAuthSecurity
561
-
562
- ``` javascript
563
- client.setSecurity(new soap.BasicAuthSecurity('username', 'password'));
564
- ```
565
-
566
- ### BearerSecurity
567
-
568
- ``` javascript
569
- client.setSecurity(new soap.BearerSecurity('token'));
570
- ```
571
-
572
- ### ClientSSLSecurity
573
-
574
- _Note_: If you run into issues using this protocol, consider passing these options
575
- as default request options to the constructor:
576
- * `rejectUnauthorized: false`
577
- * `strictSSL: false`
578
- * `secureOptions: constants.SSL_OP_NO_TLSv1_2` (this is likely needed for node >= 10.0)
579
-
580
- ``` javascript
581
- client.setSecurity(new soap.ClientSSLSecurity(
582
- '/path/to/key'
583
- , '/path/to/cert'
584
- , {/*default request options*/}
585
- ));
586
- ```
587
-
588
- ### WSSecurity
589
-
590
- `WSSecurity` implements WS-Security. UsernameToken and PasswordText/PasswordDigest is supported.
591
-
592
- ``` javascript
593
- var options = {
594
- hasNonce: true,
595
- actor: 'actor'
596
- };
597
- var wsSecurity = new soap.WSSecurity('username', 'password', options)
598
- client.setSecurity(wsSecurity);
599
- ```
600
- the `options` object is optional and can contain the following properties:
601
- * `passwordType`: 'PasswordDigest' or 'PasswordText' (default: `'PasswordText'`)
602
- * `hasTimeStamp`: adds Timestamp element (default: `true`)
603
- * `hasTokenCreated`: adds Created element (default: `true`)
604
- * `hasNonce`: adds Nonce element (default: `false`)
605
- * `mustUnderstand`: adds mustUnderstand=1 attribute to security tag (default: `false`)
606
- * `actor`: if set, adds Actor attribute with given value to security tag (default: `''`)
607
-
608
- ### WSSecurityCert
609
-
610
- WS-Security X509 Certificate support.
611
-
612
- ``` javascript
613
- var privateKey = fs.readFileSync(privateKeyPath);
614
- var publicKey = fs.readFileSync(publicKeyPath);
615
- var password = ''; // optional password
616
- var wsSecurity = new soap.WSSecurityCert(privateKey, publicKey, password);
617
- client.setSecurity(wsSecurity);
618
- ```
619
-
620
- ## Handling XML Attributes, Value and XML (wsdlOptions).
621
- Sometimes it is necessary to override the default behaviour of `node-soap` in order to deal with the special requirements
622
- of your code base or a third library you use. Therefore you can use the `wsdlOptions` Object, which is passed in the
623
- `#createClient()` method and could have any (or all) of the following contents:
624
- ```javascript
625
- var wsdlOptions = {
626
- attributesKey: 'theAttrs',
627
- valueKey: 'theVal',
628
- xmlKey: 'theXml'
629
- }
630
- ```
631
- If nothing (or an empty Object `{}`) is passed to the `#createClient()` method, the `node-soap` defaults (`attributesKey: 'attributes'`, `valueKey: '$value'` and `xmlKey: '$xml'`) are used.
632
-
633
- ### Overriding the `value` key
634
- By default, `node-soap` uses `$value` as the key for any parsed XML value which may interfere with your other code as it
635
- could be some reserved word, or the `$` in general cannot be used for a key to start with.
636
-
637
- You can define your own `valueKey` by passing it in the `wsdl_options` to the createClient call:
638
- ```javascript
639
- var wsdlOptions = {
640
- valueKey: 'theVal'
641
- };
642
-
643
- soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) {
644
- // your code
645
- });
646
- ```
647
-
648
- ### Overriding the `xml` key
649
- By default, `node-soap` uses `$xml` as the key to pass through an XML string as is; without parsing or namespacing it. It overrides all the other content that the node might have otherwise had.
650
-
651
- For example :
652
- ```javascript
653
- {
654
- dom: {
655
- nodeone: {
656
- $xml: '<parentnode type="type"><childnode></childnode></parentnode>',
657
- siblingnode: 'Cant see me.'
658
- },
659
- nodetwo: {
660
- parentnode: {
661
- attributes: {
662
- type: 'type'
663
- },
664
- childnode: ''
665
- }
666
- }
667
- }
668
- };
669
- ```
670
- could become
671
- ```xml
672
- <tns:dom>
673
- <tns:nodeone>
674
- <parentnode type="type">
675
- <childnode></childnode>
676
- </parentnode>
677
- </tns:nodeone>
678
- <tns:nodetwo>
679
- <tns:parentnode type="type">
680
- <tns:childnode></tns:childnode>
681
- </tns:parent>
682
- </tns:nodetwo>
683
- </tns:dom>
684
- ```
685
-
686
- You can define your own `xmlKey` by passing it in the `wsdl_options` object to the createClient call:
687
- ```javascript
688
- var wsdlOptions = {
689
- xmlKey: 'theXml'
690
- };
691
-
692
- soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) {
693
- // your code
694
- });
695
- ```
696
-
697
- ### Overriding the `attributes` key
698
- By default, `node-soap` uses `attributes` as the key to define a nodes attributes.
699
-
700
- ``` javascript
701
- {
702
- parentnode: {
703
- childnode: {
704
- attributes: {
705
- name: 'childsname'
706
- },
707
- $value: 'Value'
708
- }
709
- }
710
- }
711
- ```
712
- could become
713
- ``` xml
714
- <parentnode>
715
- <childnode name="childsname">Value</childnode>
716
- </parentnode>
717
- ```
718
-
719
- However, `attributes` may be a reserved key for some systems that actually want a node called `attributes`
720
- ```xml
721
- <attributes>
722
- </attributes>
723
- ```
724
-
725
- You can define your own `attributesKey` by passing it in the `wsdl_options` object to the createClient call:
726
- ```javascript
727
- var wsdlOptions = {
728
- attributesKey: '$attributes'
729
- };
730
-
731
- soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) {
732
- client.method({
733
- parentnode: {
734
- childnode: {
735
- $attributes: {
736
- name: 'childsname'
737
- },
738
- $value: 'Value'
739
- }
740
- }
741
- });
742
- });
743
- ```
744
- ### Specifying the exact namespace definition of the root element
745
- In rare cases, you may want to precisely control the namespace definition that is included in the root element.
746
-
747
- You can specify the namespace definitions by setting the `overrideRootElement` key in the `wsdlOptions` like so:
748
- ```javascript
749
- var wsdlOptions = {
750
- overrideRootElement: {
751
- namespace: 'xmlns:tns',
752
- xmlnsAttributes: [{
753
- name: 'xmlns:ns2',
754
- value: "http://tempuri.org/"
755
- }, {
756
- name: 'xmlns:ns3',
757
- value: "http://sillypets.com/xsd"
758
- }]
759
- }
760
- };
761
- ```
762
-
763
- To see it in practice, have a look at the sample files in: [test/request-response-samples/addPets__force_namespaces](https://github.com/vpulim/node-soap/tree/master/test/request-response-samples/addPets__force_namespaces)
764
-
765
- ### Custom Deserializer
766
-
767
- Sometimes it's useful to handle deserialization in your code instead of letting node-soap do it.
768
- For example if the soap response contains dates that are not in a format recognized by javascript, you might want to use your own function to handle them.
769
-
770
- To do so, you can pass a `customDeserializer` object in `options`. The properties of this object are the types that your deserializer handles itself.
771
-
772
- Example :
773
- ```javascript
774
-
775
- var wsdlOptions = {
776
- customDeserializer = {
777
-
778
- // this function will be used to any date found in soap responses
779
- date: function (text, context) {
780
- /* text is the value of the xml element.
781
- context contains the name of the xml element and other infos :
782
- {
783
- name: 'lastUpdatedDate',
784
- object: {},
785
- schema: 'xsd:date',
786
- id: undefined,
787
- nil: false
788
- }
789
-
790
- */
791
- return text;
792
- }
793
- }
794
- };
795
-
796
- soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) {
797
- ...
798
- });
799
-
800
- ```
801
-
802
- ## Handling "ignored" namespaces
803
- If an Element in a `schema` definition depends on an Element which is present in the same namespace, normally the `tns:`
804
- namespace prefix is used to identify this Element. This is not much of a problem as long as you have just one `schema` defined
805
- (inline or in a separate file). If there are more `schema` files, the `tns:` in the generated `soap` file resolved mostly to the parent `wsdl` file,
806
- which was obviously wrong.
807
-
808
- `node-soap` now handles namespace prefixes which shouldn't be resolved (because it's not necessary) as so called `ignoredNamespaces`
809
- which default to an Array of 3 Strings (`['tns', 'targetNamespace', 'typedNamespace']`).
810
-
811
- If this is not sufficient for your purpose you can easily add more namespace prefixes to this Array, or override it in its entirety
812
- by passing an `ignoredNamespaces` object within the `options` you pass in `soap.createClient()` method.
813
-
814
- A simple `ignoredNamespaces` object, which only adds certain namespaces could look like this:
815
- ```
816
- var options = {
817
- ignoredNamespaces: {
818
- namespaces: ['namespaceToIgnore', 'someOtherNamespace']
819
- }
820
- }
821
- ```
822
- This would extend the `ignoredNamespaces` of the `WSDL` processor to `['tns', 'targetNamespace', 'typedNamespace', 'namespaceToIgnore', 'someOtherNamespace']`.
823
-
824
- If you want to override the default ignored namespaces you would simply pass the following `ignoredNamespaces` object within the `options`:
825
- ```
826
- var options = {
827
- ignoredNamespaces: {
828
- namespaces: ['namespaceToIgnore', 'someOtherNamespace'],
829
- override: true
830
- }
831
- }
832
- ```
833
- This would override the default `ignoredNamespaces` of the `WSDL` processor to `['namespaceToIgnore', 'someOtherNamespace']`. (This shouldn't be necessary, anyways).
834
-
835
- If you want to override the default ignored namespaces you would simply pass the following `ignoredNamespaces` object within the `options`:
836
- ```
837
- var options = {
838
- ignoredNamespaces: {
839
- namespaces: ['namespaceToIgnore', 'someOtherNamespace'],
840
- override: true
841
- }
842
- }
843
- ```
844
- This would override the default `ignoredNamespaces` of the `WSDL` processor to `['namespaceToIgnore', 'someOtherNamespace']`. (This shouldn't be necessary, anyways).
845
-
846
- ## Handling "ignoreBaseNameSpaces" attribute
847
- If an Element in a `schema` definition depends has a basenamespace defined but the request does not need that value, for example you have a "sentJob" with basenamespace "v20"
848
- but the request need only: <sendJob> set in the tree structure, you need to set the ignoreBaseNameSpaces to true. This is set because in a lot of workaround the wsdl structure is not correctly
849
- set or the webservice bring errors.
850
-
851
- By default the attribute is set to true.
852
- An example to use:
853
-
854
- A simple `ignoredNamespaces` object, which only adds certain namespaces could look like this:
855
- ```
856
- var options = {
857
- ignoredNamespaces: true
858
- }
859
- ```
860
-
861
- ## soap-stub
862
-
863
- Unit testing services that use soap clients can be very cumbersome. In order to get
864
- around this you can use `soap-stub` in conjunction with `sinon` to stub soap with
865
- your clients.
866
-
867
- ### Example
868
-
869
- ```javascript
870
- // test-initialization-script.js
871
- var sinon = require('sinon');
872
- var soapStub = require('soap/soap-stub');
873
-
874
- var urlMyApplicationWillUseWithCreateClient = 'http://path-to-my-wsdl';
875
- var clientStub = {
876
- SomeOperation: sinon.stub()
877
- };
878
-
879
- clientStub.SomeOperation.respondWithError = soapStub.createErroringStub({..error json...});
880
- clientStub.SomeOperation.respondWithSuccess = soapStub.createRespondingStub({..success json...});
881
-
882
- soapStub.registerClient('my client alias', urlMyApplicationWillUseWithCreateClient, clientStub);
883
-
884
- // test.js
885
- var soapStub = require('soap/soap-stub');
886
-
887
- describe('myService', function() {
888
- var clientStub;
889
- var myService;
890
-
891
- beforeEach(function() {
892
- clientStub = soapStub.getStub('my client alias');
893
- soapStub.reset();
894
- myService.init(clientStub);
895
- });
896
-
897
- describe('failures', function() {
898
- beforeEach(function() {
899
- clientStub.SomeOperation.respondWithError();
900
- });
901
-
902
- it('should handle error responses', function() {
903
- myService.somethingThatCallsSomeOperation(function(err, response) {
904
- // handle the error response.
905
- });
906
- });
907
- });
908
- });
909
- ```
910
-
911
-
912
- ## Contributors
913
-
914
- * Author: [Vinay Pulim](https://github.com/vpulim)
915
- * Maintainers:
916
- - [Joe Spencer](https://github.com/jsdevel)
917
- - [Heinz Romirer](https://github.com/herom)
918
- * [All Contributors](https://github.com/vpulim/node-soap/graphs/contributors)
919
-
920
- [downloads-image]: http://img.shields.io/npm/dm/soap.svg
921
- [npm-url]: https://npmjs.org/package/soap
922
- [npm-image]: http://img.shields.io/npm/v/soap.svg
923
-
924
- [travis-url]: https://travis-ci.org/vpulim/node-soap
925
- [travis-image]: http://img.shields.io/travis/vpulim/node-soap.svg
926
-
927
- [gitter-url]: https://gitter.im/vpulim/node-soap
928
- [gitter-image]: https://badges.gitter.im/vpulim/node-soap.png
929
-
930
- [coveralls-url]: https://coveralls.io/r/vpulim/node-soap
931
- [coveralls-image]: http://img.shields.io/coveralls/vpulim/node-soap/master.svg
1
+ # Soap [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Coveralls Status][coveralls-image]][coveralls-url] [![Gitter chat][gitter-image]][gitter-url]
2
+
3
+ > A SOAP client and server for node.js.
4
+
5
+ This module lets you connect to web services using SOAP. It also provides a server that allows you to run your own SOAP services.
6
+
7
+ <!-- Run `npm run toc` to update below section -->
8
+ <!-- START doctoc generated TOC please keep comment here to allow auto update -->
9
+ <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
10
+
11
+
12
+ - [Features:](#features)
13
+ - [Install](#install)
14
+ - [Why can't I file an issue?](#why-cant-i-file-an-issue)
15
+ - [Where can I find help?](#where-can-i-find-help)
16
+ - [Module](#module)
17
+ - [soap.createClient(url[, options], callback) - create a new SOAP client from a WSDL url. Also supports a local filesystem path.](#soapcreateclienturl-options-callback---create-a-new-soap-client-from-a-wsdl-url-also-supports-a-local-filesystem-path)
18
+ - [soap.createClientAsync(url[, options]) - create a new SOAP client from a WSDL url. Also supports a local filesystem path.](#soapcreateclientasyncurl-options---create-a-new-soap-client-from-a-wsdl-url-also-supports-a-local-filesystem-path)
19
+ - [soap.listen(*server*, *path*, *services*, *wsdl*) - create a new SOAP server that listens on *path* and provides *services*.](#soaplistenserver-path-services-wsdl---create-a-new-soap-server-that-listens-on-path-and-provides-services)
20
+ - [Options](#options)
21
+ - [Server Logging](#server-logging)
22
+ - [Server Events](#server-events)
23
+ - [Server Response on one-way calls](#server-response-on-one-way-calls)
24
+ - [SOAP Fault](#soap-fault)
25
+ - [Server security example using PasswordDigest](#server-security-example-using-passworddigest)
26
+ - [Server connection authorization](#server-connection-authorization)
27
+ - [SOAP Headers](#soap-headers)
28
+ - [Received SOAP Headers](#received-soap-headers)
29
+ - [Outgoing SOAP Headers](#outgoing-soap-headers)
30
+ - [Client](#client)
31
+ - [Client.describe() - description of services, ports and methods as a JavaScript object](#clientdescribe---description-of-services-ports-and-methods-as-a-javascript-object)
32
+ - [Client.setSecurity(security) - use the specified security protocol](#clientsetsecuritysecurity---use-the-specified-security-protocol)
33
+ - [Client.*method*(args, callback) - call *method* on the SOAP service.](#clientmethodargs-callback---call-method-on-the-soap-service)
34
+ - [Client.*method*Async(args) - call *method* on the SOAP service.](#clientmethodasyncargs---call-method-on-the-soap-service)
35
+ - [Client.*service*.*port*.*method*(args, callback[, options[, extraHeaders]]) - call a *method* using a specific *service* and *port*](#clientserviceportmethodargs-callback-options-extraheaders---call-a-method-using-a-specific-service-and-port)
36
+ - [Overriding the namespace prefix](#overriding-the-namespace-prefix)
37
+ - [Client.*lastRequest* - the property that contains last full soap request for client logging](#clientlastrequest---the-property-that-contains-last-full-soap-request-for-client-logging)
38
+ - [Client.setEndpoint(url) - overwrite the SOAP service endpoint address](#clientsetendpointurl---overwrite-the-soap-service-endpoint-address)
39
+ - [Client Events](#client-events)
40
+ - [request](#request)
41
+ - [message](#message)
42
+ - [soapError](#soaperror)
43
+ - [response](#response)
44
+ - [Security](#security)
45
+ - [BasicAuthSecurity](#basicauthsecurity)
46
+ - [BearerSecurity](#bearersecurity)
47
+ - [ClientSSLSecurity](#clientsslsecurity)
48
+ - [ClientSSLSecurityPFX](#clientsslsecuritypfx)
49
+ - [WSSecurity](#wssecurity)
50
+ - [WSSecurityCert](#wssecuritycert)
51
+ - [Handling XML Attributes, Value and XML (wsdlOptions).](#handling-xml-attributes-value-and-xml-wsdloptions)
52
+ - [Overriding the `value` key](#overriding-the-value-key)
53
+ - [Overriding the `xml` key](#overriding-the-xml-key)
54
+ - [Overriding the `attributes` key](#overriding-the-attributes-key)
55
+ - [Specifying the exact namespace definition of the root element](#specifying-the-exact-namespace-definition-of-the-root-element)
56
+ - [Custom Deserializer](#custom-deserializer)
57
+ - [Handling "ignored" namespaces](#handling-ignored-namespaces)
58
+ - [Handling "ignoreBaseNameSpaces" attribute](#handling-ignorebasenamespaces-attribute)
59
+ - [soap-stub](#soap-stub)
60
+ - [Example](#example)
61
+ - [Contributors](#contributors)
62
+
63
+ <!-- END doctoc generated TOC please keep comment here to allow auto update -->
64
+
65
+ ## Features:
66
+
67
+ * Very simple API
68
+ * Handles both RPC and Document schema types
69
+ * Supports multiRef SOAP messages (thanks to [@kaven276](https://github.com/kaven276))
70
+ * Support for both synchronous and asynchronous method handlers
71
+ * WS-Security (currently only UsernameToken and PasswordText encoding is supported)
72
+ * Supports [express](http://expressjs.com/) based web server(body parser middleware can be used)
73
+
74
+ ## Install
75
+
76
+ Install with [npm](http://github.com/isaacs/npm):
77
+
78
+ ```
79
+ npm install soap
80
+ ```
81
+
82
+ ## Why can't I file an issue?
83
+
84
+ We've disabled issues in the repository and are now solely reviewing pull requests. The reasons why we disabled issues can be found here [#731](https://github.com/vpulim/node-soap/pull/731).
85
+
86
+ ## Where can I find help?
87
+
88
+ Community support can be found on gitter:
89
+
90
+ [![Gitter chat][gitter-image]][gitter-url]
91
+
92
+ If you're looking for professional help you can contact the maintainers through this [google form](https://docs.google.com/forms/d/e/1FAIpQLSdj5EXxd5flcukLInmpFQhEvQYeERaReFFh9F0nqC_4EUmeLg/viewform).
93
+
94
+ ## Module
95
+
96
+ ### soap.createClient(url[, options], callback) - create a new SOAP client from a WSDL url. Also supports a local filesystem path.
97
+
98
+ ``` javascript
99
+ var soap = require('soap');
100
+ var url = 'http://example.com/wsdl?wsdl';
101
+ var args = {name: 'value'};
102
+ soap.createClient(url, function(err, client) {
103
+ client.MyFunction(args, function(err, result) {
104
+ console.log(result);
105
+ });
106
+ });
107
+ ```
108
+ This client has a built in WSDL cache. You can use the `disableCache` option to disable it.
109
+
110
+ ### soap.createClientAsync(url[, options]) - create a new SOAP client from a WSDL url. Also supports a local filesystem path.
111
+
112
+ ``` javascript
113
+ var soap = require('soap');
114
+ var url = 'http://example.com/wsdl?wsdl';
115
+ var args = {name: 'value'};
116
+ soap.createClientAsync(url).then((client) => {
117
+ return client.MyFunctionAsync(args);
118
+ }).then((result) => {
119
+ console.log(result);
120
+ });
121
+ ```
122
+
123
+ This client has a built in WSDL cache. You can use the `disableCache` option to disable it.
124
+
125
+ #### Options
126
+
127
+ The `options` argument allows you to customize the client with the following properties:
128
+
129
+ - endpoint: to override the SOAP service's host specified in the `.wsdl` file.
130
+ - envelopeKey: to set specific key instead of `<pre><<b>soap</b>:Body></<b>soap</b>:Body></pre>`.
131
+ - preserveWhitespace: to preserve leading and trailing whitespace characters in text and cdata.
132
+ - escapeXML: escape special XML characters in SOAP message (e.g. `&`, `>`, `<` etc), default: `true`.
133
+ - suppressStack: suppress the full stack trace for error messages.
134
+ - returnFault: return an `Invalid XML` SOAP fault on a bad request, default: `false`.
135
+ - forceSoap12Headers: to set proper headers for SOAP v1.2.
136
+ - httpClient: to provide your own http client that implements `request(rurl, data, callback, exheaders, exoptions)`.
137
+ - request: to override the [request](https://github.com/request/request) module.
138
+ - wsdl_headers: custom HTTP headers to be sent on WSDL requests.
139
+ - wsdl_options: custom options for the request module on WSDL requests.
140
+ - disableCache: don't cache WSDL files, request them every time.
141
+ - overridePromiseSuffix: if your wsdl operations contains names with Async suffix, you will need to override the default promise suffix to a custom one, default: `Async`.
142
+ - normalizeNames: if your wsdl operations contains names with non identifier characters (`[^a-z$_0-9]`), replace them with `_`. Note: if using this option, clients using wsdls with two operations like `soap:method` and `soap-method` will be overwritten. Then, use bracket notation instead (`client['soap:method']()`).
143
+ - namespaceArrayElements: provides support for nonstandard array semantics. If true, JSON arrays of the form `{list: [{elem: 1}, {elem: 2}]}` are marshalled into xml as `<list><elem>1</elem></list> <list><elem>2</elem></list>`. If false, marshalls into `<list> <elem>1</elem> <elem>2</elem> </list>`. Default: `true`.
144
+
145
+ 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.
146
+
147
+ ### soap.listen(*server*, *path*, *services*, *wsdl*) - create a new SOAP server that listens on *path* and provides *services*.
148
+ *server* can be a [http](https://nodejs.org/api/http.html) Server or [express](http://expressjs.com/) framework based server
149
+ *wsdl* is an xml string that defines the service.
150
+
151
+ ``` javascript
152
+ var myService = {
153
+ MyService: {
154
+ MyPort: {
155
+ MyFunction: function(args) {
156
+ return {
157
+ name: args.name
158
+ };
159
+ },
160
+
161
+ // This is how to define an asynchronous function.
162
+ MyAsyncFunction: function(args, callback) {
163
+ // do some work
164
+ callback({
165
+ name: args.name
166
+ });
167
+ },
168
+
169
+ // This is how to receive incoming headers
170
+ HeadersAwareFunction: function(args, cb, headers) {
171
+ return {
172
+ name: headers.Token
173
+ };
174
+ },
175
+
176
+ // You can also inspect the original `req`
177
+ reallyDetailedFunction: function(args, cb, headers, req) {
178
+ console.log('SOAP `reallyDetailedFunction` request from ' + req.connection.remoteAddress);
179
+ return {
180
+ name: headers.Token
181
+ };
182
+ }
183
+ }
184
+ }
185
+ };
186
+
187
+ var xml = require('fs').readFileSync('myservice.wsdl', 'utf8');
188
+
189
+ //http server example
190
+ var server = http.createServer(function(request,response) {
191
+ response.end('404: Not Found: ' + request.url);
192
+ });
193
+
194
+ server.listen(8000);
195
+ soap.listen(server, '/wsdl', myService, xml);
196
+
197
+ //express server example
198
+ var app = express();
199
+ //body parser middleware are supported (optional)
200
+ app.use(bodyParser.raw({type: function(){return true;}, limit: '5mb'}));
201
+ app.listen(8001, function(){
202
+ //Note: /wsdl route will be handled by soap module
203
+ //and all other routes & middleware will continue to work
204
+ soap.listen(app, '/wsdl', myService, xml);
205
+ });
206
+
207
+ ```
208
+
209
+ ### Options
210
+ You can pass in server and [WSDL Options](#handling-xml-attributes-value-and-xml-wsdloptions)
211
+ using an options hash.
212
+
213
+ Server options include the below:
214
+ - `pfx`: A string or Buffer containing the private key, certificate and CA certs of the server in PFX or PKCS12 format. (Mutually exclusive with the key, cert and ca options.)
215
+ - `key`: A string or Buffer containing the private key of the server in PEM format. (Could be an array of keys). (Required)
216
+ - `passphrase`: A string of passphrase for the private key or pfx.
217
+ - `cert`: A string or Buffer containing the certificate key of the server in PEM format. (Could be an array of certs). (Required)
218
+ - `ca`: An array of strings or Buffers of trusted certificates in PEM format. If this is omitted several well known "root" CAs will be used, like VeriSign. These are used to authorize connections.
219
+ - `crl` : Either a string or list of strings of PEM encoded CRLs (Certificate Revocation List)
220
+ - `ciphers`: A string describing the ciphers to use or exclude, separated by :. The default cipher suite is:
221
+
222
+ ``` javascript
223
+ var xml = require('fs').readFileSync('myservice.wsdl', 'utf8');
224
+
225
+ soap.listen(server, {
226
+ // Server options.
227
+ path: '/wsdl',
228
+ services: myService,
229
+ xml: xml,
230
+
231
+ // WSDL options.
232
+ attributesKey: 'theAttrs',
233
+ valueKey: 'theVal',
234
+ xmlKey: 'theXml'
235
+ });
236
+ ```
237
+
238
+ ### Server Logging
239
+
240
+ If the `log` method is defined it will be called with 'received' and 'replied'
241
+ along with data.
242
+
243
+ ``` javascript
244
+ server = soap.listen(...)
245
+ server.log = function(type, data) {
246
+ // type is 'received' or 'replied'
247
+ };
248
+ ```
249
+
250
+ ### Server Events
251
+
252
+ Server instances emit the following events:
253
+
254
+ * request - Emitted for every received messages.
255
+ The signature of the callback is `function(request, methodName)`.
256
+ * headers - Emitted when the SOAP Headers are not empty.
257
+ The signature of the callback is `function(headers, methodName)`.
258
+
259
+ The sequence order of the calls is `request`, `headers` and then the dedicated
260
+ service method.
261
+
262
+ ### Server Response on one-way calls
263
+
264
+ The so called one-way (or asynchronous) calls occur when an operation is called with no output defined in WSDL.
265
+ The server sends a response (defaults to status code 200 with no body) to the client disregarding the result of the operation.
266
+
267
+ You can configure the response to match the appropriate client expectation to the SOAP standard implementation.
268
+ Pass in `oneWay` object in server options. Use the following keys:
269
+ `emptyBody`: if true, returns an empty body, otherwise no content at all (default is false)
270
+ `responseCode`: default statusCode is 200, override it with this options (for example 202 for SAP standard compliant response)
271
+
272
+ ### SOAP Fault
273
+
274
+ A service method can reply with a SOAP Fault to a client by `throw`ing an
275
+ object with a `Fault` property.
276
+
277
+ ``` javascript
278
+ throw {
279
+ Fault: {
280
+ Code: {
281
+ Value: 'soap:Sender',
282
+ Subcode: { value: 'rpc:BadArguments' }
283
+ },
284
+ Reason: { Text: 'Processing Error' }
285
+ }
286
+ };
287
+ ```
288
+
289
+ To change the HTTP statusCode of the response include it on the fault. The statusCode property will not be put on the xml message.
290
+
291
+ ``` javascript
292
+ throw {
293
+ Fault: {
294
+ Code: {
295
+ Value: 'soap:Sender',
296
+ Subcode: { value: 'rpc:BadArguments' }
297
+ },
298
+ Reason: { Text: 'Processing Error' },
299
+ statusCode: 500
300
+ }
301
+ };
302
+ ```
303
+
304
+ ### Server security example using PasswordDigest
305
+
306
+ If `server.authenticate` is not defined then no authentication will take place.
307
+
308
+ ``` javascript
309
+ server = soap.listen(...)
310
+ server.authenticate = function(security) {
311
+ var created, nonce, password, user, token;
312
+ token = security.UsernameToken, user = token.Username,
313
+ password = token.Password, nonce = token.Nonce, created = token.Created;
314
+ return user === 'user' && password === soap.passwordDigest(nonce, created, 'password');
315
+ };
316
+ ```
317
+
318
+ ### Server connection authorization
319
+
320
+ The `server.authorizeConnection` method is called prior to the soap service method.
321
+ If the method is defined and returns `false` then the incoming connection is
322
+ terminated.
323
+
324
+ ``` javascript
325
+ server = soap.listen(...)
326
+ server.authorizeConnection = function(req) {
327
+ return true; // or false
328
+ };
329
+ ```
330
+
331
+
332
+ ## SOAP Headers
333
+
334
+ ### Received SOAP Headers
335
+
336
+ A service method can look at the SOAP headers by providing a 3rd arguments.
337
+
338
+ ``` javascript
339
+ {
340
+ HeadersAwareFunction: function(args, cb, headers) {
341
+ return {
342
+ name: headers.Token
343
+ };
344
+ }
345
+ }
346
+ ```
347
+
348
+ It is also possible to subscribe to the 'headers' event.
349
+ The event is triggered before the service method is called, and only when the
350
+ SOAP Headers are not empty.
351
+
352
+ ``` javascript
353
+ server = soap.listen(...)
354
+ server.on('headers', function(headers, methodName) {
355
+ // It is possible to change the value of the headers
356
+ // before they are handed to the service method.
357
+ // It is also possible to throw a SOAP Fault
358
+ });
359
+ ```
360
+
361
+ First parameter is the Headers object;
362
+ second parameter is the name of the SOAP method that will called
363
+ (in case you need to handle the headers differently based on the method).
364
+
365
+ ### Outgoing SOAP Headers
366
+
367
+ Both client & server can define SOAP headers that will be added to what they send.
368
+ They provide the following methods to manage the headers.
369
+
370
+
371
+ #### *addSoapHeader*(soapHeader[, name, namespace, xmlns]) - add soapHeader to soap:Header node
372
+ ##### Parameters
373
+ - `soapHeader` Object({rootName: {name: 'value'}}), strict xml-string,
374
+ or function (server only)
375
+
376
+ For servers only, `soapHeader` can be a function, which allows headers to be
377
+ dynamically generated from information in the request. This function will be
378
+ called with the following arguments for each received request:
379
+
380
+ - `methodName` The name of the request method
381
+ - `args` The arguments of the request
382
+ - `headers` The headers in the request
383
+ - `req` The original request object
384
+
385
+ The return value of the function must be an Object({rootName: {name: 'value'}})
386
+ or strict xml-string, which will be inserted as an outgoing header of the
387
+ response to that request.
388
+
389
+ For example:
390
+
391
+ ``` javascript
392
+ server = soap.listen(...);
393
+ server.addSoapHeader(function(methodName, args, headers, req) {
394
+ console.log('Adding headers for method', methodName);
395
+ return {
396
+ MyHeader1: args.SomeValueFromArgs,
397
+ MyHeader2: headers.SomeRequestHeader
398
+ };
399
+ // or you can return "<MyHeader1>SomeValue</MyHeader1>"
400
+ });
401
+ ```
402
+
403
+ ##### Returns
404
+ The index where the header is inserted.
405
+
406
+ ##### Optional parameters when first arg is object :
407
+ - `name` Unknown parameter (it could just a empty string)
408
+ - `namespace` prefix of xml namespace
409
+ - `xmlns` URI
410
+
411
+ #### *changeSoapHeader*(index, soapHeader[, name, namespace, xmlns]) - change an already existing soapHeader
412
+ ##### Parameters
413
+ - `index` index of the header to replace with provided new value
414
+ - `soapHeader` Object({rootName: {name: 'value'}}), strict xml-string
415
+ or function (server only)
416
+
417
+ See `addSoapHeader` for how to pass a function into `soapHeader`.
418
+
419
+ #### *getSoapHeaders*() - return all defined headers
420
+
421
+ #### *clearSoapHeaders*() - remove all defined headers
422
+
423
+
424
+ ## Client
425
+
426
+ An instance of `Client` is passed to the `soap.createClient` callback. It is used to execute methods on the soap service.
427
+
428
+ ### Client.describe() - description of services, ports and methods as a JavaScript object
429
+
430
+ ``` javascript
431
+ client.describe() // returns
432
+ {
433
+ MyService: {
434
+ MyPort: {
435
+ MyFunction: {
436
+ input: {
437
+ name: 'string'
438
+ }
439
+ }
440
+ }
441
+ }
442
+ }
443
+ ```
444
+
445
+ ### Client.setSecurity(security) - use the specified security protocol
446
+
447
+ ### Client.*method*(args, callback, options) - call *method* on the SOAP service.
448
+
449
+ ``` javascript
450
+ client.MyFunction({name: 'value'}, function(err, result, rawResponse, soapHeader, rawRequest) {
451
+ // result is a javascript object
452
+ // rawResponse is the raw xml response string
453
+ // soapHeader is the response soap header as a javascript object
454
+ // rawRequest is the raw xml request string
455
+ })
456
+ ```
457
+
458
+ The `args` argument allows you to supply arguments that generate an XML document inside of the SOAP Body section.
459
+
460
+ The `options` object is optional and is passed to the `request`-module.
461
+ Interesting properties might be:
462
+ * `timeout`: Timeout in milliseconds
463
+ * `forever`: Enables keep-alive connections and pools them
464
+
465
+ ### Client.*method*Async(args) - call *method* on the SOAP service.
466
+
467
+ ``` javascript
468
+ client.MyFunctionAsync({name: 'value'}).then((result) => {
469
+ // result is a javascript array containing result, raw and soapheader
470
+ // result is a javascript object
471
+ // raw is the raw response
472
+ // soapHeader is the response soap header as a javascript object
473
+ })
474
+ ```
475
+
476
+ The `args` argument allows you to supply arguments that generate an XML document inside of the SOAP Body section.
477
+
478
+ ##### Example with JSON for the `args`
479
+ The example above uses `{name: 'value'}` as the args. This may generate a SOAP messages such as:
480
+
481
+ ``` javascript
482
+ <?xml version="1.0" encoding="utf-8"?>
483
+ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
484
+ <soapenv:Body>
485
+ <Request xmlns="http://www.example.com/v1">
486
+ <name>value</name>
487
+ </Request>
488
+ </soapenv:Body>
489
+ </soapenv:Envelope>
490
+ ```
491
+
492
+ Note that the "Request" element in the output above comes from the WSDL. If an element in `args` contains no namespace prefix, the default namespace is assumed. Otherwise, you must add the namespace prefixes to the element names as necessary (e.g., `ns1:name`).
493
+
494
+ Currently, when supplying JSON args, elements may not contain both child elements and a text value, even though that is allowed in the XML specification.
495
+
496
+ ##### Example with XML String for the `args`
497
+ You may pass in a fully-formed XML string instead the individual elements in JSON `args` and attributes that make up the XML. The XML string should not contain an XML declaration (e.g., `<?xml version="1.0" encoding="UTF-8"?>`) or a document type declaration (e.g., `<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">`).
498
+
499
+ ```
500
+ var args = { _xml: "<ns1:MyRootElement xmlns:ns1="http://www.example.com/v1/ns1">
501
+ <ChildElement>elementvalue</ChildElement>
502
+ </ns1:MyRootElement>"
503
+ };
504
+ ```
505
+ You must specify all of the namespaces and namespace prefixes yourself. The element(s) from the WSDL are not utilized as they were in the "Example with JSON as the `args`" example above, which automatically populated the "Request" element.
506
+
507
+ ### Client.*service*.*port*.*method*(args, callback[, options[, extraHeaders]]) - call a *method* using a specific *service* and *port*
508
+
509
+ ``` javascript
510
+ client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
511
+ // result is a javascript object
512
+ })
513
+ ```
514
+
515
+ #### Options (optional)
516
+ - Accepts any option that the request module accepts, see [here.](https://github.com/mikeal/request)
517
+ - For example, you could set a timeout of 5 seconds on the request like this:
518
+ ``` javascript
519
+ client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
520
+ // result is a javascript object
521
+ }, {timeout: 5000})
522
+ ```
523
+
524
+ - You can measure the elapsed time on the request by passing the time option:
525
+ ``` javascript
526
+ client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
527
+ // client.lastElapsedTime - the elapsed time of the last request in milliseconds
528
+ }, {time: true})
529
+ ```
530
+
531
+ - Also, you could pass your soap request through a debugging proxy such as [Fiddler](http://www.telerik.com/fiddler) or [Betwixt](https://github.com/kdzwinel/betwixt).
532
+ ``` javascript
533
+ client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
534
+ // client.lastElapsedTime - the elapsed time of the last request in milliseconds
535
+ }, {proxy: 'http://localhost:8888'})
536
+ ```
537
+
538
+ - You can modify xml (string) before call:
539
+ ``` javascript
540
+ client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
541
+ // client.lastElapsedTime - the elapsed time of the last request in milliseconds
542
+ }, {postProcess: function(_xml) {
543
+ return _xml.replace('text', 'newtext');
544
+ }})
545
+ ```
546
+
547
+ #### Extra Headers (optional)
548
+
549
+ Object properties define extra HTTP headers to be sent on the request.
550
+
551
+ - Add custom User-Agent:
552
+ ```javascript
553
+ client.addHttpHeader('User-Agent', `CustomUserAgent`);
554
+ ```
555
+
556
+ #### Alternative method call using callback-last pattern
557
+
558
+ To align method call signature with node' standard callback-last patter and event allow promisification of method calls, the following method signatures are also supported:
559
+
560
+ ```javascript
561
+ client.MyService.MyPort.MyFunction({name: 'value'}, options, function (err, result) {
562
+ // result is a javascript object
563
+ })
564
+
565
+ client.MyService.MyPort.MyFunction({name: 'value'}, options, extraHeaders, function (err, result) {
566
+ // result is a javascript object
567
+ })
568
+ ```
569
+
570
+ ### Overriding the namespace prefix
571
+ `node-soap` is still working out some kinks regarding namespaces. If you find that an element is given the wrong namespace prefix in the request body, you can add the prefix to it's name in the containing object. I.E.:
572
+
573
+ ```javascript
574
+ client.MyService.MyPort.MyFunction({'ns1:name': 'value'}, function(err, result) {
575
+ // request body sent with `<ns1:name`, regardless of what the namespace should have been.
576
+ }, {timeout: 5000})
577
+ ```
578
+
579
+ - Remove namespace prefix of param
580
+
581
+ ```javascript
582
+ client.MyService.MyPort.MyFunction({':name': 'value'}, function(err, result) {
583
+ // request body sent with `<name`, regardless of what the namespace should have been.
584
+ }, {timeout: 5000})
585
+ ```
586
+
587
+ ### Client.*lastRequest* - the property that contains last full soap request for client logging
588
+
589
+ ### Client.setEndpoint(url) - overwrite the SOAP service endpoint address
590
+
591
+ ### Client Events
592
+ Client instances emit the following events:
593
+
594
+ ### _request_
595
+ Emitted before a request is sent. The event handler has the signature `(xml, eid)`.
596
+
597
+ - _xml_ - The entire Soap request (Envelope) including headers.
598
+ - _eid_ - The exchange id.
599
+
600
+ ### _message_
601
+ Emitted before a request is sent, but only the body is passed to the event handler. Useful if you don't want to log /store Soap headers. The event handler has the signature `(message, eid)`.
602
+
603
+ - _message_ - Soap body contents.
604
+ - _eid_ - The exchange id.
605
+
606
+ ### _soapError_
607
+ Emitted when an erroneous response is received. Useful if you want to globally log errors. The event handler has the signature `(error, eid)`.
608
+
609
+ - _error_ - An error object which also contains the resoponse.
610
+ - _eid_ - The exchange id.
611
+ ### _response_
612
+ Emitted after a response is received. This is emitted for all responses (both success and errors). The event handler has the signature `(body, response, eid)`
613
+
614
+ - _body_ - The SOAP response body.
615
+ - _response_ - The entire `IncomingMessage` response object.
616
+ - _eid_ - The exchange id.
617
+
618
+ An 'exchange' is a request/response couple.
619
+ Event handlers receive the exchange id in all events.
620
+ The exchange id is the same for the requests events and the responses events, this way you can use it to retrieve the matching request
621
+ when an response event is received.
622
+
623
+ By default exchange ids are generated by using node-uuid but you can use options in client calls to pass your own exchange id.
624
+
625
+ Example :
626
+
627
+ ```javascript
628
+ client.MyService.MyPort.MyFunction(args , function(err, result) {
629
+
630
+ }, {exchangeId: myExchangeId})
631
+ ```
632
+
633
+
634
+ ## Security
635
+
636
+ `node-soap` has several default security protocols. You can easily add your own
637
+ as well. The interface is quite simple. Each protocol defines these optional methods:
638
+ * `addOptions(options)` - a method that accepts an options arg that is eventually passed directly to `request`.
639
+ * `addHeaders(headers)` - a method that accepts an argument with HTTP headers, to add new ones.
640
+ * `toXML()` - a method that returns a string of XML to be appended to the SOAP headers. Not executed if `postProcess` is also defined.
641
+ * `postProcess(xml, envelopeKey)` - a method that receives the the assembled request XML plus envelope key, and returns a processed string of XML. Executed before `options.postProcess`.
642
+
643
+ ### BasicAuthSecurity
644
+
645
+ ``` javascript
646
+ client.setSecurity(new soap.BasicAuthSecurity('username', 'password'));
647
+ ```
648
+
649
+ ### BearerSecurity
650
+
651
+ ``` javascript
652
+ client.setSecurity(new soap.BearerSecurity('token'));
653
+ ```
654
+
655
+ ### ClientSSLSecurity
656
+
657
+ _Note_: If you run into issues using this protocol, consider passing these options
658
+ as default request options to the constructor:
659
+ * `rejectUnauthorized: false`
660
+ * `strictSSL: false`
661
+ * `secureOptions: constants.SSL_OP_NO_TLSv1_2` (this is likely needed for node >= 10.0)
662
+
663
+ If you want to reuse tls sessions, you can use the option `forever: true`.
664
+
665
+ ``` javascript
666
+ client.setSecurity(new soap.ClientSSLSecurity(
667
+ '/path/to/key',
668
+ 'path/to/cert',
669
+ '/path/to/ca-cert', /*or an array of buffer: [fs.readFileSync('/path/to/ca-cert/1', 'utf8'),
670
+ 'fs.readFileSync('/path/to/ca-cert/2', 'utf8')], */
671
+ { /*default request options like */
672
+ // strictSSL: true,
673
+ // rejectUnauthorized: false,
674
+ // hostname: 'some-hostname'
675
+ // secureOptions: constants.SSL_OP_NO_TLSv1_2,
676
+ // forever: true,
677
+ },
678
+ ));
679
+ ```
680
+
681
+ ### ClientSSLSecurityPFX
682
+
683
+ _Note_: If you run into issues using this protocol, consider passing these options
684
+ as default request options to the constructor:
685
+ * `rejectUnauthorized: false`
686
+ * `strictSSL: false`
687
+ * `secureOptions: constants.SSL_OP_NO_TLSv1_2` (this is likely needed for node >= 10.0)
688
+
689
+ If you want to reuse tls sessions, you can use the option `forever: true`.
690
+
691
+ ``` javascript
692
+ client.setSecurity(new soap.ClientSSLSecurityPFX(
693
+ '/path/to/pfx/cert', // or a buffer: [fs.readFileSync('/path/to/pfx/cert', 'utf8'),
694
+ 'path/to/optional/passphrase',
695
+ { /*default request options like */
696
+ // strictSSL: true,
697
+ // rejectUnauthorized: false,
698
+ // hostname: 'some-hostname'
699
+ // secureOptions: constants.SSL_OP_NO_TLSv1_2,
700
+ // forever: true,
701
+ },
702
+ ));
703
+ ```
704
+
705
+ ### WSSecurity
706
+
707
+ `WSSecurity` implements WS-Security. UsernameToken and PasswordText/PasswordDigest is supported.
708
+
709
+ ``` javascript
710
+ var options = {
711
+ hasNonce: true,
712
+ actor: 'actor'
713
+ };
714
+ var wsSecurity = new soap.WSSecurity('username', 'password', options)
715
+ client.setSecurity(wsSecurity);
716
+ ```
717
+ the `options` object is optional and can contain the following properties:
718
+ * `passwordType`: 'PasswordDigest' or 'PasswordText' (default: `'PasswordText'`)
719
+ * `hasTimeStamp`: adds Timestamp element (default: `true`)
720
+ * `hasTokenCreated`: adds Created element (default: `true`)
721
+ * `hasNonce`: adds Nonce element (default: `false`)
722
+ * `mustUnderstand`: adds mustUnderstand=1 attribute to security tag (default: `false`)
723
+ * `actor`: if set, adds Actor attribute with given value to security tag (default: `''`)
724
+
725
+ ### WSSecurityCert
726
+
727
+ WS-Security X509 Certificate support.
728
+
729
+ ``` javascript
730
+ var privateKey = fs.readFileSync(privateKeyPath);
731
+ var publicKey = fs.readFileSync(publicKeyPath);
732
+ var password = ''; // optional password
733
+ var wsSecurity = new soap.WSSecurityCert(privateKey, publicKey, password);
734
+ client.setSecurity(wsSecurity);
735
+ ```
736
+
737
+ ## Handling XML Attributes, Value and XML (wsdlOptions).
738
+ Sometimes it is necessary to override the default behaviour of `node-soap` in order to deal with the special requirements
739
+ of your code base or a third library you use. Therefore you can use the `wsdlOptions` Object, which is passed in the
740
+ `#createClient()` method and could have any (or all) of the following contents:
741
+ ```javascript
742
+ var wsdlOptions = {
743
+ attributesKey: 'theAttrs',
744
+ valueKey: 'theVal',
745
+ xmlKey: 'theXml'
746
+ }
747
+ ```
748
+ If nothing (or an empty Object `{}`) is passed to the `#createClient()` method, the `node-soap` defaults (`attributesKey: 'attributes'`, `valueKey: '$value'` and `xmlKey: '$xml'`) are used.
749
+
750
+ ### Overriding the `value` key
751
+ By default, `node-soap` uses `$value` as the key for any parsed XML value which may interfere with your other code as it
752
+ could be some reserved word, or the `$` in general cannot be used for a key to start with.
753
+
754
+ You can define your own `valueKey` by passing it in the `wsdl_options` to the createClient call:
755
+ ```javascript
756
+ var wsdlOptions = {
757
+ valueKey: 'theVal'
758
+ };
759
+
760
+ soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) {
761
+ // your code
762
+ });
763
+ ```
764
+
765
+ ### Overriding the `xml` key
766
+ By default, `node-soap` uses `$xml` as the key to pass through an XML string as is; without parsing or namespacing it. It overrides all the other content that the node might have otherwise had.
767
+
768
+ For example :
769
+ ```javascript
770
+ {
771
+ dom: {
772
+ nodeone: {
773
+ $xml: '<parentnode type="type"><childnode></childnode></parentnode>',
774
+ siblingnode: 'Cant see me.'
775
+ },
776
+ nodetwo: {
777
+ parentnode: {
778
+ attributes: {
779
+ type: 'type'
780
+ },
781
+ childnode: ''
782
+ }
783
+ }
784
+ }
785
+ };
786
+ ```
787
+ could become
788
+ ```xml
789
+ <tns:dom>
790
+ <tns:nodeone>
791
+ <parentnode type="type">
792
+ <childnode></childnode>
793
+ </parentnode>
794
+ </tns:nodeone>
795
+ <tns:nodetwo>
796
+ <tns:parentnode type="type">
797
+ <tns:childnode></tns:childnode>
798
+ </tns:parent>
799
+ </tns:nodetwo>
800
+ </tns:dom>
801
+ ```
802
+
803
+ You can define your own `xmlKey` by passing it in the `wsdl_options` object to the createClient call:
804
+ ```javascript
805
+ var wsdlOptions = {
806
+ xmlKey: 'theXml'
807
+ };
808
+
809
+ soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) {
810
+ // your code
811
+ });
812
+ ```
813
+
814
+ ### Overriding the `attributes` key
815
+ By default, `node-soap` uses `attributes` as the key to define a nodes attributes.
816
+
817
+ ``` javascript
818
+ {
819
+ parentnode: {
820
+ childnode: {
821
+ attributes: {
822
+ name: 'childsname'
823
+ },
824
+ $value: 'Value'
825
+ }
826
+ }
827
+ }
828
+ ```
829
+ could become
830
+ ``` xml
831
+ <parentnode>
832
+ <childnode name="childsname">Value</childnode>
833
+ </parentnode>
834
+ ```
835
+
836
+ However, `attributes` may be a reserved key for some systems that actually want a node called `attributes`
837
+ ```xml
838
+ <attributes>
839
+ </attributes>
840
+ ```
841
+
842
+ You can define your own `attributesKey` by passing it in the `wsdl_options` object to the createClient call:
843
+ ```javascript
844
+ var wsdlOptions = {
845
+ attributesKey: '$attributes'
846
+ };
847
+
848
+ soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) {
849
+ client.method({
850
+ parentnode: {
851
+ childnode: {
852
+ $attributes: {
853
+ name: 'childsname'
854
+ },
855
+ $value: 'Value'
856
+ }
857
+ }
858
+ });
859
+ });
860
+ ```
861
+ ### Specifying the exact namespace definition of the root element
862
+ In rare cases, you may want to precisely control the namespace definition that is included in the root element.
863
+
864
+ You can specify the namespace definitions by setting the `overrideRootElement` key in the `wsdlOptions` like so:
865
+ ```javascript
866
+ var wsdlOptions = {
867
+ overrideRootElement: {
868
+ namespace: 'xmlns:tns',
869
+ xmlnsAttributes: [{
870
+ name: 'xmlns:ns2',
871
+ value: "http://tempuri.org/"
872
+ }, {
873
+ name: 'xmlns:ns3',
874
+ value: "http://sillypets.com/xsd"
875
+ }]
876
+ }
877
+ };
878
+ ```
879
+
880
+ To see it in practice, have a look at the sample files in: [test/request-response-samples/addPets__force_namespaces](https://github.com/vpulim/node-soap/tree/master/test/request-response-samples/addPets__force_namespaces)
881
+
882
+ ### Custom Deserializer
883
+
884
+ Sometimes it's useful to handle deserialization in your code instead of letting node-soap do it.
885
+ For example if the soap response contains dates that are not in a format recognized by javascript, you might want to use your own function to handle them.
886
+
887
+ To do so, you can pass a `customDeserializer` object in `options`. The properties of this object are the types that your deserializer handles itself.
888
+
889
+ Example :
890
+ ```javascript
891
+
892
+ var wsdlOptions = {
893
+ customDeserializer: {
894
+
895
+ // this function will be used to any date found in soap responses
896
+ date: function (text, context) {
897
+ /* text is the value of the xml element.
898
+ context contains the name of the xml element and other infos :
899
+ {
900
+ name: 'lastUpdatedDate',
901
+ object: {},
902
+ schema: 'xsd:date',
903
+ id: undefined,
904
+ nil: false
905
+ }
906
+
907
+ */
908
+ return text;
909
+ }
910
+ }
911
+ };
912
+
913
+ soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) {
914
+ ...
915
+ });
916
+
917
+ ```
918
+
919
+ ### Changing the tag formats to use self-closing (empty element) tags
920
+ The XML specification specifies that there is no semantic difference between `<Tag></Tag>` and `<Tag />`, and node-soap defaults to using the `<Tag></Tag>` format. But if your web service is particular, or if there is a stylistic preference, the `useEmptyTag` option causes tags with no contents to use the `<Tag />` format instead.
921
+
922
+ ```javascript
923
+ var wsdlOptions = {
924
+ useEmptyTag: true
925
+ };
926
+ ```
927
+
928
+ For example: `{ MyTag: { attributes: { MyAttr: 'value' } } }` is:
929
+
930
+ * **Without useEmptyTag**: `<MyTag MyAttr="value"></MyTag>`
931
+ * **With useEmptyTag set to true**: `<MyTag MyAttr="value" />`
932
+
933
+ ## Handling "ignored" namespaces
934
+ If an Element in a `schema` definition depends on an Element which is present in the same namespace, normally the `tns:`
935
+ namespace prefix is used to identify this Element. This is not much of a problem as long as you have just one `schema` defined
936
+ (inline or in a separate file). If there are more `schema` files, the `tns:` in the generated `soap` file resolved mostly to the parent `wsdl` file,
937
+ which was obviously wrong.
938
+
939
+ `node-soap` now handles namespace prefixes which shouldn't be resolved (because it's not necessary) as so called `ignoredNamespaces`
940
+ which default to an Array of 3 Strings (`['tns', 'targetNamespace', 'typedNamespace']`).
941
+
942
+ If this is not sufficient for your purpose you can easily add more namespace prefixes to this Array, or override it in its entirety
943
+ by passing an `ignoredNamespaces` object within the `options` you pass in `soap.createClient()` method.
944
+
945
+ A simple `ignoredNamespaces` object, which only adds certain namespaces could look like this:
946
+ ```
947
+ var options = {
948
+ ignoredNamespaces: {
949
+ namespaces: ['namespaceToIgnore', 'someOtherNamespace']
950
+ }
951
+ }
952
+ ```
953
+ This would extend the `ignoredNamespaces` of the `WSDL` processor to `['tns', 'targetNamespace', 'typedNamespace', 'namespaceToIgnore', 'someOtherNamespace']`.
954
+
955
+ If you want to override the default ignored namespaces you would simply pass the following `ignoredNamespaces` object within the `options`:
956
+ ```
957
+ var options = {
958
+ ignoredNamespaces: {
959
+ namespaces: ['namespaceToIgnore', 'someOtherNamespace'],
960
+ override: true
961
+ }
962
+ }
963
+ ```
964
+ This would override the default `ignoredNamespaces` of the `WSDL` processor to `['namespaceToIgnore', 'someOtherNamespace']`. (This shouldn't be necessary, anyways).
965
+
966
+ If you want to override the default ignored namespaces you would simply pass the following `ignoredNamespaces` object within the `options`:
967
+ ```
968
+ var options = {
969
+ ignoredNamespaces: {
970
+ namespaces: ['namespaceToIgnore', 'someOtherNamespace'],
971
+ override: true
972
+ }
973
+ }
974
+ ```
975
+ This would override the default `ignoredNamespaces` of the `WSDL` processor to `['namespaceToIgnore', 'someOtherNamespace']`. (This shouldn't be necessary, anyways).
976
+
977
+ ## Handling "ignoreBaseNameSpaces" attribute
978
+ If an Element in a `schema` definition depends has a basenamespace defined but the request does not need that value, for example you have a "sentJob" with basenamespace "v20"
979
+ but the request need only: <sendJob> set in the tree structure, you need to set the ignoreBaseNameSpaces to true. This is set because in a lot of workaround the wsdl structure is not correctly
980
+ set or the webservice bring errors.
981
+
982
+ By default the attribute is set to true.
983
+ An example to use:
984
+
985
+ A simple `ignoredNamespaces` object, which only adds certain namespaces could look like this:
986
+ ```
987
+ var options = {
988
+ ignoredNamespaces: true
989
+ }
990
+ ```
991
+
992
+ ## soap-stub
993
+
994
+ Unit testing services that use soap clients can be very cumbersome. In order to get
995
+ around this you can use `soap-stub` in conjunction with `sinon` to stub soap with
996
+ your clients.
997
+
998
+ ### Example
999
+
1000
+ ```javascript
1001
+ // test-initialization-script.js
1002
+ var sinon = require('sinon');
1003
+ var soapStub = require('soap/soap-stub');
1004
+
1005
+ var urlMyApplicationWillUseWithCreateClient = 'http://path-to-my-wsdl';
1006
+ var clientStub = {
1007
+ SomeOperation: sinon.stub()
1008
+ };
1009
+
1010
+ clientStub.SomeOperation.respondWithError = soapStub.createErroringStub({..error json...});
1011
+ clientStub.SomeOperation.respondWithSuccess = soapStub.createRespondingStub({..success json...});
1012
+
1013
+ soapStub.registerClient('my client alias', urlMyApplicationWillUseWithCreateClient, clientStub);
1014
+
1015
+ // test.js
1016
+ var soapStub = require('soap/soap-stub');
1017
+
1018
+ describe('myService', function() {
1019
+ var clientStub;
1020
+ var myService;
1021
+
1022
+ beforeEach(function() {
1023
+ clientStub = soapStub.getStub('my client alias');
1024
+ soapStub.reset();
1025
+ myService.init(clientStub);
1026
+ });
1027
+
1028
+ describe('failures', function() {
1029
+ beforeEach(function() {
1030
+ clientStub.SomeOperation.respondWithError();
1031
+ });
1032
+
1033
+ it('should handle error responses', function() {
1034
+ myService.somethingThatCallsSomeOperation(function(err, response) {
1035
+ // handle the error response.
1036
+ });
1037
+ });
1038
+ });
1039
+ });
1040
+ ```
1041
+
1042
+
1043
+ ## Contributors
1044
+
1045
+ * Author: [Vinay Pulim](https://github.com/vpulim)
1046
+ * Maintainers:
1047
+ - [Joe Spencer](https://github.com/jsdevel)
1048
+ - [Heinz Romirer](https://github.com/herom)
1049
+ * [All Contributors](https://github.com/vpulim/node-soap/graphs/contributors)
1050
+
1051
+ [downloads-image]: http://img.shields.io/npm/dm/soap.svg
1052
+ [npm-url]: https://npmjs.org/package/soap
1053
+ [npm-image]: http://img.shields.io/npm/v/soap.svg
1054
+
1055
+ [travis-url]: https://travis-ci.org/vpulim/node-soap
1056
+ [travis-image]: http://img.shields.io/travis/vpulim/node-soap.svg
1057
+
1058
+ [gitter-url]: https://gitter.im/vpulim/node-soap
1059
+ [gitter-image]: https://badges.gitter.im/vpulim/node-soap.png
1060
+
1061
+ [coveralls-url]: https://coveralls.io/r/vpulim/node-soap
1062
+ [coveralls-image]: http://img.shields.io/coveralls/vpulim/node-soap/master.svg