Show in Frame No Frame
Up Previous Next Title Page Index Contents Search

Browser
Node.js using callback for results
Node.js using async and await

9.2.5 API with JavaScript

The MetaEdit+ API can be called from JavaScript, e.g. from a browser or Node.js. Support was tested with jQuery SOAP 1.7.3 in Chrome 90 and 140, and node-soap 1.3.0 in Node.js v24.

To allow calling from a browser, the MetaEdit+ API server supports CORS, responding to the preflight HTTP OPTIONS method by sending 204 with keepAlive and:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Content-type, Soapaction
So that the browser XmlHttpRequest does not strip the replied information, API replies include the same allowed origin of anywhere:
Access-Control-Allow-Origin: *

Browser

To open the Digital Watch example’s TST graph (oid: 9_389) synchronously using jQuery SOAP 1.7.3 in Chrome 140:
1)Download the jquery.soap zip and expand it to a new folder
2)Log in with MetaEdit+ to the demo repository, opening project Digital Watch
3)Open the API Tool (main launcher, Repository | API Tool) and press Start Server
4)Press Save WSDL, and save MetaEdit.wsdl in the jquery.soap folder’s web subfolder
5)Open index.html from the jquery.soap web subfolder
6)Change the following values in the fields on the index.html page

Field
Value
url
http://localhost:6390/MetaEditAPI
method
open
appendMethodToURL
false
HTTPHeaders
{}
envAttributes
{ 'xmlns:ns': 'http://metacase.com/wsdl/' }
SOAPHeader
JSON
Contents:

data
JSON
Contents:
{
receiver: {
areaID: 9,
objectID: 389
}
}
namespace
ns http://metacase.com/wsdl/
7)Press the Start jQuery.soap Test!! button at the bottom of the page

The resulting JavaScript code is shown on the right, followed by the SOAP request body and SOAP response body.
01 $.soap({
02   url: "http://localhost:6390/MetaEditAPI",
03   method: "open",
04   appendMethodToURL: false,
05   timeout: 5000,
06   HTTPHeaders: {},
07   envAttributes: { 'xmlns:ns': 'http://metacase.com/wsdl/' },
08   data: { 
09     receiver: { 
10       areaID: 9,
11       objectID: 389
12     }
13   },
14   namespaceQualifier: "ns",
15   namespaceURL: "http://metacase.com/wsdl/",
16   enableLogging: true
17 });
In your own code, you can set the unchanging parts of the $.soap configuration first:
01 $.soap({
02   url: "http://localhost:6390/MetaEditAPI",
03   appendMethodToURL: false,
04   timeout: 5000,
05   HTTPHeaders: {},
06   envAttributes: { 'xmlns:ns': 'http://metacase.com/wsdl/' },
07   namespaceQualifier: "ns",
08   namespaceURL: "http://metacase.com/wsdl/",
09   enableLogging: true
10 });
Each SOAP call is then shorter:
01 $.soap({
02   method: "open",
03   data: { 
04     receiver: { 
05       areaID: 9,
06       objectID: 389
07     }
08   }
09 });

Node.js using callback for results

To open the Digital Watch example’s TST graph (oid: 9_389) using node-soap 1.3.0 in Node.js v24, e.g. in Visual Studio Code with launch.json using type “node”:
01 class MEOop {
02   constructor(areaID, objectID) {
03     this.areaID = areaID;
04     this.objectID = objectID;
05   }
06 }
07 class MetaEditAPI {
08   open(graphOop) {
09     let soap = require('soap');
10     let url = __dirname + '/MetaEdit.wsdl';
11     soap.createClient(url, {}, function(err, client) {
12       client.open( { receiver: graphOop }, function(err, apiFnReturn) {
13         // sync call returns a JavaScript object with property 'result'
14         console.log(JSON.stringify(apiFnReturn.result));
15      });
16     });
17  }
18 }
19 
20 let me = new MetaEditAPI();
21 me.open(new MEOop(9, 389));
Lines 1–6 create a little helper class to represent the MEOop references to repository objects. Line 7 defines a class MetaEditAPI with a single wrapper method, open(), on lines 9–17. Line 20 creates an instance of the MetaEditAPI class, and line 21 calls its open() method with an MEOop instance pointing to the TST graph (oid: 9_389, as seen in its Graph Info).

In the main open() function, lines 9–10 set up the node soap library details, pointing to the MetaEdit.wsdl file that you can save from the MetaEdit+ API Tool. Line 12 creates a Node.js SOAP client. (In a larger program you would want to refactor these out to be reused, rather than created again for each API call.)

In Node.js SOAP, API calls can act on their return values by passing a callback success function to the library function: here, when creating the client succeeds, the callback’s function body on line 12 will be executed. That calls the client’s open() API function (which Node.js SOAP has created automatically based on the WSDL). The first argument is a JavaScript object containing the arguments to the MetaEdit+ API function (here, just the receiver graph’s MEOop). The second argument is another callback, invoked when the MetaEdit+ API function returns. The anonymous callback function body is on line 14, and prints the result property from the MetaEdit+ API function’s return value.

For API methods which return an array, note that the current version of Node.js SOAP seems to have a bug: an empty array [] is returned as null, and a single element array [x] is returned as x. You can use code similar to the following as a workaround for array functions.
var answer = apiFnReturn.result;
if (typeof(answer) === "undefined") {
    console.log("Length == 0 in XML, expected JS Array, got nothing");
    answer = [];       // return an empty Array
} else if (!Array.isArray(answer)) {
    console.log("Length == 1 in XML, expected JS Array, got single object");
    answer = [answer]; // enclose in Array
} else {
    console.log("Length >= 2 in XML, expected JS Array, got Array")
    answer = answer;   // return as is
}

Node.js using async and await

To open the Digital Watch example’s TST graph (oid: 9_389) asynchronously using node-soap 1.3.0 in Node.js v24, e.g. in Visual Studio Code with launch.json using type “node”:
01 class MEOop {
02   constructor(areaID, objectID) {
03     this.areaID = areaID;
04     this.objectID = objectID;
05   }
06 }
07 class MetaEditAPI {
08   async open(graphOop) {
09     let soap = require('soap');
10     let url = __dirname + '/MetaEdit.wsdl';
11     let client = await soap.createClientAsync(url);
12 
13     await this.openAsync(client, graphOop);
14   }
15 
16   async openAsync(client, graphOop) {
17     let openArgs = { receiver: graphOop };
18     let openReturn = await client.openAsync(openArgs);
19     let answer = openReturn[0].result;
20     // async call returns array, first element has result property
21 
22     console.log(JSON.stringify(answer));
23 
24     return answer;   // return as is
25   }
26 }
27 
28 let me = new MetaEditAPI();
29 me.open(new MEOop(9, 389));
Lines 1–6 create a little helper class to represent the MEOop references to repository objects. Line 7 defines a class MetaEditAPI with a wrapper method, open(), on lines 8–14. Lines 16–25 call the actual MetaEdit+ API method. Line 28 creates an instance of the MetaEditAPI class, and line 29 calls its open() method with an MEOop instance pointing to the TST graph (oid: 9_389, as seen in its Graph Info).

In the wrapper open() function, lines 9–10 set up the node soap library details, pointing to the MetaEdit.wsdl file that you can save from the MetaEdit+ API Tool. Line 11 creates a Node.js SOAP client. (In a larger program you would want to refactor these out to be reused, rather than created again for each API call.)

In Node.js SOAP, asynchronous calls require adding async on functions that use them, and the function should await the return of the asynchronous function call. Execution of this program then waits on line 11 while the client is created, and again on line 13 where openAsync() is called (as it will itself wait on line 18 for the SOAP client’s call to the MetaEdit+ API open() function (which Node.js SOAP has created automatically based on the WSDL). The single argument to the API open() function is a JavaScript object containing the arguments to the MetaEdit+ API function (here, just the receiver graph’s MEOop). The result of the API call is passed back as the result property in a JavaScript object, the first element in an array (the rest is other details about the SOAP call). Line 19 pulls the result property from that array, and line 22 and 24 print and return it.

Show in Frame No Frame
Up Previous Next Title Page Index Contents Search