The MarkLogic REST service extension supports the execution of custom code, whether via an inline script or an existing module in your application’s modules database. The MarkLogic Python client supports execution of custom code by simplifying the submission of custom code and converting the multipart response into more useful Python data types.

Table of contents

Setup

The examples below all depend on the instructions in the setup guide having already been performed.

To try out the examples, start a Python shell and first run the following:

from marklogic import Client
client = Client('http://localhost:8000', digest=('python-user', 'pyth0n'))

Executing ad-hoc queries

The v1/eval REST endpoint supports the execution of ad-hoc JavaScript and XQuery queries. Each type of query can be easily submitted via the client:

client.eval(javascript="fn.currentDateTime()")
client.eval(xquery="fn:current-dateTime()")

Variables can optionally be provided via a dict:

results = client.eval(javascript='Sequence.from([{"hello": myValue}])', vars={"myValue": "world"})
assert "world" == results[0]["hello"]

Because the REST endpoint returns a sequence of items, the client will always return a list of values. See the section below on how data types are converted to understand how the client will convert each value into an appropriate Python data type.

Invoking modules

The v1/invoke REST endpoint supports the execution of JavaScript and XQuery main modules that have been deployed to your application’s modules database.

If you wish to attempt the examples below (instead of invoking your own modules), first run the following to insert a simple runnable module into the out-of-the-box “Modules” database:

from marklogic.documents import Document
module = Document('/sample.sjs', 'const doc = {"hello": "world"}; doc', permissions={"rest-reader": ["read", "update", "execute"]})
client.documents.write(module, params={"database": "Modules"})

A module can be invoked via the client in the following manner:

# Set the input to the URI of the module you wish to invoke in your application's 
# modules database.
client.invoke("/sample.sjs")

You can provide variables to your module in the same fashion as when evaluating custom code (the variable will not have any impact on the sample module loaded above; this is shown purely to demonstrate how to define variables):

client.invoke("/sample.sjs", vars={"my_var1": "value1"})

Conversion of data types

The REST endpoints for evaluating ad-hoc code and for invoking a module both return a sequence of values, with each value having MarkLogic-specific type information. The client will use this type information to convert each value into an appropriate Python data type. For example, each JSON object into the example below is converted into a dict:

results = client.eval(javascript='Sequence.from([{"doc": 1}, {"doc": 2}])')
assert len(results) == 2
assert results[0]["doc"] == 1
assert results[1]["doc"] == 2

The following table describes how each MarkLogic type is associated with a Python data type. For any MarkLogic type not listed in the table, such as hexBinary and base64Binary, the value is not converted and will remain of type bytes.

MarkLogic type Python type
string str
integer int
boolean bool
decimal Decimal
map dict
element() str
array list
array-node() list
object-node() dict or marklogic.documents.Document
document-node() str or marklogic.documents.Document
binary() bytes or marklogic.documents.Document

For the object-node(), document-node(), and binary() entries in the above table, a marklogic.documents.Document instance will be returned if the value is associated with a URI via the multipart X-URI header. Otherwise, a value of type dict, str, or bytes is returned respectively.

Returning the original HTTP response

Each client.eval method and client.invoke accept a return_response argument. When that argument is set to True, the original response is returned. This can be useful for custom processing of the response or debugging requests.

Referencing a transaction

The client.eval and client.invoke functions both support referencing a REST API transaction via the tx argument. See the guide on transactions for further information.

Providing additional arguments

The client.eval and client.invoke methods each provide a **kwargs argument, so you can pass in any other arguments you would normally pass to requests. For example:

client.eval(javascript="fn.currentDateTime()", params={"database": "Documents"})
client.invoke("/sample.sjs", params={"database": "Documents"})

Please see the eval endpoint documentation and the invoke endpoint documentation for information on additional parameters.