Kunal Roy
Kunal Roy

Reputation: 787

Doing an external webservice call from rpgle program

I need to write a Rpgle program which needs to do a POST call (SOAP call) to an external webservice (the external webservice is a different java based system) in order to get invoice value based on certain inputs. Is there an inbuilt rpgle subprogram through which I can make this call. If yes can can anyone suggest what is that. If NO then can anyone suggest how to achieve this?

An appropriate answer will be highly appreciated.

Upvotes: 0

Views: 860

Answers (2)

Charles
Charles

Reputation: 23823

There are two parts for the answer to this question.

  1. How to interact with the web service
  2. How to build / consume the required XML based SOAP document

Interacting with the web service

  • As suggested in another answer, IBM provides some built-in HTTP functionality for use via SQL. Note there are older Java based functions in QSYSTOOL, the newer tools in QSYS2 are preferred.
  • IBM Also provides the Integrated web services client for ILE
  • Lastly, there are various commercial or open source tools such as Scott Klement's excellent open source HTTP API

Building / Consuming SOAP XML
This is where things may get difficult. SOAP documents tend to be rather complex, which is why JSON has gotten popular. And contrary to REST ideals, retrieving data in SOAP often requires a POST'ing a SOAP document rather than a simple GET. Without examples of the document you need to POST and the document you expect to retrieve, it's hard to offer specific guidance.

  • Db2 offers various XML related functions such as XMLPARSE() and XMLTABLE() for consuming XML (as shown in the linked question in the other answer).
  • Db2 provides other XMLxxx functions for generating XML.
  • RPG offers the XML-INTO and XML-SAX op-codes for consuming XML.
  • IBM's previously mentioned Integrated web services client for ILE includes a wsdl2rpg script for generating a service programs stub programs to create and consume web services that provide Web Service Definition Language (WSDL) specs; as is often the case for SOAP services.
  • There's an open source WSDL2RPG tool (which came before IBM's tool) that generates RPGLE code for interacting with a WSDL defined web service using the open source HTTP API mentioned above.

If you're new to calling web services from the IBM i, I recommend Scott Klement's excellent Web Services for RPGer's presentation. It also talks about the open source wsdl2rpg generator.

Cool Things: ILE RPG as a Web Services Client shows using IBM's Integrated web services client. The programming manual is also useful.

Upvotes: 1

WStanzl
WStanzl

Reputation: 304

SQL provides the functionality you need.

Your best starting point is this example, taken from https://colemaxwell.dev/posts/rest-api-ibmi-qsys2/

SELECT *
    FROM JSON_TABLE(
        QSYS2.HTTP_GET(
            'http://fakestoreapi.com/products?limit=10',
            ''
        ),
        '$' COLUMNS(
            name VARCHAR(75) PATH 'lax $.title',
            totalRatings INT PATH 'lax $.rating.count'
        )
    );

Embed that in your RPG program.

This example receives JSON format; you did not tell in your question which data format the service you use returns.

You mentioned you want to use POST. Strictly speaking, this should be a GET request, according to this (very good document): https://www.ibm.com/docs/en/i/7.4?topic=programming-http-functions-overview but a POST request would also work. There is also a QSYS2.HTTP_POST SQL function, which works in a similar way.

Implemented in a raw SQLRPGLE program, it looks like the following (adapt as you require):

**FREE
DCL-S sUrlQuery VARCHAR(256);
DCL-S iLimit INT(10);
DCL-S sName CHAR(10);
DCL-S iTotalRatings INT(10);

iLimit = 10;
sUrlQuery = 'http://fakestoreapi.com/products?' + 
            'limit=' + %CHAR(iLimit);
EXEC SQL
   SELECT name, totalRatings INTO :sName, :iTotalRatings
   FROM JSON_TABLE(
           QSYS2.HTTP_GET(:sUrlQuery,''),
           '$' COLUMNS(
               name VARCHAR(75) PATH 'lax $.title',
               totalRatings INT PATH 'lax $.rating.count'
           )
        );

DSPLY sName;
DSPLY iTotalRatings;

*INLR = '1';

EDIT:

THE XML variant has already been answered here:

Get an XML from WEB with a SQL DB2 on Iseries

My (tested working) version of it:

**FREE

DCL-S sUrlQuery VARCHAR(256);
DCL-S sDateSel CHAR(8);
DCL-S sCode CHAR(3);
DCL-S sCurrency CHAR(10);
DCL-S dXRate PACKED(15: 5);

sCode = 'usd';
sDateSel = '20240223';
sUrlQuery = 'https://www.backend-rates.ezv.admin.ch/api/xmldaily?' +
            'd=' + sDateSel;

EXEC SQL        
    SELECT Waehrung, Kurs INTO :sCurrency, :dXRate 
    FROM XMLTABLE(
        XMLNAMESPACES (DEFAULT 'https://www.backend-rates.ezv.admin.ch/xmldaily'),
       '$doc/wechselkurse/devise'
        PASSING XMLPARSE 
            (DOCUMENT SYSTOOLS.HTTPGETCLOB(:sUrlQuery, '')) as "doc" 
       COLUMNS 
          code Char(3) PATH '@code',
          waehrung char(10) PATH 'waehrung' ,
          kurs decfloat PATH 'kurs'
       )
   WHERE Code = :sCode;
        

DSPLY sCode;
DSPLY sCurrency;
DSPLY %CHAR(dXRate);

*INLR = '1';

Upvotes: 1

Related Questions