domino-db Quick Start
The domino-db module provides a promise based JavaScript interface for accessing data in a Domino database. It uses the Proton add-in to create, read, update and delete database objects. It uses the Domino Query Language (DQL) to find and perform bulk operations on all documents matching a query, thereby reducing transactions and resulting in improved performance.
Prerequisites
- Node.js and npm. Currently, domino-db requires Node.js 10.x. Node.js 8.x is no longer in active Long Term Support (LTS). We are deprecating support for 8.x before it reaches end of life.
- A Domino server with the Proton add-in running. This server should also have a
copy of node-demo.nsf in the Domino data directory.
- You can find the database in the Domino AppDev Pack.
- Extract the file manually to the domino data directory and update ownership/permission as necessary.
- The domino-db archive file (domino-domino-db-1.11.7.tgz).
Installation
Suppose you have an existing Node.js application. Your application, including your package.json file, lives in a folder called /my-app. Let's also assume you have a copy of the domino-db archive in a folder called /packages.
To add the domino-db module as a dependency:
cd /my-app
npm install /packages/domino-domino-db-1.11.7.tgz --save
The npm install
command fetches the domino-db code and saves the dependency to
package.json.
Quick start
This section shows you how to get started using the domino-db module by creating documents in a Node.js application. It covers only a fraction of the available classes and functions. For a complete list of functions, see the domino-db Reference.
The following assumes you have an existing Node.js application and have added the domino-db module as a dependency. Now suppose you want to create a document in a Domino database.
You start by requiring the domino-db module. Since the module exports only one
function, it is usually recommended to destructure useServer
directly:
const { useServer } = require('@domino/domino-db');
Next, you define a server configuration object. This object describes your
particular Domino server. Be sure to change hostName
and port
to match your
configuration:
const serverConfig = {
hostName: 'your.server.com', // Host name of your server
connection: {
port: '3002', // Proton port on your server
},
};
NOTE: The above assumes Proton is listening for insecure connections on port 3002. If Proton is listening on a different port, change the
port
property. If Proton is using TLS, you need to specify additional properties. See Secure network requests for details.
To acquire an instance of a Server object, call useServer
with the server
configuration:
useServer(serverConfig).then(async server => {
// TODO: Add code that uses the Server object
});
Notice useServer
is an asynchronous function. It returns a Promise
object.
When the promise succeeds, the then
handler is executed. This is an ubiquitous
pattern in the domino-db module. All functions are asynchronous.
Before you can create a document, you define two more objects:
const databaseConfig = {
filePath: 'node-demo.nsf', // The database file name
};
const createOptions = {
documents: [
{
Form: 'Contact',
FirstName: 'Aaron',
LastName: 'Aardman',
City: 'Arlington',
State: 'MA',
},
{
Form: 'Contact',
FirstName: 'Brian',
LastName: 'Zelnick',
City: 'Chelmsford',
State: 'MA',
},
],
};
The first object specifies the database on the target server. This example assumes you are using node-demo.nsf from the Domino AppDev Pack. If you haven't already done so, copy node-demo.nsf to your Domino server's data directory now.
The createOptions
object includes a documents
array defining two new
documents. See domino-db Document Schema for details
on how to represent a document as a JavaScript object.
Now you can create multiple documents with just a few lines of code:
useServer(serverConfig).then(async server => {
const database = await server.useDatabase(databaseConfig);
const response = await database.bulkCreateDocuments(createOptions);
// Display the new document UNIDs
const unids = response.documents.map(doc => doc['@unid']);
console.log(`Documents created: ${unids}`);
});
In other words, you acquire a Database object by passing the database
configuration to Server::useDatabase
. Then you create the documents by passing
createOptions
to Database::bulkCreateDocuments
.
Putting it all together, the following code creates two contact documents:
const { useServer } = require('@domino/domino-db');
const serverConfig = {
hostName: 'your.server.com', // Host name of your server
connection: {
port: '3002', // Proton port on your server
},
};
const databaseConfig = {
filePath: 'node-demo.nsf', // The database file name
};
const createOptions = {
documents: [
{
Form: 'Contact',
FirstName: 'Aaron',
LastName: 'Aardman',
City: 'Arlington',
State: 'MA',
},
{
Form: 'Contact',
FirstName: 'Brian',
LastName: 'Zelnick',
City: 'Chelmsford',
State: 'MA',
},
],
};
useServer(serverConfig).then(async server => {
const database = await server.useDatabase(databaseConfig);
const response = await database.bulkCreateDocuments(createOptions);
// Display the new document UNIDs
const unids = response.documents.map(doc => doc['@unid']);
console.log(`Documents created: ${unids}`);
});
Notice we used the ES6 await
syntax in this example. If you prefer not to use
await
, you can replace the last few lines of code with a promise chain.
useServer(serverConfig)
.then(server => {
return server.useDatabase(databaseConfig);
})
.then(database => {
return database.bulkCreateDocuments(createOptions);
})
.then(response => {
// Display the new document UNIDs
const unids = response.documents.map(doc => doc['@unid']);
console.log(`Documents created: ${unids}`);
});
It's up to you whether to use await
syntax or promise chaining!
Secure network requests
To securely connect with Proton on your Domino server, your server configuration object needs to include additional properties as shown below.
const serverConfig = {
hostName: 'your.server.com', // Host name of your server
connection: {
port: '3002', // Proton port on your server
secure: true,
},
credentials: {
rootCertificate,
clientCertificate,
clientKey,
},
};
In this example:
connection.secure
is a boolean value set totrue
credentials.rootCertificate
is aBuffer
object containing the PEM encoding of the server root certificates. This buffer must start with-----BEGIN CERTIFICATE-----
.credentials.clientCertificate
is aBuffer
object containing the PEM encoding of the client's certificate chain. This buffer identifies your application to the Proton add-in. It must start with-----BEGIN CERTIFICATE-----
.credentials.clientKey
is aBuffer
object containing the PEM encoding of the client's private key. This buffer must start with-----BEGIN RSA PRIVATE KEY-----
.
Often, the credentials
properties are initialized from three separate files on
disk. Ultimately, each application developer must decide how to do this, but
here is some sample code showing one way to initialize the properties.
const fs = require('fs');
const path = require('path');
const readFile = fileName => {
try {
return fs.readFileSync(path.resolve(fileName));
} catch (error) {
return undefined;
}
};
const rootCertificate = readFile('./root.crt');
const clientCertificate = readFile('./client.crt');
const clientKey = readFile('./client.key');
After the useServer()
promise is resolved, it is a good practice to clear the
clientKey
buffer. It is each application's responsibility to protect its
private key from potential exploits.