Article
· Oct 29, 2018 5m read

Create a Node/Express BackEnd and connect it to IRIS in less you say 'Mississippi'

Here I’ll walk you through the process of creating a simple Node/Express API and connect it to a InterSystems IRIS instance.

I won't go into much detail about how to work with any of the technologies I will mention in this tutorial but I will leave links, in case you want to learn more.

The objective here is to give you a practical guide on how to set up and connect a node.js back-end API to IRIS.

Before we get our hands dirty, make sure you have Node.js running on your machine. So I'll check:

➜ node --version
v8.12.0

Version 8.12.0 is the current LTS (Long Term support) version of node.js.

In case you have to install it go to https://nodejs.org.

Create the Main Project directory

In your terminal, navigate to a directory where you would like to save your project. Now create a new directory for your project and navigate into it:

➜ mkdir amazing_iris_project
➜ cd amazing_iris_project

Create an Express App

Ok, this will be as straightforward as the previous example. Don’t forget to navigate to your project top folder.

I will be using the Express Application Generator to quickly create an application skeleton and name it api:

➜ npx express-generator api
➜ cd api
➜ npm install
➜ npm start

Let’s see what I have done:

  1. Used npm’s npx to install express-generator globally.
  2. Used express-generator to create an express app and named it api.
  3. cd into the API directory.
  4. Installed all dependencies.
  5. Started the app.

In your browser, navigate to http://localhost:3000/.

If all is ok, you will see the express welcome page. Congratulations! That means you now have a basic Express application running on your local machine. Easy right?

To stop your express app, just press `Ctrl + c` in your terminal.

Install the InterSystems IRIS node adaptor

npm get all the packages for you except iris.node that must be copy manually. So you should copy the iris.node file to /node_module/iris directory (create it if not exists). 

You can get iris.node from WRC or also from the /bin directory of a InterSystems IRIS installed instance. Be careful and check if the copied file is the right version for your node installation. In my case I used node version v8.12.0 so I needed iris800.node. Remember to rename the file to iris.node.

You can get more detail about InterSystems IRIS node adaptor and versions here:
https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=BXJS_intro#BXJS_intro_install

Configure the Database Connection

Well, we can solve this question in many differents ways, but do it simple. Create a new file db/database.js and write this inside:

const iris = require('iris/iris');
const db = new iris.IRIS();
module.exports = db;

With this only three lines we are making "public" to the rest of components a reference to a InterSystems IRIS connection.

Open the Database Connection

Now, we are ready to tell to our Express server that opens the connection when is started. In order to do this we are going to edit the file bin/www.

In any place of this file we can write:

const db = require('../db/database');
const irisConfig = {
  ip_address: '127.0.0.1',
  tcp_port: 51773,
  username: 'superuser',
  password: '*********',
  namespace: 'USER'
};

Here we are declaring two objects, first object is the Database reference (from the file we build just a moment ago) and second object is an object containing the necessary data to open the connection (change to fit your needs, user, password, namespace, etc.).

After that, modify the onListening function in this way:

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);

  db.open(irisConfig, (error, result) => {
    if (error) {
      debug(result);
    } else {
      console.log('IRIS connection opened!');
    }
  });

}

We are just opening the connection to the database once the Express server is up and ready to listen.

You can start the server after that and check if we get the pretty message "IRIS connection opened!" in that case well done!!

Go for a coffee if you want you deserve it!! laugh

Let's go for more

How was the coffee? good? well is the right time to go for more fun.

When the server is running what happen when you open a browser and go to http://localhost:3000/users/?
Yes, you see the message "respond with a resource". surprise What a heck? from where it's coming?

I try to explain it. Express use Routing to decide how an application's endpoint (URI) respond to client requests (more info here http://expressjs.com/en/guide/routing.html) and... ok cool better take a look to the code ... If you open app.js you can see a line like this one:

var usersRouter = require('./routes/users');

and later something like:

app.use('/users', usersRouter);


With that lines we are telling to Express that every request to path /users must be route to the code in /routes/users.js. So let's go to that file and review it. Look this function:

/* GET users listing. */
router.get('/', function(req, res, next) {
  res.send('respond with a resource');
});

Not so complex right? What if we use this function and get some data from the InterSystems IRIS instance? wink

Add this line at beginning of the file:

const db = require('../db/database');

And rewrite the method like this:

router.get('/', function(req, res, next) {
  db.get({global:'test'}, function (error, result) {
    if (error) {
      res.status(500).send(result);
    } else {
      res.status(200).send('global test='+result.data);
    }
  })

});

This method now will returns the value inside the InterSystems IRIS Global ^test.

Super!! we are almost done. Write something at this global opening a terminal session in IRIS. Something like:

root@iris:/# iris session IRIS
Node: iris, Instance: IRIS
Username: superuser
Password: ****
USER>set ^test="Hello from IRIS"


Use the browser and go again to http://localhost:3000/users/. What happen now?

Yes!! You did it!! Do the victory dance !! laugh

Did you enjoy? 

Of course, this project as it is won’t do much, but is the start of a Full Stack Application.

If you want to get more of this, give me one star any comment and I'll make you the Master Developer of Full Stack Cosmic Applications ever!!!

Discussion (3)3
Log in or sign up to continue

Once upon a time promised to make Server-Side JavaScript alongside with Caché ObjectScript and Caché Basic:

I found a JS Runtime Shell that uses Node.JS & esprima:

SAMPLES>##class(%CPT.JS.Runtime.Shell).Run()
 
JRS> ?
 
.L CLASS   - load javascript methods from CLASS into JS global namespace
.LV var,.. - load the given COS public vars into JS global namespace
 
.S FUNC  - list the source of the method which implements function FUNC
           - FUNC must be in the global namespace
           - the whole implementing method is shown, even for an inner function
           - this will also work for non-javascript methods
.M       - list MAC code from latest compilation
.I       - list INT code from latest compilation
.T       - show latest tree
 
.G       - list global symbols
 
.N CODE  - execute JS on node.js
.N       - execute the last-entered line of JS on node.js
 
.CONFIG ... - passed to %CPT.CalloutShell 'CONFIG' command
 
.SET ... - passed to %CPT.CalloutShell 'SET' command
.CLEAR ... - passed to %CPT.CalloutShell 'CLEAR' command
.SHOW ... - passed to %CPT.CalloutShell 'SHOW' command
 
!COS     - execute a line of COS
 
Anything else is interpreted as JS. :-
* if preceded by "=" it must be a single function definition
* otherwise it can be either a single expression or a sequence
  of statements separated by ";"s
 
Either way it will be compiled into a function body and :-
* if preceded by "==" it is stored as a JS global with the new function's name
* otherwise it will just be executed
 
\n can be used to represent a newline.
 
You can also take input from a file :-
 <FILE    - read JS from FILE and compile+execute it
 <=FILE   - read JS from FILE and compile+store it
 
The result of the execution is shown and also stored in global variable '_'.
 
For a global variable, set it without using 'var' (this will be fixed)


JRS> .N var obj { name: "John", age: 30, city: "New York" }; JSON.stringify(obj);
{result: "{""name"":""John"",""age"":30,""city"":""New York""}"}

JRS> .N Math.random()
{result: .5670654247514904}

JRS> .N var fruits ["Banana""Orange""Apple""Mango"]; fruits.sort();
{result: ["Apple", "Banana", "Mango", "Orange", 1: "Apple", 2: "Banana", 3: "Mango", 4: "Orange"]}

JRS> q
 
SAMPLES>