Web Services
Configure webservice interface
Configuration web services interface in IBM i:
Steps to create Web services on IBM I use Apache HTTP web server:
- Go to below link for IBM web administration for i. http::2001/HTTPAdmin
- The sign in popup will appear, enter the require details
- Click on Create a New HTTP Server.
- Specify the port
- Specify the user id
Set Configuration for Apache web server instance:
- Once the Apache web server instance is created, a default configuration file will be created.
- To access objects from an As400 library through a web service URL, we will add configuration in the configuration file.
- We can access the configuration on the IFS path below and add our configuration.
/www/http_server_instance/conf/httpd.conf - Below is the configuration to access any program in library
ScriptAliasMatch /myPath/([a-z0-9]+)/.* /Qsys.Lib/userlibrary.Lib/$1.pgm
Require all granted
Start the Apache web server Instance:
Once the required configuration are added and saved in the file then we can start our Apache web server instance using the below commands:
STRTCPSVR SERVER(*HTTP) RESTART(*HTTP) HTTPSVR(Apache_server_instance)
Service program for web service program:
- IBM I service program QZHBCGI
- This service program has many procedures, that are helpful to create a web service program.
- Below are the most common procedure
- QtmhGetEnv- to get environment information like REQUEST_URI, REQUEST_METHOD, CONTENT_TYPE header info.
- QtmhRdStin – To read the request body data coming from web service.
- QtmhWrStout – To write the response to the web service.
- We can create a binding directory, add the QZHBCGI service program in the binding directory, and add binding directory to use those procedures.
Configuring an integrated Web application server Instance:
Steps to configure the Web serving environment:
- Start the IBM Web Administration for i interface.
- Start a 5250 session to the system.
- Sign on with a user profile that has at least these special authorities:
*ALLOBJ, *IOSYSCFG, *JOBCTL, and *SECADM. - Run the following command to start the web administration interface job:
STRTCPSVR SERVER(*HTTP) HTTPSVR(*ADMIN)
- Start a 5250 session to the system.
- Create an integrated Web application server instance.
-
- Open a browser to http://:2001/HTTPAdmin.
- Log in with a user profile that has, at least these special authorities:
*ALLOBJ, *IOSYSCFG, *JOBCTL, and *SECADM. - Select the Setup tabbed page.
- Under Common Tasks and Wizards, select Create Application Server.
- The Create Application Server page opens. Select Next.
- Select an option under IBM integrated Web application server for i, then select Next.
- The Specify Application Server Name page opens. For Application server name, specify IWAIAS. This will be the name of the integrated Web application server. Select Next.
- The Specify Internal Ports Used by the Application Server page opens. For First port in range, change the default value to 21060. This port number is an example. You should verify this port is available for use, or use a port you know is available. Select Next.
- The Create a new HTTP server (powered by Apache) page opens.
- For HTTP server name, enter IWAIAS
- For Port, specify 2060. This port number is an example. You should verify this port is available for use or use a port you know is available.
- Open a browser to http://:2001/HTTPAdmin.
Select Next.
- The Specify User ID for this Server page opens. Select Next.
- The Sample Applications page is open. Select Next until the Summary page opens.
- Select Finish.
- The Web page is re-displayed with the Manage > Application Servers tabbed page active. Under Server, IWAIAS1 is listed with a status of Creating.
-
- Configure IBM i Access for Web.
- Restore the 5250 session window.
- IBM i Access for Web provides commands to configure the product. Two different commands are provided, a CL command and a Qshell script command. Both commands provide and perform the same function. Use the version which works best for your circumstances.To use the CL command, follow these steps:
- Configure IBM i Access for Web for your Web application server by using the following command:
CFGACCWEB APPSVRTYPE(*INTAPPSVR) INSTANCE(IWAIAS)
These are the parameters used:APPSVRTYPETells the command which Web application server to configure.
INSTANCE
Tells the command which IBM integrated Web application server for i instance to configure.
For help on this command and the parameters, press F1.
Migration Note: If you are already using IBM i Access for Web within another Web application server, refer to the New Web application server considerations topic. This topic discusses additional CFGACCWEB command parameters that can be input to migrate user data from an existing configuration to this new configuration.
- Several messages like these will be displayed:
- Configuring IBM i Access for Web.
- Preparing to perform the configuration changes.
- IBM i Access for Web command has completed.
- Press F3 or Enter when the command completes to exit the display session. To use the Qshell script command, follow these steps:
- Start the Qshell environment by using the following CL command:QSH
- Make the IBM i Access for Web directory the current directory. Run this command:cd /QIBM/ProdData/Access/Web2/install
- Configure IBM i Access for Web for the Web application server previously created:cfgaccweb -appsvrtype “*INTAPPSVR” -instance “IWAIAS”
- Press F3 when the command completes to exit the Qshell session.
- Configure IBM i Access for Web for your Web application server by using the following command:
- If the command were to fail or indicate an error, refer to the log files:
- /QIBM/UserData/Access/Web2/logs/cmds.log
High level, cause and recovery information; translated.
- /QIBM/UserData/Access/Web2/logs/cmdstrace.log
Detailed command flow for IBM Software Service; English only.
- After successfully configuring IBM i Access for Web, the IBM integrated Web application server instance must be restarted to load the changes to its configuration. This will be done later.
- Start the Web environment.
- Return to the browser window that is open to the IBM Web Administration for i server management page.
- The Manage > Application Servers tabbed page should be active. Under Server IWAIAS is listed with a status of Running. Stop and restart the integrated Web application server:
- Select the red icon next to the Running status to stop the integrated Web application server. The IWAIAS1 HTTP server will also be stopped. Select the refresh icon next to the Stopping status to refresh the page if the page does not periodically refresh.
- When the status is updated to Stopped, select the green icon next to Stopped to start the integrated Web application server. The IWAIAS HTTP server will also be started.
- The status will be updated to Starting. Select the refresh icon next to the Starting status to refresh the page if it does not periodically refresh.
IBM i Access for Web will load and start as the integrated Web application server starts.
Consuming webservices
Web Services:
Web Services on AS400(IBM i) allow users to access data and business systems across multiple devices and platforms. They can also be used to automate business processes. IBM i/AS400 System web services use open standards such as the Representational State Transfer (REST) architecture and Open Data Protocol (OData) to offer a comprehensive solution for creating, managing, and deploying enterprise-grade applications.
How do web services work on IBM i Server?
A web service on an IBM i server can be used to provide applications, data, and services to remote users, regardless of their device or location. Web services are a way of exchanging information between two computers over the Internet.
Using web services on an IBM i server involves the set-up of a secure communication channel which is made up of a combination of basic protocols such as Hyper Text Transfer Protocol (HTTP), Simple Object Access Protocol (SOAP), and Web Services Description Language (WSDL).
The benefits of using web services on an IBM i server include improved scalability, better resource management, faster response times, and increased efficiency.
Features and Benefits of Web Services for IBM i:
- Flexible Deployment
- Easy Integration
- Security Features
- Cloud Native Capabilities
- Robust tooling
- Comprehensive Documentation
Typically, the APIs (or web services) are either SOAP-based or REST-based web services. However, REST has gained widespread acceptance across the web as a simpler alternative to SOAP. The key motivator of choosing REST-based web services is their simplicity and their ubiquity:
- It’s about delivering content in the simplest possible way
- HTTP is available everywhere
The concrete implementation of a REST web service follows three basic design principles:
- Use HTTP methods explicitly
- Be stateless.
- Expose directory structure-like Uniform Resource Identifiers (URIs).
The REST architectural style describes six constraints:
- Client – Server
- Stateless
- Cacheable
- Uniform interface
- Layered system
- Code-on-Demand (Optional)
HTTP Request Methods:
- POST (Create) – To create a new resource on the server.
- GET (Read) – To retrieve a resource’s data from the server.
- PUT (Update) – To change the state of a resource or to update it.
- DELETE – To remove or delete a resource.
Tracking Software defects:
- Get /defects – list all bugs.
- Get /defects/123 – Retrieve bug 123.
- POST /defects/123 – Create a new defect 123 with the POST request body.
- PUT /defects/123 – Update defect 123 with the PUT request body.
- DELETE /defects/123 – delete defect 123
HTTP status codes:
200 OK, everything worked as expected. |
201 Created |
202 Accepted |
204 No Content |
301 Moved Permanently |
303 See Other |
304 Not Modified |
307 Temporary Redirect |
400 Bad Request |
401 Unauthorized |
403 Forbidden |
404 Not Found |
406 Not Acceptable |
409 Conflict |
410 Gone |
412 Precondition Failed |
415 Unsupported Media Type |
500 Internal Server Error |
503 Service Unavailable |
Methods to consume Web services on IBM I:
- IBM-Supplied SQL routines.
- SYSTOOLS
- QSYS2
- HTTPAPI
- IBM-Supplied AXIS routines.
Consuming Webservices with IBM-Supplied SQL routines:
IBM i Native SQL routines under QSYS2/SYSTOOLS has various functions to make HTTP requests to web services.
Some commonly used functions are:
- HTTPPOSTCLOBVERBOSE
- HTTPPUTCLOBVERBOSE
- HTTPGETCLOBVERBOSE
- HTTPDELETECLOBVERBOSE
- First added in 2014, just after IBM i 7.2 release.
- You must have a JVM installed.
- Starts the JVM in each job(Performance considerations).
Examples:
- HTTPGETCLOBVERBOSE:
Select Coalesce(Varchar(ResponseMsg,1250), ' '), Varchar(ResponseHttpHeader,1000) From Table(Systools.HttpGetClobVerbose( 'https://gorest.co.in/public/v2/users', ''))
Result:
Sample program:
- HTTPPOSTCLOBVERBOSE:
select Coalesce(Varchar(ResponseMsg,1250), ' '), Varchar(ResponseHttpHeader,2000) From Table(Systools.HttpPostClobVerbose( 'https://gorest.co.in/public/v2/users', '', '{"id":7702935,"name":"Karthick","email":"sktest@corwin.example" ,"gender":"female","status":"active"}'))
Result:
Sample program:
- HTTPDELETECLOBVERBOSE:
Select Coalesce(Varchar(ResponseMsg,1250), ' '), Varchar(ResponseHttpHeader,1000) From Table(Systools.HttpDeleteClobVerbose( 'https://gorest.co.in/public/v2/users', ''))
IBM i functions used for consuming web services from clients:
Schema | Functions |
---|---|
SYSTOOLS | URLENCODE |
SYSTOOLS | URLDECODE |
SYSTOOLS | BASE64ENCODE |
SYSTOOLS | BASE64DECODE |
SYSTOOLS | HTTPHEAD |
SYSTOOLS | HTTPGETBLOB |
SYSTOOLS | HTTPGETBLOBVERBOSE |
SYSTOOLS | HTTPGETCLOB |
SYSTOOLS | HTTPGETCLOBVERBOSE |
SYSTOOLS | HTTPPUTBLOB |
SYSTOOLS | HTTPPUTBLOBVERBOSE |
SYSTOOLS | HTTPPUTCLOB |
SYSTOOLS | HTTPPUTCLOBVERBOSE |
SYSTOOLS | HTTPPOSTBLOB |
SYSTOOLS | HTTPPOSTBLOBVERBOSE |
SYSTOOLS | HTTPPOSTCLOB |
SYSTOOLS | HTTPPOSTCLOBVERBOSE |
SYSTOOLS | HTTPDELETEBLOB |
SYSTOOLS | HTTPDELETEBLOBVERBOSE |
SYSTOOLS | HTTPDELETECLOB |
SYSTOOLS | HTTPDELETECLOBVERBOSE |
SYSTOOLS | HTTPBLOB |
SYSTOOLS | HTTPBLOBVERBOSE |
SYSTOOLS | HTTPCLOB |
SYSTOOLS | HTTPCLOBVERBOSE |
Parsing JSON
Operations on JSON Data in IBM i
A JSON data store is a database that provides the capabilities to store, process, and manage data in JSON format. The JSON feature for Db2 enables a Db2 database to serve as a JSON data store. Before we dive into the way JSON can be parsed using SQL statements, we will see how to store the JSON data in a DB2 file.
Note : Before working with JSON make sure to change the CCSID of the session to 37. You can use CHGJOB command for this purpose. Without this CCSID, you might see the output as 0.
How to Create a Column that can store JSON Data?
JSON data can be stored in Character Large Object, Or CLOB format in a column in Db2. To create a column to store JSON data use CREATE TABLE statement in SQL; specify CLOB as the data type for the field which is supposed to hold the JSON data.
CREATE TABLE qtemp/tmp (JSONDOC CLOB)
Also, you can create a variable which will store a JSON object. Below is the query to create a Variable to hold a JSON object.
CREATE VARIABLE JSON_VAR VARCHAR(2000)
How to Insert a JSON Data into a table?
Normal INSERT INTO query can be used to insert JSON data into a DB2 table.
INSERT INTO qtemp/tmp VALUES ( '{"person":[{"name": "Mike", "age": 25},{"name": "Tom", "age": 21}]}')
Also, you can assign a JSON object as this Variable’s value –
SET JSON_VAR='{ "id" : 105, "name" : { "first":"Sovan", "last":"Kapuria" }, "phones" : [{"type":"home", "number":"2548-9663"}, {"type":"work", "number":"2548-9801"}]}'
How to Retrieve Data that is inside JSON document?
One of the most powerful language elements is JSON_TABLE, this can convert a JSON object into a Database table. For Database based applications, this is helpful as to fetch or parse the values from a JSON object you don’t need to write a program. Instead, you can use only JSON_TABLE.
The JSON_TABLE function consists of three parts.
- The JSON object from which Relational Database will be created.
- A path expression which will help to create one or more rows from the JSON object.
- The definition of the result columns which will be created. These definitions can include the column name, the result data type, and a path expression to use to locate the column information from JSON data.
SELECT t.name, t.age FROM QTemp/tmp a , JSON_TABLE( a.jsondoc,'$.person[*]' COLUMNS ( name VARCHAR(10) PATH '$.name' , age numeric(10) PATH '$.age') ) as t
Below is the output of above query –
Suppose, from the JSON_VAR Variable you want to fetch only ID, First Name and Last Name; then you want to put them in a Database format. So this is how you can achieve that –
SELECT * FROM JSON_TABLE(JSON_VAR, '$' COLUMNS( id VARCHAR(10) PATH '$.id', first VARCHAR(10) PATH '$.name.first', last VARCHAR(10) PATH '$.name.last' ) ) as t
Now that we have a JSON object, we can use JSON_TABLE to fetch values from that JSON object in a database format.
In this example, a SELECT statement is used to invoke JSON_TABLE and that function helps to return all the values which has been asked for.
The global variable JSON_VAR will be used as the input for the JSON_TABLE function.
Here, ‘$’ only references one item in the object, this use of JSON_TABLE will only produce one row.
After the outermost SQL/JSON path expression, the columns are defined. The first column is named ID and has a type of VARCHAR(10). The SQL/JSON path to locate that value is ‘$.id’.
Similarly, this example has columns FIRST and LAST, to get those values you need to locate the value with SQL/JSON Path Expression as ‘$.first’ and ‘$.last’.
This above query will give you below output –
In the above example, a Single row has been created from the JSON object. To retrieve multiple rows using the array elements embedded in the JSON object, NESTED column definition should be used.
A nested column definition begins with the keyword NESTED and is followed by an SQL/JSON path expression which indicates which JSON values are to be processed by the columns within the nested definition. This path expression indicates which elements of an array should be used to produce rows. Typically, the path expression contains ‘[*]’ which indicates that all the elements of an array are handled. After the path, the columns are defined using the COLUMNS keyword, just like the columns that are defined in a regular column definition.
SELECT * FROM JSON_TABLE( JSON_VAR, '$' COLUMNS( first VARCHAR(10) PATH '$.name.first', last VARCHAR(10) PATH '$.name.last' , NESTED PATH '$.phones[*]' COLUMNS ( "type" VARCHAR(10), "number" VARCHAR(10) ) ) ) as t
This query will give output like this –
Now, as there are multiple rows hence ORDINALITY can be used to show the order/count of the data in a RDB format –
SELECT * FROM JSON_TABLE( JSON_VAR, '$' COLUMNS( first VARCHAR(10) PATH '$.name.first', last VARCHAR(10) PATH '$.name.last' , NESTED PATH '$.phones[*]' COLUMNS ( ord FOR ORDINALITY, "type" VARCHAR(10), "number" VARCHAR(10) ) ) ) as t
Above query will give you the output like this –
How to create a JSON with given values?
Now, let’s learn how we can create a JSON with given values using SQL Query. We can use JSON_OBJECT Scalar Function to create or convert given values to a JSON.
First of all, Change the CCSID of the session from 65535 to 1144 or 37. If you do not do that, then you can see below error message popping up during query run –
Character conversion between CCSID 65535 and CCSID 1208 not valid.
Now, CCSID 1208 is not available in IBM i. Hence, that’s the reason we can change the CCSID either to 280, 37 or to 1144. Here, 1144 has been used.
To create JSON Object using JSON_OBJECT scalar function, there might be two scenarios. One method through VALUES and another method through Physical File.
Now, how do we create the query with VALUES Statement –
VALUES JSON_OBJECT (KEY 'ID' VALUE '100', KEY 'NAME' VALUE 'SOVAN')
Here, KEY works like the element ID and VALUE works like the element value. So, if you run this statement using STRSQL then, you will see something like below –
The output does not seem to show anything, by seeing this value no one will understand whether the JSON object’s value is fine or not.
So, what we can do is – wrap this JSON_OBJECT scalar function in a CHAR built-in function; this CHAR can help to convert the JSON data in a readable format. Here is how query can be written –
VALUES CHAR(JSON_OBJECT (KEY 'ID' VALUE '100', KEY 'NAME' VALUE 'SOVAN'))
But, this will not return anything other than an error message.
Result too long.
To resolve this, we may truncate the output till first 100 characters –
VALUES CHAR(JSON_OBJECT (KEY 'ID' VALUE '100', KEY 'NAME' VALUE 'SOVAN'), 100)
Now, you will be able to see something of this new JSON OBJECT. But this does not look decent.
But, how to make the output look decent? More on that later.
Now, let’s see how we can create a JSON Object based on data from Physical file.
I have a physical file which looks like below –
So now, we will try to create a JSON using these two rows of values.
This simple query can be used which is quite similar to the previous statement –
SELECT Char(JSON_OBJECT ( KEY 'ID' VALUE a.ID, KEY 'NAME' VALUE a.NAME ),100) "Department Objects" FROM SKAPURIA/PF_JSON a
This query will give this below output –
Now, how can we see a decent looking output. For that, below steps can be taken.
- Create a Temporary file with this output.
- Once that is created, then copy that output file into an IFS file.
CPYTOIMPF FROMFILE(SKAPURIA/J1) TOSTMF('/home/skapuria/json.txt') RCDDLM(*CRLF) DTAFMT(*FIXED)
How to get JSON values from JSON Data?
The SQL/JSON function JSON_QUERY finds one or more specified JSON values in JSON data and returns the values in a character string.
Suppose, we have below JSON Data –
{"id":"200", "name":{"first":"Sovan", "last":"Kapuria"}}
Now, if we have to get only the JSON value for name from JSON data, then we’ll use JSON_QUERY in the SQL statement. Prior to that, change the session CCSID to 37.
VALUES CHAR(JSON_QUERY('{"id":"200", "name":{"first":"Sovan", "last":"Kapuria"}}', '$.name'),100)
Then this will be the output that we’ll get –
Now suppose, we want to get the value ID from the JSON Data but the output should be enclosed in an array wrapper. By using below SQL statement we can achieve the same.
VALUES CHAR(JSON_QUERY('{"id":"200", "name":{"first":"Sovan", "last":"Kapuria"}}', '$.id' WITH WRAPPER),100)
We’ll get the output like below –
Let’s say, we want to see all the JSON values present in the JSON data while enclosed in the array wrapper. Below query will do that for us.
VALUES CHAR(JSON_QUERY('{"id":"200", "name":{"first":"Sovan", "last":"Kapuria"}}', '$.*' WITH WRAPPER),100)
We’ll get this output –
Now again, let’s suppose we have a JSON array and we need to find the fourth element of that array. Then this is how we can get it.
VALUES CHAR(JSON_QUERY('[2,3,4,5,6]', '$[3]' WITH WRAPPER),100)
We’ll get this in return –
Now suppose, we have a JSON array having five elements and we are trying to find the sixth element from that array. But as the array is not having sixth element, hence this query will end up in error. But there is a clause which can help to handle that error –
VALUES CHAR(JSON_QUERY('[2,3,4,5,6,7]', '$[6]' EMPTY OBJECT ON ERROR),100)
This EMPTY OBJECT ON ERROR clause will return a null value in case the above query hits error.
How to get JSON values in required data type from JSON Data?
The JSON_VALUE function returns an SQL scalar value with required data type from a JSON text using an SQL/JSON path expression.
Suppose, I want a value to be returned from JSON text data in Integer type.
VALUES JSON_VALUE('{"id":"200", "name":{"first":"Sovan", "last":"Kapuria"}}', '$.id' RETURNING INTEGER)
Now, If I want the value to be returned in Decimal data type then below query will help you –
VALUES JSON_VALUE('{"id":"200", "name":{"first":"Sovan", "last":"Kapuria"}}', '$.id' RETURNING DECIMAL)
Again, in some scenario, if I want the value to be returned as a float , then –
VALUES JSON_VALUE('{"id":"200", "name":{"first":"Sovan", "last":"Kapuria"}}', '$.id' RETURNING FLOAT)
Now, I’ll try to return a value from a JSON text which is an array value. In case nothing is found, then it should return ‘Not Found’.
VALUES CHAR(JSON_VALUE('[2,3,4,5,6,7]', '$[*]' DEFAULT 'NOT FOUND' ON ERROR),100)
As this is an array hence JSON_VALUE is not able to return a particular scalar value.
How to create JSON Array based on given values?
Suppose we have few values, and we need to create a JSON Array out of it. For that purpose, Scalar Function JSON_ARRAY is used.
Here, I have names of 3 city, and I want to create a JSON Array for these 3. Below is the Query for IBM i to achieve the same.
VALUES CHAR((JSON_ARRAY('Delhi', 'Mumbai', 'Bangalore')),100)
This is the output of the above query –
This array can be created using values present in physical file as well.
PF_JSON has below data –
Now, I would want to create an array based on all the IDs present in the file –
VALUES CHAR(JSON_ARRAY(SELECT ID FROM SKAPURIA/PF_JSON),100)
Below is the output that we’ll get –
Parsing XML
XML Parser
The XML domain is very similar to the XMLNS domain, but the XML domain has no support for XML namespaces or opaque parsing.
The XML domain is deprecated, but existing message flows that use the XML domain continue to work. Use the XMLNSC domain when developing new message flows.
The XML parser is not model-driven and does not use an XML Schema when parsing XML documents.
If you want the XML domain to parse a particular message, you must select Message Domain as XML on the appropriate node in the message flow.
Features Of the XML Parser
Feature | Present | Description |
---|---|---|
Namespace support | No | |
On-demand parsing | Yes | |
Compact message tree | No | |
Opaque parsing | No | |
Ultra high performance | No | |
Validation | No | |
Inline DTD support | Yes | Inline DTDs are processed and retained in the message tree. |
XML Data Model compliance | Yes | The resultant message tree conforms to the XML Data Model. |
XMLNSC Parser
The XMLNSC parser is a flexible, general-purpose XML parser that offers high performance XML parsing and optional XML Schema validation.
The XMLNSC parser has a range of options that make it suitable for most XML processing requirements. Some of these options are only available in the XMLNSC parser.
Although the XMLNSC parser is capable of parsing XML documents without an XML Schema, extra features of the parser become available when it operates in model-driven mode. In model-driven mode, the XMLNSC parser is guided by an XML Schema, which describes the shape of the message tree (the logical model).
XML Schemas are created automatically from the content of a message set when the message set is added to a BAR file. The XML Schemas are deployed to the integration node and used by the XMLNSC parser to validate your XML messages. Validation is fully compliant with the XML Schema 1.0 specification.
Features Of the XMLNSC Parser
Feature | Present |
---|---|
Namespace support | Yes |
On-demand parsing | Yes |
Compact message tree | Yes |
Opaque parsing | Yes |
Ultra high performance | Yes |
Validation | Yes |
Inline DTD support | Partial |
XML Data Model compliance | Partial |
XMLNS Parser
The XMLNS parser is a flexible, general-purpose XML parser.
The XMLNS parser is not model-driven and does not use an XML Schema when parsing XML documents.
Features Of the XMLNS Parser
Feature | Present |
---|---|
Namespace support | Yes |
On-demand parsing | Yes |
Compact message tree | No |
Opaque parsing | Partial |
Ultra high performance | No |
Validation | No |
Inline DTD support | Yes |
XML Data Model compliance | Yes |
Opcode : XML-INTO is used to parse an XML document into variable.
XML-INTO can operate in two different ways:
- Reading XML data directly into an RPG variable
- Reading XML data gradually into an array parameter that it passes to the procedure specified by %HANDLER(handlerProc).
The first operand specifies the target of the parsed data. It can contain a variable name or the %HANDLER built-in function.
The second operand must be the %XML built-in function, identifying the XML document to be parsed and the options controlling the way the parsing is done. See %XML (xmlDocument {:options}) for more information on %XML.
%XML (xmlDocument {:options})
%XML is used as the second operand of the XML-SAX and XML-INTO operation codes to specify the XML document to be parsed, and the options to control how the document is parsed. %XML does not return a value, and it cannot be specified anywhere other than for the XML-SAX and XML-INTO operation codes.
“Options” Parameter Options | ||
---|---|---|
Parameter | Options | Description |
doc | doc=string doc=file | string, the default, tells the %XML built-in function that the XMLdocument parameter contains a string or field of XML (i.e., not a file name). file tells the %XML built-in function that the XMLdocument parameter is the name of an IFS file that contains the XML. |
case | case=lower case=upper case=any | This specifies how the XML is stored. Specifying case=lower or case=upper is faster than case=any because the parser will convert the XML to all uppercase when case=any is specified. |
trim | trim=all trim=none | This controls whether spaces (tabs, linefeeds, excess blanks) should be removed before assigning to variables. It applies only to character fields. Other data types always trim extra spaces. |
allowmissing | allowmissing=no allowmissing=yes | When you copy the XML values to a data structure, this option controls whether or not a node/element for each data structure subfield must exist in the XML. You probably want to set this to “yes” in most cases. |
allowextra | allowextra=no allowextra=yes | The complement of allowmissing, this option controls whether or not to allow extra nodes/elements in the XML that do not have a corresponding subfield name in the target data structure. |
path | path=xmlnode/name | This is perhaps the most powerful feature of %XML. It allows you to directly retrieve an element in an XML document. If this option is not specified, the element retrieved is the same as the target field name (for standalone fields) and the names of the subfields (for data structures). |
Examples of the XML-INTO operation
Parsing directly into a variable from a file
D qualName DS QUALIFIED D name 10A D lib 10A D copyInfo DS QUALIFIED D from LIKEDS(qualName) D to LIKEDS(qualName) D toName S 10A VARYING // Assume file cpyA.xml contains the following lines: //// /free // Data structure "copyInfo" has two subfields, "from" // and "to". Each of these subfields has two subfields // "name" and "lib". xml-into copyInfo %XML('cpyA.xml' : 'doc=file'); // copyInfo.from .name = 'MASTFILE ' .lib = 'CUSTLIB ' // copyInfo.to .name = 'MYFILE ' .lib = '*LIBL ' // Parse the "copyinfo/to/name" information into variable // "toName". Use the "path" option to specify the location // of this information in the XML document. xml-into toName %XML('cpyA.xml' : 'doc=file path=copyinfo/to/name'; // toName = 'MYFILE'// MYFILE *LIBL //
Parsing directly into a variable from a string variable
D info DS D name 10A D val 5I 0 DIM(2) D xmlFragment S 1000A VARYING D opts S 20A INZ('doc=string') D dateVal S 10A INZ('12/25/04') D format S 4A INZ('mdy/') D mydate S D DATFMT(*ISO) /free // 1. Parsing into a data structure containing an array xmlFragment = ''; xml-into info %XML(xmlFragment); // info now has the value // name = 'Jill' // val(1) = 10 // val(2) = -5 // 2. Parsing into a date. The "fmt" XML attribute indicates the // format of the XML date. xmlFragment = ' Jill ' + '10 -5 ' + dateVal + ' '; xml-into mydate %XML(xmlFragment); // xmlFragment = '12/25/04 ' // mydate = 2004-12-25
Parsing an unknown number of XML elements using a handling procedure
// DDS for "MYFILE" // A R PARTREC // A ID 10P 0 // A QTY 10P 0 // A COST 7P 2 // XML data in "partData.xml" //// // 100 13 12.03 // ... // 9 14 3.50 // Fmyfile o e disk D options S 100A D allOk S N D partHandler PR 10I 0 D ok N D parts LIKEREC(partrec) DIM(10) CONST D numRecs 10U 0 VALUE : : /free // Initiating the parsing options = 'doc=file path=parts/part'; allOk = *ON; xml-into %HANDLER(partHandler : allOk) %XML('partData.xml' : options); // Check if the operation wrote the data // successfully if not allOk; // some output error occurred endif; /end-free : : // The procedure to receive the data from up to 10 // XML elements at a time. The first call to the // this procedure would be passed the following data // in the "parts" parameter: // parts(1) .id = 13 .qty = 100 .cost = 12.03 // parts(2) .id = 14 .qty = 9 .cost = 3.50 // ... // If there were more than 10 "part" child elements in // the XML file, this procedure would be called more // than once. P partHandler B D PI 10I 0 D ok 1N D parts LIKEREC(partrec) DIM(10) CONST D numRecs 10U 0 VALUE D i S 10I 0 * xmlRecNum is a static variable, so it will hold its * value across calls to this procedure. * Note: Another way of storing this information would be to * pass it as part of the first parameter; in that * case the first parameter would be a data structure * with two subfields: ok and xmlRecNum D xmlRecNum S 10I 0 STATIC INZ(0) /free for i = 1 to numRecs; xmlRecNum = xmlRecNum + 1; write(e) partRec parts(i); // Parameter "ok" was passed as the second parameter // for the %HANDLER built-in function for the XML-INTO // operation. The procedure doing the XML-INTO // operation can check this after the operation to // see if all the data was written successfully. if %error; // log information about the error logOutputError (xmlRecNum : parts(i)); ok = *OFF; endif; endfor; // continue parsing return 0; /end-free P E 0 254 1.98
Tools for consuming webservice
Services in IBM i:
- HTTP API
- CGI Programming
-
HTTP API:
HTTP API (Hypertext Transfer Protocol Application Programming Interface) is a tool that allows users to access and modify content in IBM i. It can be used with IBM InfoSphere Information Analyzer or with ILE RPG.
HTTP API is an IBM i library (LIBHTTP) containing a full set of API’s allowing any IBM i programmer to write IBM i programs to easily connect to remote webservices and read, write and tinker (“tinker” is a technical term) with cloud based applications.
HTTP API characteristics:
- Communication protocol: Uses HTTP for client-server communication.
- Standard HTTP methods: Employs methods like GET, POST, PUT, and DELETE for various operations.
- Lightweight: Generally, more lightweight and flexible than other API types, such SOAP API
- Lightweight: Generally, more lightweight and flexible than other API types, such SOAP API
- Data interchange formats: Commonly use formats like JSON or XML for data interchange.
- Stateless: Operates stateless, meaning each request from the client contains all the information needed to process it.
- Ease of implementation: Simpler and more straightforward to implement and use, especially for web-based services.
- Internet-based services: Ideal for internet-based applications due to their compatibility with web technologies.
- HTTP API use cases The use cases for HTTP APIs span a wide range of applications, particularly those involving web-based services, mobile apps, and the Internet of Things (IoT).
- Web services: HTTP APIs are extensively used to build web services, such as RESTful services, where they manage the interaction between a client (like a web browser) and a web server. They are ideal for retrieving web page content, submitting form data, and conducting server-side operations based on client requests.
HTTP API advantages
HTTP APIs offer several benefits that make them popular for web-based services and applications. These advantages stem from their inherent design and functionality within the HTTP framework.
Here’s a list of their key benefits:
- Efficient performance: They offer quick data transfer, enhancing performance, particularly in web and mobile applications.
- High scalability: Their stateless nature allows for efficient handling of increasing loads, making them highly scalable.
- Broad interoperability: Thanks to standard web protocols, HTTP APIs can easily integrate with many internet-based services and technologies.
- Rapid development and testing: The simplicity of their design allows for faster development, testing, and debugging, speeding up the software development lifecycle.
HTTP API disadvantages
While HTTP APIs are advantageous in many scenarios, they also have certain drawbacks to consider when choosing an API type for specific applications. These disadvantages are related to security, state management, and more.
Below are the main disadvantages:
- Security concerns: Additional security measures are often required, as HTTP APIs lack the built-in security standards found in protocols like SOAP.
- Not ideal for complex transactions: They may not be as effective in handling complex, transactional operations requiring advanced features like transaction compliance and detailed error handling.
- Exposure to web vulnerabilities: Being internet-based, HTTP APIs are susceptible to common web security threats, necessitating strong security measures.
- Network dependency: Their performance depends highly on network conditions and issues like latency and bandwidth can significantly impact their efficiency.
HTTP API components
-
Client
A client is a software component or user interface that initiates communication by sending HTTP requests to a server. Its primary function is to request specific actions or information from the server, acting as the initiator of interactions within the HTTP API. Additionally, clients are responsible for managing authentication credentials ensuring secure access to the API.
Here’s what you need to know about the client:
- Role: The client’s role is to request information or perform actions from the server. Examples include web browsers, mobile apps, or software applications.
- Actions:Clients use actions like “GET” (to fetch data), “POST” (to send data to the server), “PUT” (to update existing data), and “DELETE” (to remove data).
-
Server
The server is a software component that listens for incoming HTTP requests from clients, processes those requests, and sends back appropriate responses. It is the central hub for handling data, logic, and resources on the backend. The server is the backbone of an HTTP API and is responsible for receiving, processing, and responding to client requests while ensuring the security, performance, and reliability of the API’s services.
Here’s what you should know about servers:
- Functionality: Servers are remote computer systems responsible for handling client requests. They contain the data and logic necessary to fulfill these requests.
- Decision-making: Servers decide how to respond to each client request, whether fetching data, storing data, or sending a response back to the client.
- Authentication and authorization: Managing user access and ensuring clients have the necessary permissions to perform certain actions or access specific resources.
- Error handling: In case of errors or issues, servers communicate with clients by sending specific messages, such as “404 Not Found” or “500 Internal Server Error.”
- Security: Implementing security measures to protect against common web vulnerabilities, such as authentication mechanisms, encryption (HTTPS), and input validation.
-
HTTP methods
HTTP methods, also known as HTTP verbs, are standard actions that clients can use to interact with a server when making HTTP requests. These methods define the type of operation the client wants to perform on a specific resource hosted by the server. These commands help maintain clarity and consistency in web communications.
- GET – an HTTP method used to retrieve data from the server. It’s like requesting information without changing the server’s data. Typically includes a URL specifying the resource to retrieve.
- POST – an HTTP method used to send data to the server for processing or storage. It’s like submitting new information or making a request that might lead to changes on the server. It often includes a request body containing data to be processed.
- PUT – an HTTP method used to update existing data or resources on the server. It’s like editing an item or resource that already exists. Typically provides the complete updated data for the resource.
- DELETE – an HTTP method used to request the removal or deletion of a resource on the server. It’s like asking to remove something from the server’s records. Typically includes a URL specifying the resource to be deleted.
-
Data format
In the context of HTTP APIs, data format refers to the specific structure and encoding used to represent information exchanged between clients and servers. It defines how data is organized, formatted, and transmitted in a way that both the client and server can understand. Data Format is a standardized language or template that clients and servers agree upon to package and understand the information they exchange.
Here’s what you need to know:
- JSON – It’s like speaking in a simple, universal language. JSON is easy to learn and use, making it a popular choice for data exchange.
- XML – Think of XML as using a more structured and detailed language suitable for complex data. It’s like having a formal conversation.
-
Stateless
Statelessness, in the context of an HTTP API, refers to the design principle where each client request to the server is treated as an independent and self-contained interaction. The server does not retain any information or context about previous requests from the same client. Statelessness is like having a conversation where each sentence you speak is self-contained, and you don’t rely on what was said before.
System Requirements:
- IBM i (OS/400) version 6.1 or later.
- Your TCP/IP must be installed and working.
- You need an ILE RPG compiler.
Instructions:
- Download the .ZIP file to your PC by right-clicking this link HTTP API distribution and choosing “Save Target As.”
- Extract the data from the .ZIP file into a temporary location on your hard drive.
- Open an MS-DOS prompt.
- Switch to the directory where you unzipped HTTPAPI.ZIP
- C:\ > cd \httpapi
- Run the batch file. It will FTP to your iSeries, create the LIBHTTP library, create the appropriate source files, and upload all the source members. You must pass parameters to tell where your iSeries is, as well as your user id and password:
- C:\HTTPAPI > upload ibmi.example.com bob my password
- Skip ahead to the section entitled “Building the Source”
Manual Upload to iSeries:
Create the necessary objects on IBM i:
- CRTLIB LIB(LIBHTTP)
- CRTSRCPF FILE(LIBHTTP/QCLSRC) RCDLEN(92)
- CRTSRCPF FILE(LIBHTTP/QDDSSRC) RCDLEN(92)
- CRTSRCPF FILE(LIBHTTP/QCMDSRC) RCDLEN(92)
- CRTSRCPF FILE(LIBHTTP/QRPGLESRC) RCDLEN(112)
- CRTSRCPF FILE(LIBHTTP/QSH) RCDLEN(124)
- CRTSRCPF FILE(LIBHTTP/QSRVSRC) RCDLEN(92)
- CRTSRCPF FILE(LIBHTTP/QXMLGENS) RCDLEN(112)
- CRTSRCPF FILE(LIBHTTP/EXPAT) RCDLEN(112)
On IBM i, type:
- CHGCURLIB CURLIB(LIBHTTP)
- CRTCLPGM INSTALL SRCFILE(LIBHTTP/QCLSRC)
- CALL INSTALL
- The HTTPAPI installer will guide you through the rest of the process.
-
CGI Programming
IBM includes a set of APIs that provide CGI capability to RPG IV and other ILE-targeted languages. ILE C/400 has CGI capability built into the language, and there also several add-on libraries that provide clean and direct CGI support from within C. Therefore, the CGI APIs are not required if you use C or C++.
IBM includes seven APIs for CGI programming. They are summarized in the table below.
APIs for CGI Programming API Name Description QtmhGetEnv Gets a value from the CGI environment QtmhPutEnv Changes a value in the CGI environment QtmhRdStin Reads a string from the standard input device (i.e., read data sent to a CGI program from an HTML form) QtmhWrStout Writes a string to the standard output device (i.e., write to the Web browser) QtmhCvtDB Converts URL-encoded string to an externally described data structure QzhbCgiParse Parses the data from an HTML form QzhbCgiUtils “Utilities” to create a full HTTP response Read the Environment variable, REQUEST_METHOD
Get environment via API :
CALLB APIGetEnvparm EnvRec parm EnvRecLen parm EnvLen parm EnvName parm EnvNameLen parm QUSEC
The following is a list of cgiGetVar() sub procedure variations:
cgiGetVar() Subprocedure Variations API Name Description cgiGetVar() Retrieves a value from an HTML form cgiGetVarCnt() Retrieves the number of occurrences of an individual HTML form field cgiGetVarU() Retrieves a value from an HTML form field and converts it to uppercase cgiGetVarL() Retrieves a value from an HTML form field and converts it to lowercase cgiGetVarDec() Retrieves a value from an HTML form as a decimal value cgiGetVarInt() Retrieves a value from an HTML form as an integer CGI programming setup:
- Download the following files:
- samplerpg.txt (TXT,17KB) – contains the RPG source code.
- samplerpg.zip (ZIP,1.1KB) – contains the html code that requests the CGI.
- Use the following CL commands to create a directory structure:
- mkdir dir(‘/qsys.lib/rpgdemo.lib’)
- mkdir dir(‘/qsys.lib/rpgdemo.lib/qcsrc.file’)
- mkdir dir(‘/rpgdemo’)
- mkdir dir(‘/rpgdemo/html’)
- Use FTP to connect to your server.
- Use the following FTP commands to copy the files to your server:
- put samplerpg.html /rpgdemo/html/samplerpg.html
- put samplerpg.txt
/qsys.lib/rpgdemo.lib/qcsrc.file/samplerpg.mbr
- Use the following CL commands to create the program (PGM) object called SAMPLERPG:
- CRTRPGMOD MODULE(rpgdemo/samplerpg) SRCFILE(rpgdemo/qcsrc) SRCMBR(samplerpg) OUTPUT(*print)
- CRTPGM PGM(rpgdemo/samplerpg) MODULE(rpgdemo/samplerpg) BNDSRVPGM(qhttpsvr/qzhbcgi)
Be aware the mkdir command will use hierarchical file authorities, unless you specify otherwise, for the *PUBLIC users. You may want to specifically add read and execute authorities for server user profiles QTMHHTTP and QTMHHTP1 to these new directories.
- Download the following files: