@itentialopensource/adapter-metaswitch 1.0.3 → 1.2.1

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.
package/TAB2.md CHANGED
@@ -11,7 +11,17 @@
11
11
  ## Specific Adapter Information
12
12
  ### Authentication
13
13
 
14
- This document will go through the steps for authenticating the Metaswitch adapter with Basic Authentication. Properly configuring the properties for an adapter in Itential Platform is critical for getting the adapter online. You can read more about adapter authentication <a href="https://docs.itential.com/opensource/docs/authentication" target="_blank">HERE</a>.
14
+ This document will go through the steps for authenticating the Metaswitch adapter with Basic Authentication. Properly configuring the properties for an adapter in Itential Platform is critical for getting the adapter online. You can read more about adapter authentication <a href="https://docs.itential.com/opensource/docs/authentication" target="_blank">HERE</a>.
15
+
16
+ #### Overview
17
+
18
+ **Version 1.1.0+** includes automatic SOAP envelope wrapping with WS-Security credentials. The adapter now:
19
+ - Automatically wraps XML payloads in SOAP envelopes
20
+ - Embeds credentials using WS-Security UsernameToken standard
21
+ - Removes the need for workflows to handle SOAP envelopes or credentials
22
+ - Maintains 100% backward compatibility with existing workflows
23
+
24
+ **Security Enhancement**: Credentials are never exposed in workflow payloads. They are securely stored in adapter configuration and automatically embedded at the adapter level.
15
25
 
16
26
  #### Basic Authentication
17
27
  The Metaswitch adapter requires Basic Authentication. If you change authentication methods, you should change this section accordingly and merge it back into the adapter repository.
@@ -32,7 +42,56 @@ STEPS
32
42
  ```
33
43
  you can leave all of the other properties in the authentication section, they will not be used when the auth_method is basic user_password.
34
44
 
35
- 4. Restart the adapter. If your properties were set correctly, the adapter should go online.
45
+ 4. Restart the adapter. If your properties were set correctly, the adapter should go online.
46
+
47
+ #### Automatic SOAP Envelope Wrapping (v1.1.0+)
48
+
49
+ The adapter automatically wraps all XML payloads in SOAP envelopes with WS-Security credentials. This happens transparently at the adapter level.
50
+
51
+ ##### How It Works
52
+
53
+ **Workflows send XML only:**
54
+ ```xml
55
+ <UserDataRequest>
56
+ <UserId>12345</UserId>
57
+ <DataReference>RepositoryData</DataReference>
58
+ </UserDataRequest>
59
+ ```
60
+
61
+ **Adapter automatically wraps with SOAP + Credentials:**
62
+ ```xml
63
+ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
64
+ xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
65
+ <soapenv:Header>
66
+ <wsse:Security soapenv:mustUnderstand="1">
67
+ <wsse:UsernameToken>
68
+ <wsse:Username>admin</wsse:Username>
69
+ <wsse:Password Type="...#PasswordText">password</wsse:Password>
70
+ </wsse:UsernameToken>
71
+ </wsse:Security>
72
+ </soapenv:Header>
73
+ <soapenv:Body>
74
+ <UserDataRequest>
75
+ <UserId>12345</UserId>
76
+ <DataReference>RepositoryData</DataReference>
77
+ </UserDataRequest>
78
+ </soapenv:Body>
79
+ </soapenv:Envelope>
80
+ ```
81
+
82
+ ##### Key Features
83
+
84
+ - **Automatic Detection**: If your workflow already sends a SOAP envelope, the adapter detects it and skips wrapping
85
+ - **Zero Migration**: Existing workflows continue working without changes
86
+ - **Secure Credentials**: Username/password from adapter config are automatically embedded
87
+ - **API-Specific**: Correct namespaces applied based on API type (EAS, NSeries, Metaview, NWSAP)
88
+
89
+ ##### Security Best Practices
90
+
91
+ 1. **Always use HTTPS**: Credentials are sent as PasswordText in WS-Security headers
92
+ 2. **Restrict adapter access**: Only authorized workflows should call the adapter
93
+ 3. **Rotate credentials**: Change passwords periodically in adapter configuration
94
+ 4. **Monitor logs**: Review adapter logs for authentication failures
36
95
 
37
96
  #### Troubleshooting
38
97
  - Make sure you copied over the correct username and password.
@@ -45,6 +104,34 @@ you can leave all of the other properties in the authentication section, they wi
45
104
  - Credentials should be ** masked ** by the adapter so make sure you verify the username and password - including that there are erroneous spaces at the front or end.
46
105
  - Remember when you are done to turn auth_logging off as you do not want to log credentials.
47
106
 
107
+ ##### SOAP Wrapper Troubleshooting (v1.1.0+)
108
+
109
+ If you encounter issues with the automatic SOAP wrapping:
110
+
111
+ **Error: "Empty payload body provided"**
112
+ - The adapter received an empty or null payload
113
+ - Verify your workflow is sending XML content in the body parameter
114
+
115
+ **Error: "Missing authentication credentials in adapter configuration"**
116
+ - The adapter cannot find username or password in properties.authentication
117
+ - Verify the authentication section is configured correctly (see above)
118
+
119
+ **Error: "SOAP Envelope Error"**
120
+ - General SOAP wrapping failure
121
+ - Check adapter logs for detailed error messages
122
+ - Verify the XML payload is well-formed
123
+
124
+ **Existing SOAP envelope not detected:**
125
+ - If your workflow sends a SOAP envelope and it's being double-wrapped:
126
+ - Ensure the envelope uses one of these prefixes: `soapenv:`, `soap:`, or `SOAP-ENV:`
127
+ - The detection looks for `<soapenv:Envelope`, `<soap:Envelope`, or `<SOAP-ENV:Envelope`
128
+
129
+ **Testing SOAP wrapper:**
130
+ - Send a simple XML payload through the adapter
131
+ - Check the FULL REQUEST log to see the generated SOAP envelope
132
+ - Verify credentials are properly embedded in the wsse:Security header
133
+ - Confirm the Metaswitch API accepts the request
134
+
48
135
  ### Sample Properties
49
136
 
50
137
  Sample Properties can be used to help you configure the adapter in the Itential Platform. You will need to update connectivity information such as the host, port, protocol and credentials.
package/adapter.js CHANGED
@@ -97,7 +97,12 @@ class Metaswitch extends AdapterBaseCl {
97
97
 
98
98
  // The generic adapter functions should already be ignored (e.g. healthCheck)
99
99
  // you can add specific methods that you do not want to be workflow functions to ignore like below
100
- // myIgnore.push('myMethodNotInWorkflow');
100
+ // Exclude SOAP utility methods from workflow functions
101
+ myIgnore.push('wrapBodyInSoapEnvelope');
102
+ myIgnore.push('getSoapNamespaces');
103
+ myIgnore.push('buildOriginHost');
104
+ myIgnore.push('injectOriginHost');
105
+ myIgnore.push('escapeXml');
101
106
 
102
107
  return super.iapGetAdapterWorkflowFunctions(myIgnore);
103
108
  }
@@ -645,6 +650,193 @@ class Metaswitch extends AdapterBaseCl {
645
650
  return super.iapGetAdapterInventory(callback);
646
651
  }
647
652
 
653
+ /* SOAP SECURITY UTILITY METHODS */
654
+ /**
655
+ * @function wrapBodyInSoapEnvelope
656
+ * @summary Wraps request body in SOAP envelope and injects OriginHost with credentials
657
+ *
658
+ * @param {string} body - The inner XML payload (without SOAP envelope and OriginHost)
659
+ * @param {string} apiType - API type (EAS, NSeries, Metaview, NWSAP) for namespace handling
660
+ *
661
+ * @returns {object} Object containing the updated SOAP payload
662
+ * @returns {string} returns.payload - The complete SOAP envelope with credentials
663
+ * @returns {Error} returns.error - Error object if parsing or serialization fails
664
+ */
665
+ wrapBodyInSoapEnvelope(body, apiType = 'EAS') {
666
+ const meth = 'adapter-wrapBodyInSoapEnvelope';
667
+ const origin = `${this.id}-${meth}`;
668
+ log.trace(origin);
669
+
670
+ try {
671
+ // Validate body is present (before any processing)
672
+ if (!body || body.trim() === '') {
673
+ return { error: new Error('Empty payload body provided') };
674
+ }
675
+
676
+ // Detect if payload is already a SOAP envelope (skip wrapping)
677
+ const trimmedBody = body.trim();
678
+ if (trimmedBody.includes('<soapenv:Envelope')
679
+ || trimmedBody.includes('<soap:Envelope')
680
+ || trimmedBody.includes('<SOAP-ENV:Envelope')) {
681
+ log.debug(`${origin}: Payload already contains SOAP envelope, skipping wrap`);
682
+ return { payload: body, alreadyWrapped: true };
683
+ }
684
+
685
+ // Build OriginHost with credentials from adapter properties
686
+ const originHostResult = this.buildOriginHost();
687
+ if (originHostResult.error) {
688
+ return { error: originHostResult.error };
689
+ }
690
+
691
+ // Inject OriginHost into the body XML (append before any closing tags)
692
+ const bodyWithOriginHost = this.injectOriginHost(body, originHostResult.originHost);
693
+
694
+ // Determine namespace based on API type
695
+ const namespaces = this.getSoapNamespaces(apiType);
696
+
697
+ // Construct SOAP envelope with minimal header (Metaswitch pattern)
698
+ const soapEnvelope = `<soapenv:Envelope ${namespaces}>
699
+ <soapenv:Header/>
700
+ <soapenv:Body>${bodyWithOriginHost}</soapenv:Body>
701
+ </soapenv:Envelope>`;
702
+
703
+ return { payload: soapEnvelope };
704
+ } catch (ex) {
705
+ log.error(`${origin}: Exception wrapping SOAP envelope: ${ex.message}`);
706
+ return { error: ex };
707
+ }
708
+ }
709
+
710
+ /**
711
+ * @function getSoapNamespaces
712
+ * @summary Returns SOAP namespace declarations for specific Metaswitch API
713
+ *
714
+ * @param {string} apiType - API type (EAS, NSeries, Metaview, NWSAP)
715
+ * @returns {string} Namespace declaration string
716
+ */
717
+ // eslint-disable-next-line class-methods-use-this
718
+ getSoapNamespaces(apiType) {
719
+ const commonNamespaces = 'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"';
720
+
721
+ // API-specific namespaces based on Metaswitch documentation
722
+ const apiNamespaces = {
723
+ EAS: 'xmlns:sh="http://www.metaswitch.com/sdp/soap/sh"',
724
+ NSeries: 'xmlns:sh="http://www.metaswitch.com/nsrs/soap/sh"',
725
+ Metaview: 'xmlns:sh="http://www.metaswitch.com/ems/soap/sh"',
726
+ NWSAP: 'xmlns:sh="http://www.metaswitch.com/srb/soap/sh"'
727
+ };
728
+
729
+ return `${commonNamespaces} ${apiNamespaces[apiType] || apiNamespaces.EAS}`;
730
+ }
731
+
732
+ /**
733
+ * @function buildOriginHost
734
+ * @summary Builds OriginHost XML element with credentials from adapter properties
735
+ * Following Metaswitch pattern: server@domain?clientVersion=X.X&adminName=XXX&password=YYY
736
+ *
737
+ * @returns {object} Object containing the OriginHost XML or error
738
+ * @returns {string} returns.originHost - The OriginHost XML element
739
+ * @returns {Error} returns.error - Error object if credentials are missing
740
+ */
741
+ buildOriginHost() {
742
+ const meth = 'adapter-buildOriginHost';
743
+ const origin = `${this.id}-${meth}`;
744
+ log.trace(origin);
745
+
746
+ try {
747
+ // Get credentials and connection info from adapter properties
748
+ const auth = this.allProps.authentication || {};
749
+ const conn = this.allProps.properties || {};
750
+
751
+ // Validate required credentials
752
+ if (!auth.username || !auth.password) {
753
+ return { error: new Error('Missing username or password in adapter authentication configuration') };
754
+ }
755
+
756
+ // Build OriginHost value following Metaswitch sample pattern
757
+ // Format: server@domain?clientVersion=X.X&adminName=XXX&password=YYY&ignoreSequenceNumber=true
758
+ const server = conn.host || 'server';
759
+ const domain = conn.domain || 'domain';
760
+ const clientVersion = conn.clientVersion || '1.0';
761
+
762
+ // URL-encode credentials to handle special characters
763
+ const adminName = encodeURIComponent(auth.username);
764
+ const password = encodeURIComponent(auth.password);
765
+
766
+ const originHostValue = `${server}@${domain}?clientVersion=${clientVersion}&adminName=${adminName}&password=${password}&ignoreSequenceNumber=true`;
767
+
768
+ // Return as XML element (will be inserted into SOAP body)
769
+ const originHostXml = `<OriginHost>${this.escapeXml(originHostValue)}</OriginHost>`;
770
+
771
+ log.debug(`${origin}: Built OriginHost for ${server}@${domain} with user ${auth.username}`);
772
+
773
+ return { originHost: originHostXml };
774
+ } catch (ex) {
775
+ log.error(`${origin}: Exception building OriginHost: ${ex.message}`);
776
+ return { error: ex };
777
+ }
778
+ }
779
+
780
+ /**
781
+ * @function injectOriginHost
782
+ * @summary Injects OriginHost element into the body XML before closing tags
783
+ * Metaswitch expects OriginHost as the last element in ShPull/ShUpdate
784
+ *
785
+ * @param {string} body - The XML body content (ShPull or ShUpdate operation)
786
+ * @param {string} originHost - The OriginHost XML element to inject
787
+ * @returns {string} Body XML with OriginHost injected
788
+ */
789
+ // eslint-disable-next-line class-methods-use-this
790
+ injectOriginHost(body, originHost) {
791
+ const meth = 'adapter-injectOriginHost';
792
+ const origin = `${this.id}-${meth}`;
793
+ log.trace(origin);
794
+
795
+ try {
796
+ // Find the closing tag of the root element (ShPull, ShUpdate, etc.)
797
+ // OriginHost should be inserted just before this closing tag
798
+ const closingTagMatch = body.match(/<\/(sh:)?(ShPull|ShUpdate|ShSubs|ShNotif)>/);
799
+
800
+ if (closingTagMatch) {
801
+ const closingTag = closingTagMatch[0];
802
+ const insertPosition = body.lastIndexOf(closingTag);
803
+
804
+ // Insert OriginHost before the closing tag with proper indentation
805
+ const modifiedBody = `${body.substring(0, insertPosition)} ${originHost}\n${body.substring(insertPosition)}`;
806
+
807
+ log.debug(`${origin}: Injected OriginHost before ${closingTag}`);
808
+ return modifiedBody;
809
+ }
810
+
811
+ // If no recognized Metaswitch operation tag found, append at the end
812
+ // This handles cases where the body is a simple XML fragment
813
+ log.warn(`${origin}: No recognized Metaswitch operation tag found, appending OriginHost to body`);
814
+ return `${body}\n${originHost}`;
815
+ } catch (ex) {
816
+ log.error(`${origin}: Exception injecting OriginHost: ${ex.message}`);
817
+ // Return original body if injection fails (fail gracefully)
818
+ return `${body}\n${originHost}`;
819
+ }
820
+ }
821
+
822
+ /**
823
+ * @function escapeXml
824
+ * @summary Escapes special XML characters in strings
825
+ *
826
+ * @param {string} str - String to escape
827
+ * @returns {string} XML-safe string
828
+ */
829
+ // eslint-disable-next-line class-methods-use-this
830
+ escapeXml(str) {
831
+ if (!str) return '';
832
+ return str
833
+ .replace(/&/g, '&amp;')
834
+ .replace(/</g, '&lt;')
835
+ .replace(/>/g, '&gt;')
836
+ .replace(/"/g, '&quot;')
837
+ .replace(/'/g, '&apos;');
838
+ }
839
+
648
840
  /**
649
841
  * @callback healthCallback
650
842
  * @param {Object} result - the result of the get request (contains an id and a status)
@@ -703,11 +895,18 @@ class Metaswitch extends AdapterBaseCl {
703
895
  return callback(null, errorObj);
704
896
  }
705
897
 
898
+ // Wrap body in SOAP envelope with credentials
899
+ const soapResult = this.wrapBodyInSoapEnvelope(body, 'EAS');
900
+ if (soapResult.error) {
901
+ log.error(`${origin}: SOAP envelope wrapping failed - ${soapResult.error.message}`);
902
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'SOAP Envelope Error', null, null, null, soapResult.error);
903
+ return callback(null, errorObj);
904
+ }
905
+
706
906
  /* HERE IS WHERE YOU SET THE DATA TO PASS INTO REQUEST */
707
907
  const queryParamsAvailable = {};
708
908
  const queryParams = {};
709
909
  const pathVars = [];
710
- const bodyVars = body;
711
910
 
712
911
  // loop in template. long callback arg name to avoid identifier conflicts
713
912
  Object.keys(queryParamsAvailable).forEach((thisKeyInQueryParamsAvailable) => {
@@ -720,7 +919,7 @@ class Metaswitch extends AdapterBaseCl {
720
919
  // set up the request object - payload, uriPathVars, uriQuery, uriOptions, addlHeaders, authData, callProperties, filter, priority, event
721
920
  // see adapter code documentation for more information on the request object's fields
722
921
  const reqObj = {
723
- payload: bodyVars,
922
+ payload: soapResult.payload,
724
923
  uriPathVars: pathVars,
725
924
  uriQuery: queryParams
726
925
  };
@@ -785,11 +984,18 @@ class Metaswitch extends AdapterBaseCl {
785
984
  return callback(null, errorObj);
786
985
  }
787
986
 
987
+ // Wrap body in SOAP envelope with credentials
988
+ const soapResult = this.wrapBodyInSoapEnvelope(body, 'NSeries');
989
+ if (soapResult.error) {
990
+ log.error(`${origin}: SOAP envelope wrapping failed - ${soapResult.error.message}`);
991
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'SOAP Envelope Error', null, null, null, soapResult.error);
992
+ return callback(null, errorObj);
993
+ }
994
+
788
995
  /* HERE IS WHERE YOU SET THE DATA TO PASS INTO REQUEST */
789
996
  const queryParamsAvailable = {};
790
997
  const queryParams = {};
791
998
  const pathVars = [];
792
- const bodyVars = body;
793
999
 
794
1000
  // loop in template. long callback arg name to avoid identifier conflicts
795
1001
  Object.keys(queryParamsAvailable).forEach((thisKeyInQueryParamsAvailable) => {
@@ -802,7 +1008,7 @@ class Metaswitch extends AdapterBaseCl {
802
1008
  // set up the request object - payload, uriPathVars, uriQuery, uriOptions, addlHeaders, authData, callProperties, filter, priority, event
803
1009
  // see adapter code documentation for more information on the request object's fields
804
1010
  const reqObj = {
805
- payload: bodyVars,
1011
+ payload: soapResult.payload,
806
1012
  uriPathVars: pathVars,
807
1013
  uriQuery: queryParams
808
1014
  };
@@ -867,11 +1073,18 @@ class Metaswitch extends AdapterBaseCl {
867
1073
  return callback(null, errorObj);
868
1074
  }
869
1075
 
1076
+ // Wrap body in SOAP envelope with credentials
1077
+ const soapResult = this.wrapBodyInSoapEnvelope(body, 'Metaview');
1078
+ if (soapResult.error) {
1079
+ log.error(`${origin}: SOAP envelope wrapping failed - ${soapResult.error.message}`);
1080
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'SOAP Envelope Error', null, null, null, soapResult.error);
1081
+ return callback(null, errorObj);
1082
+ }
1083
+
870
1084
  /* HERE IS WHERE YOU SET THE DATA TO PASS INTO REQUEST */
871
1085
  const queryParamsAvailable = {};
872
1086
  const queryParams = {};
873
1087
  const pathVars = [];
874
- const bodyVars = body;
875
1088
 
876
1089
  // loop in template. long callback arg name to avoid identifier conflicts
877
1090
  Object.keys(queryParamsAvailable).forEach((thisKeyInQueryParamsAvailable) => {
@@ -884,7 +1097,7 @@ class Metaswitch extends AdapterBaseCl {
884
1097
  // set up the request object - payload, uriPathVars, uriQuery, uriOptions, addlHeaders, authData, callProperties, filter, priority, event
885
1098
  // see adapter code documentation for more information on the request object's fields
886
1099
  const reqObj = {
887
- payload: bodyVars,
1100
+ payload: soapResult.payload,
888
1101
  uriPathVars: pathVars,
889
1102
  uriQuery: queryParams
890
1103
  };
@@ -949,11 +1162,18 @@ class Metaswitch extends AdapterBaseCl {
949
1162
  return callback(null, errorObj);
950
1163
  }
951
1164
 
1165
+ // Wrap body in SOAP envelope with credentials
1166
+ const soapResult = this.wrapBodyInSoapEnvelope(body, 'NWSAP');
1167
+ if (soapResult.error) {
1168
+ log.error(`${origin}: SOAP envelope wrapping failed - ${soapResult.error.message}`);
1169
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'SOAP Envelope Error', null, null, null, soapResult.error);
1170
+ return callback(null, errorObj);
1171
+ }
1172
+
952
1173
  /* HERE IS WHERE YOU SET THE DATA TO PASS INTO REQUEST */
953
1174
  const queryParamsAvailable = {};
954
1175
  const queryParams = {};
955
1176
  const pathVars = [];
956
- const bodyVars = body;
957
1177
 
958
1178
  // loop in template. long callback arg name to avoid identifier conflicts
959
1179
  Object.keys(queryParamsAvailable).forEach((thisKeyInQueryParamsAvailable) => {
@@ -966,7 +1186,7 @@ class Metaswitch extends AdapterBaseCl {
966
1186
  // set up the request object - payload, uriPathVars, uriQuery, uriOptions, addlHeaders, authData, callProperties, filter, priority, event
967
1187
  // see adapter code documentation for more information on the request object's fields
968
1188
  const reqObj = {
969
- payload: bodyVars,
1189
+ payload: soapResult.payload,
970
1190
  uriPathVars: pathVars,
971
1191
  uriQuery: queryParams
972
1192
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itentialopensource/adapter-metaswitch",
3
- "version": "1.0.3",
3
+ "version": "1.2.1",
4
4
  "description": "This adapter integrates with system described as: Metaswitch.",
5
5
  "main": "adapter.js",
6
6
  "wizardVersion": "3.12.1",
@@ -11,6 +11,25 @@
11
11
  "systemx.customer.com"
12
12
  ]
13
13
  },
14
+ "domain": {
15
+ "type": "string",
16
+ "description": "domain name for OriginHost parameter (Metaswitch authentication)",
17
+ "default": "domain",
18
+ "examples": [
19
+ "customer.com",
20
+ "metaswitch.local"
21
+ ]
22
+ },
23
+ "clientVersion": {
24
+ "type": "string",
25
+ "description": "client version for OriginHost parameter (Metaswitch API version)",
26
+ "default": "1.0",
27
+ "examples": [
28
+ "1.0",
29
+ "1.6",
30
+ "2.0"
31
+ ]
32
+ },
14
33
  "port": {
15
34
  "type": "integer",
16
35
  "description": "port on which to connect to the server",
@@ -1,10 +1,10 @@
1
1
  {
2
- "version": "0.4.6",
3
- "configLines": 4658,
4
- "scriptLines": 2498,
5
- "codeLines": 2492,
6
- "testLines": 4001,
7
- "testCases": 171,
8
- "totalCodeLines": 8991,
2
+ "version": "1.2.0",
3
+ "configLines": 4722,
4
+ "scriptLines": 2523,
5
+ "codeLines": 2750,
6
+ "testLines": 4416,
7
+ "testCases": 200,
8
+ "totalCodeLines": 9689,
9
9
  "wfTasks": 29
10
10
  }
@@ -116,12 +116,12 @@
116
116
  }
117
117
  },
118
118
  "requestBody": {
119
- "description": "indeterminate body object",
120
119
  "content": {
121
120
  "application/json": {
122
121
  "schema": {
123
122
  "type": "object"
124
- }
123
+ },
124
+ "example": {}
125
125
  }
126
126
  }
127
127
  }
@@ -247,12 +247,12 @@
247
247
  }
248
248
  },
249
249
  "requestBody": {
250
- "description": "indeterminate body object",
251
250
  "content": {
252
251
  "application/json": {
253
252
  "schema": {
254
253
  "type": "object"
255
- }
254
+ },
255
+ "example": {}
256
256
  }
257
257
  }
258
258
  }
@@ -520,12 +520,12 @@
520
520
  }
521
521
  },
522
522
  "requestBody": {
523
- "description": "indeterminate body object",
524
523
  "content": {
525
524
  "application/json": {
526
525
  "schema": {
527
526
  "type": "object"
528
- }
527
+ },
528
+ "example": {}
529
529
  }
530
530
  }
531
531
  }
@@ -812,12 +812,12 @@
812
812
  }
813
813
  },
814
814
  "requestBody": {
815
- "description": "indeterminate body object",
816
815
  "content": {
817
816
  "application/json": {
818
817
  "schema": {
819
818
  "type": "object"
820
- }
819
+ },
820
+ "example": {}
821
821
  }
822
822
  }
823
823
  }