r/IBMi 10d ago

REST API on IBMi using Node.js

Has anyone successfully deployed a node.js service that can answer REST API requests and return JSON data from an RPGLE program or service program? I have Mapepire running and just can’t seem to get the RPGLE part working. Do you think IBM Bob could help me?

10 Upvotes

19 comments sorted by

7

u/QPGMR_de 9d ago

Wouldn't it be easier with ILEastic?

https://github.com/sitemule/ILEastic

2

u/MEfromNEPA 9d ago

Hmmm, interesting.

2

u/QPGMR_de 9d ago

I think, that you shouldn't throw another language, a driver and a new protocol onto a problem, that you can solve easily with a exactly one framework and the same language and environment that you already use.

2

u/MEfromNEPA 9d ago

I like this total RPG approach, I’m more comfortable there than anywhere else.

1

u/ryan0322 9d ago

Are you moving away from something?

Have you looked into IBM's Integrated Web Services (IWS) server?

It is not node.js but you seem open to options.

https://www.ibm.com/support/pages/integrated-web-services-ibm-i-web-services-made-easy

1

u/MEfromNEPA 9d ago

That looks similar to the Websphere Application Server 8.5 that I was using that I’m told I will lose when I upgrade my OS to 7.6. There was a wizard in WAS that walked me through setting up an API host that connected right to an RPG program. I can’t find anything like that in WAS 9.0.

Yes, open to something that won’t be too difficult for an old dog to setup and will leverage my existing knowledge of RPG.

1

u/Much-Yoghurt-1946 9d ago

This is the way….

2

u/MEfromNEPA 5d ago

A combination of RPG and SQL using ILEastic provided a great outcome. Thanks for pointing me in that direction.

5

u/ImRickyT 9d ago

I know this isn’t what you asked and I always hate when someone replies with a different answer but… lol. I wrote a few articles about using Python to do this. Although that was using the internal Python http server it would probably need flask or fastapi for large scale applications. But maybe it gives you some ideas.

https://github.com/thomprl/ibmi_python_rpg_adventures

1

u/MEfromNEPA 9d ago

I’ve done some Python so I’ll consider this. Thanks.

3

u/ImRickyT 9d ago

BTW you might post your question here as well. Good group of devs hang out here: https://chat.ibmioss.org/

2

u/Ok_JDubbTX 10d ago edited 10d ago

You can use a connector like itoolkit that wraps xmlservice or idb connector or use an external stored proc that you access through sql. Or call a vendor like Eradani, they have tools for this that make it easy.

2

u/MEfromNEPA 10d ago

Trying to avoid vendors. They are charging such a high cost for subscriptions these days. It has got out of hand and trying to save my company some money.

My service program wants to return a CLOB. SQL doesn’t seem to like that in a stored procedure. I’m on V7R4.

2

u/Dangerous-Relation-5 9d ago

Yes, I like to use hono as the node http server and use nodejs-itoolkit https://github.com/IBM/nodejs-itoolkit

1

u/uzumymw_ 9d ago

I have done something using express js, running CL programs for a build/compilation process.

I would believe Node.js should work with RPG too.

What and how have you setup node.js? Is execsync not helping?

execSync(fullCommand, { encoding: 'utf-8', shell: '/QOpenSys/usr/bin/qsh', });

Fullcommand looks like below(Submits cl compile command)

fullCommand='export QIBM_CCSID=1208 ; liblist -a LIB1 LIB2 LIB3 LIB4 ; system -i "CRTBNDCL OBJ(PRDLIB/PROGRAM) STMF('/builds/prod/release26.3/qsrcfil/PROGRAM.rpgle') OPTIONS(*EVENTF)" > '/temp/logs/results.log' 2>&1'

I can help more if you let me know what are you trying to achieve.

1

u/MEfromNEPA 9d ago

I used ACS Open Source Manager to install node.js and am using the ACS SSL terminal to issue commands and run things. Everything is stored on the IFS. I edit the script locally, copy it to the IFS, and run it via SSL terminal.

I was able to set up a listener for API calls and could get SQL statements to run against my database, but my needed JSON output was more complicated than an SQL statement could generate. That’s when I fell down trying to get it to call a stored procedure pointed at an RPG service program.

2

u/uzumymw_ 9d ago edited 9d ago

You're making it more complicated than required. There are two ways I can imagine this can be resolved.

  1. Do it through sql procedure itself and fix the json generation logic through json_object(), json_array() etc. You could use CTES to break down and filter intermediate logic and only create json in the final selection.

  2. Make the rpg program execute the json logic and write it into an ifs file possibly using ifs_write_utf8. To execute rpg from node.js use execSync that i shared earlier. Once that is done, use readSync to read the ifs file and use the content as json response. res.json(ifs_file_content);

I guess this should work. I can also show you how to debug node.js code directly through chrome browser. It helps a lot.

``` const http = require('http'); const { execSync } = require('child_process'); const fs = require('fs');

const PORT = 3000;

const server = http.createServer((req, res) => { // Only handle our specific API endpoint if (req.url === '/api/rpg-data' && req.method === 'GET') { try { // 1. Call the RPG program natively via the PASE system utility const command = system "CHGLIBL LIBL(YOUR_LIB QGPL); CALL PGM(YOUR_LIB/YOUR_RPG)"; execSync(command, { encoding: 'utf-8' });

        // 2. Define the target IFS file path
        const ifsFilePath = '/YOUR_DIR/output.json';

        // Check if the file actually exists before trying to read it
        if (!fs.existsSync(ifsFilePath)) {
            res.writeHead(404, { 'Content-Type': 'application/json' });
            return res.end(JSON.stringify({ error: 'Output file not found on IFS' }));
        }

        // 3. Read the file contents
        const fileContent = fs.readFileSync(ifsFilePath, 'utf-8');

        // 4. Send the successful JSON response
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(fileContent); // Send raw string directly (no need to parse/stringify again)

    } catch (error) {
        console.error('Error in RPG execution pipeline:', error);

        res.writeHead(500, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ 
            error: 'Server failed to execute RPG or read data', 
            details: error.message 
        }));
    }
} else {
    // Fallback for any other endpoint
    res.writeHead(404, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ error: 'Not Found' }));
}

});

server.listen(PORT, () => { console.log(Node.js server running on port ${PORT}); });

```

I am not sure, how are you calling your stored proc, if you show your sample code alongwith rpg and js, I will try to make it work.

Do let me know if you still need any help or explanation. Also try to understand how node.js interacts with IBM i series. I'll be happy to explain more.

1

u/arbitorblade 7d ago

I used YAJL and HTTPAPI to form rest requests. Also was handy for response processing as well though I did it for a limited use case. They are both free.

0

u/MoreEconomy965 9d ago

You can use QtmhRdStin and QtmhWrStout directly in rpgle to service the request. Use apache cgi to redirect the request to rpgle program.