Data Services is a convenient way to integrate MarkLogic into an existing enterprise environment. A data service is a fixed interface over the data managed in MarkLogic expressed in terms of the consuming application. Data services can run queries ("Find eligible insurance plans for an applicant"), updates ("Flag this claim as fraudulent"), or both ("Adjust the rates of plans that haven't made claims in the last year"). A MarkLogic cluster can support dozens or even hundreds of different data services operating over the data and metadata managed in a data hub.
As with Java generalists, a Node.js generalist and a MarkLogic Server expert need the ability to collaborate based on contractual data services that are implemented close to the data as service endpoints and are callable as functions in client programs. In particular:
The initial release doesn't provide a way to generate stubs for endpoint modules or to load the proxy service directory into the modules database. The MarkLogic expert can use the Gradle tasks provided by the Java API for those tasks.
To learn how to create and deploy a Data Services proxy service, follow the instructions in the Creating the Proxy Service Directory section of our Introduction to the Java API. Once you have created the Data Service Proxy, you may return to this chapter to learn how you use Gulp to generate modules as well as how to call them from your Node.js client application.
The following topics are covered:
The service and function declarations can take the following annotations to affect the generated module:
The $jsType annotation supports the mappings listed below for return values.
Declared data type of return value | Mappable JavaScript types |
boolean | boolean (default) string |
dateTime | Date string (default) |
float, int, or unsignedInt | number (default) string |
The $jsType annotation is not supported for other server data types or for parameters.
Parameters accept and implicitly convert JavaScript input values to server data types as follows:
The declarations can also contain $java* annotations, which are ignored in the Node.js environment. Similarly, the $js* annotations are ignored in the Java environment.
Gulp provides a tool for build task execution in Node.js environments that's comparable Gradle in Java environments.
The Node.js API makes it easy to write Gulp pipelines that generate proxy modules. The proxy-generator.js module provides a generate() factory function, which return a Node.js Transform that takes the Gulp Vinyl descriptor for a proxy service directory as input and produces the Gulp Vinyl wrapper for a generated proxy module as output.
Following the Gradle project convention (where ml-modules/root/ds contains proxy service directories), the example below of a gulpfile.js pipes proxy service directories to the proxy module generator and then pipes the generated proxy modules to the lib directory for the project:
'use strict'; const gulp = require('gulp'); const proxy = require('marklogic/lib/proxy-generator.js'); function proxygen() { return gulp.src('ml-modules/root/ds/*') .pipe(proxy.generate()) .pipe(gulp.dest('lib/')); } exports.proxygen = proxygen;
The following Gulp command command is used to process this gulfile.js:
gulp proxygen
The Node.js client modules can use require() to import the generated proxy modules in the usual way and then construct proxy objects and call the methods of the proxy objects to invoke the server endpoints.
Similar to the Interface generated for Java, the JavaScript module generated for Node.js defines and exports a JavaScript class with the following characteristics:
A JavaScript MJS module can be invoked through the /v1/invoke
endpoint. This is the preferred method.
The following listings show a generic example of how a developer might write code to use a Data Service method available on a service you have defined:
// Import the marklocig utilities const marklogic = require('marklogic'); // import the generated class const GENERATED_CLASS = require("./lib/GENERATED_CLASS.js"); // create a client for the host and port as the user const client = marklogic.createDatabaseClient({host:THE_HOST, port:THE_PORT, user:THE_USER, password:THE_PASSWORD}); // construct an instance of the class const theInstance = GENERATED_CLASS.on(client); // call a method of the instance to execute an endpoint on the server const theOutput = theInstance.theMethod(...parameters...);
The method returns either a JavaScript Promise or a stream for the output depending on the $jsOutputMode annotation (as described earlier).
By providing the class instead of providing only a factory for instances, we make it possible to use the class in instanceof tests.