Web Service Utilities running on IBM i for providing superfast Web Services and running lightning speed Web Applications powered by IBM i based on AJAX-Requests
The Library WEBSRVUTL with the Service Program WERSRVUTL gives RPG-Programmers a fast and easy way to provide Web Services powered by IBM i.
Web Services are the cutting edge Technology of the Internet. Millions of Websites based on Web Services like Google, Facebook, Amazon and so on.
Rainer Ross is the developer of the hotel search engine www.myhofi.com - this application is powered by IBM i, built with HTML5, CSS3, JavaScript, Db/2 inMemory, Symmetric Multiprocessing, Watson Content Analytics and runs on the server side with pure free RPG Web Services. myhofi.com was awarded with the IBM Innovation Award.
The IBM i has all the Technologies for building high speed Web Services and superfast Web Applications out-of-the-box and is the best choice for all your Internet Applications.
Why RPG-Programs runs faster than programs that are written in interpreted languages such as the Net.Data® and PHP scripting languages
A major concern with CGI performance on other platforms is the fact that a CGI program is started on each Web client request. This includes additional disk and operating system activity to create the new process (job). Quite often, CGI program initialization, such as connecting to a database management system, also takes some time that adds to the response time users experience with such applications.
The IBM HTTP Server for i takes a different approach. The HTTP Server keeps a pool of HTTP server child processes that is used to run CGI programs. The child processes are not ended after a CGI program is run within the process. In addition, child processes are associated with a user profile and only requests for CGI programs that run under the same user profile associated with an existing child process will be run in the process.
CGI programs that are created by compiling source code typically run faster than programs that are written in interpreted languages such as the Net.Data® and PHP scripting languages. However, programs that are written in scripting languages tend to be easier to write, maintain, and debug. Read more
Hello World www.myhofi.com/myapp/helloworld.pgm Link to Sourcecode
Providing JSON www.myhofi.com/myapp/websrv11.pgm?id=1 Link to Sourcecode
{
"success": true,
"errormsg": "",
"errorid": 0,
"items": [
{
"id": 1,
"name": "MINERALÖL-TANKSTELLE",
"country": "DE",
"zip": "12559",
"city": "BERLIN",
"street": "GOETHESTR. 8",
"sales": 535647.59,
"credit": 5000.00,
"balance": 1650.00,
"date": "2015-02-06"
}
]
}
Providing XML www.myhofi.com/myapp/websrv02.pgm?id=1 Link to Sourcecode
<data>
<customer>
<id>1</id>
<name>MINERALÖL-TANKSTELLE</name>
<country>DE</country>
<zip>12559</zip>
<city>BERLIN</city>
<street>GOETHESTR. 8</street>
<sales>535647.59</sales>
<credit>5000.00</credit>
<balance>1650.00</balance>
<date>2015-02-06</date>
</customer>
</data>
Web Application with AJAX-Request to the JSON-Webservice www.myhofi.com/devhtm/websrv04.html
- The AJAX-Request is powered by the JavaScript UI-Library www.webix.com
webix.ajax().post("/myapp/websrv01.pgm", {id:0},
function(text, data) {
}
);
More Web Applications built with Web Services and www.webix.com
- Data Management with Menu, Google Maps, Gantt, Gages, Charts and Scheduler http://www.myhofi.com/tms/HTML/Myapp.html
- Read the HTTP Environment Variables
getenv()
- Get Input from HTTP-Server
getInput()
- Get KeyValue from Input-Data
getKeyValue()
- Create HTTP-Header
getHeader()
- Read Data from the HTTP-Server
readStdin()
- Write Data to the HTTP-Server
wrtStdout()
- Write Data to the HTTP-Server and generate HTTP-Header
writeStdout()
How to use it in your RPG-Program with Scott Klements YAJL - Sourcecode
Example GET-Request from a business partner to your IBM i http://www.mycompany.com/myapp/request.pgm?id=5&name=Ross
//------------------------------------------------------------------//
// Main //
//------------------------------------------------------------------//
dcl-proc main;
dcl-s LocErrmsg varchar(500);
dcl-s LocId like(Id); // Id
dcl-s LocName like(Name); // Name
getInput(); // Get Input
monitor;
LocId = %dec(getKeyValue('Id'):10:0); // Get Id
on-error;
endmon;
LocName = getKeyValue('name'); // Get Name
yajl_genopen(*on);
crtjson(LocId);
yajl_writeStdout(200:GblErrMsg);
yajl_genclose();
end-proc;
//------------------------------------------------------------------//
How to use it in your RPG-Program with SQL to generate JSON-Data - Sourcecode
Example GET-Request from a business partner to your IBM i http://www.mycompany.com/myapp/request.pgm?id=5
//------------------------------------------------------------------//
// Variables //
//------------------------------------------------------------------//
dcl-s GblJson SQLType(CLOB:16000000) ccsid(*utf8); // 16 MB
//------------------------------------------------------------------//
// Main //
//------------------------------------------------------------------//
dcl-proc main;
clear GblJson; // JSON-Data
clear DsData; // Input-Data
getInput(); // Get Input
monitor;
DsData.Id = %dec(getKeyValue('Id'):9:0); // Customer-Id
on-error;
endmon;
crtJson(DsData); // Create JSON-Data
writeStdout(%addr(GblJson_Data):GblJson_Len);
end-proc;
//------------------------------------------------------------------//
// Create JSON-Data //
//------------------------------------------------------------------//
dcl-proc crtJson;
dcl-pi *n;
PiData likeds(DsData) const;
end-pi;
exec sql
select JSON_OBJECT(
'items' value
JSON_ARRAYAGG(
JSON_OBJECT(
'id' value id,
'country' value trim(country),
'name' value trim(name),
'zip' value trim(zip),
'city' value trim(city),
'street' value trim(street),
'sales' value sales,
'credit' value credit,
'balance' value balance,
'date' value date
)
)
)
into :GblJson
from customer
where Id = Case
When :PiData.Id > 0 Then :PiData.Id
Else Id
End;
end-proc;
//------------------------------------------------------------------//
Procedure getenv()
read the HTTP Environment Variables - Useful Link
LocMethod = %str(getenv('REQUEST_METHOD')); // Result GET or POST
When the Environment Variable is not delivered then put the command in a Monitor Statement like this
Monitor;
LocAuth = %str(getenv('AUTH_TYPE')); // Authentification Type
on-error;
End-Mon;
Procedure getInput()
reads the Input Data from GET and POST Requests and parse the Input Data in Keys and Values
- The maxlength of a key is 128 bytes. The key can be upper case, lower case and mixed case
- The maxlength of a value is 1,000,000 bytes
- The maximal number of variables is 1000, when you need more variables then change https://github.com/RainerRoss/WEBSRVUTL/blob/master/QCPYSRC/WEBSRVUTL.RPGLE in line 59 to your own number of needed variables and create the Binding Directory and the Service Program
CALL PGM(WEBSRVUTL/WEBSRVUTLC)
dcl-ds DsKeyVal qualified dim(1000) inz;
Example GET-Request http://www.mycompany.com/myapp/request.pgm?id=5&name=Ross&city=Munich
?
-> Starts the Query_String -> the Input Parameters&
-> Separator Key=Value&Key=Value
Key Value
--------------
id 5
name Ross
city Munich
In your RPG-Program
Dcl-S Id int(10);
Dcl-S Name varchar(30);
Dcl-S City varchar(30);
Monitor;
Id = %dec(getKeyValue('id'):10:0);
on-error;
End-Mon;
Name = getKeyValue('name');
City = getKeyValue('city');
- Generates a Text HTTP Header
Header = getHeader(TEXT)
- Generates a JSON HTTP Header
Header = getHeader()
orHeader = getHeader(JSON)
- Generates a XML HTTP Header
Header = getHeader(XML)
* Data Pointer
* Data-Length int(10)
* Error Array
Dcl-S MyData char(256) ccsid(*UTF8);
MyData = 'HelloWorld';
wrtStdout(%addr(MyData):%len(%trimr(MyData)):DsApierr);
Dcl-S MyData varchar(256) ccsid(*UTF8);
MyData = 'HelloWorld';
wrtStdout(%addr(MyData:*data):%len(MyData):DsApierr);
* Data Pointer
* Data-Length int(10)
* Type uns(03) options(*nopass) JSON, XML, TEXT default is JSON
Dcl-S MyData char(256) ccsid(*UTF8);
MyData = 'HelloWorld';
writeStdout(%addr(MyData):%len(%trimr(MyData)):TEXT);
Dcl-S MyData varchar(256) ccsid(*UTF8);
MyData = 'HelloWorld';
wrtStdout(%addr(MyData:*data):%len(MyData):TEXT);
- QtmhRdStin more Information
- QtmhWrStout more Information
- getenv more Information
License Programs
- 5770SS1 Option 3 – Extended Base Directory Support
- 5770SS1 Option 12 – Host Servers
- 5770SS1 Option 30 – Qshell
- 5770SS1 Option 33 – PASE
- 5770SS1 Option 34 – Digital Certificate Manager
- 5770SS1 Option 39 – Components for Unicode
- 5770TC1 - TCP/IP
- 5770JV1 - Java
- 5770DG1 – HTTP-Server: Apache 2.4.20
Non-License Software (open source)
- YAJL from Scott Klement (create and parse JSON) - Download here
- Create a library
CRTLIB LIB(WEBSRVUTL) TEXT('Webservice Utilities')
- Create a source physical file
CRTSRCPF FILE(WEBSRVUTL/QCLPSRC)
- Create a source physical file
CRTSRCPF FILE(WEBSRVUTL/QSRVSRC)
- Create a source physical file
CRTSRCPF FILE(WEBSRVUTL/QCPYSRC)
- Create a source physical file
CRTSRCPF FILE(WEBSRVUTL/QMODSRC)
- Copy the files from
QCLPSRC, QCPYSRC, QMODSRC
to your SRCPF's - Compile the CL-Program
CRTBNDCL PGM(WEBSRVUTL/WEBSRVUTLC) SRCFILE(WEBSRVUTL/QCLPSRC)
- Create the Binding Directory and the Service Program
CALL PGM(WEBSRVUTL/WEBSRVUTLC)
- Start HTTP-Admin
STRTCPSVR SERVER(*HTTP) HTTPSVR(*ADMIN)
- Stop HTTP-Admin
ENDTCPSVR SERVER(*HTTP) HTTPSVR(*ADMIN)
- Open your browser and start the IBM i HTTP-Admin: http://yourIP:2001/HTTPAdmin
- Create the new HTTP-Server Instance
Server name: MYSERVER
Server description: My new Webserver
Server root: /www/myserver
Document root: /www/myserver/htdocs
IP address: All IP addresses
Port: 8010
Log directory: /www/myserver/logs
Access log file: access_log
Error log file: error_log
Log maintenance 7 days
-
Start HTTP-Server Instance MYSERVER
STRTCPSVR SERVER(*HTTP) HTTPSVR(MYSERVER)
-
Call the example Webpage from your browser
http://yourIP:8010/index.html
- Open your favorite editor create a new file named
MyFirstWebsite.html
in the/www/myserver/htdocs
folder and copy https://github.com/RainerRoss/WEBSRVUTL/blob/master/HTML/MyFirstWebsite.html into theMyFirstWebsite.html
file
- Show the files in the folder htdocs
wrklnk '/www/myserver/htdocs/*'
- Select 8 on
MyFirstWebsite.html
and check the CCSID - Change the CCSID
CHGATR OBJ('/www/myserver/htdocs/MyFirstWebsite.html') ATR(*CCSID) VALUE(1208)
- Call
MyFirstWebsite.html
from your browserhttp://yourIP:8010/MyFirstWebsite.html
- Open your favorite editor create a new file named
MyFirstApp.html
in the/www/myserver/htdocs
folder and copy https://github.com/RainerRoss/WEBSRVUTL/blob/master/HTML/MyFirstApp.html into theMyFirstMyFirstApp.html
file
- Show the files in the folder htdocs
wrklnk '/www/myserver/htdocs/*'
- Select 8 on
MyFirstApp.html
and check the CCSID - Change the CCSID
CHGATR OBJ('/www/myserver/htdocs/MyFirstApp.html') ATR(*CCSID) VALUE(1208)
- Call
MyFirstApp.html
from your browserhttp://yourIP:8010/MyFirstApp.html
- Create a library
CRTLIB LIB(MYAPP) TEXT('My Web Applications')
- Create a source physical file
CRTSRCPF FILE(MYAPP/QRPGSRC)
- Create a source physical file
CRTSRCPF FILE(MYAPP/QSQLSRC)
- Copy the file https://github.com/RainerRoss/WEBSRVUTL/blob/master/Examples/HelloWorld.RPGLE to your SRCPF
- Add MYAPP and WEBSRVUTL to your Library List
ADDLIBLE LIB(MYAPP) POSITION(*LAST)
ADDLIBLE LIB(WEBSRVUTL) POSITION(*LAST)
- Compile the program
CRTBNDRPG PGM(MYAPP/HELLOWORLD) SRCFILE(MYAPP/QRPGSRC)
- Open HTTP-Admin from your Browser
http://yourIP:2001/HTTPAdmin -> all Servers -> MYSERVER -> Tools -> Edit configuration
- Insert
DefaultNetCCSID 1208
- Check your IBM i CCSID
DSPSYSVAL QCCSID
when the CCSID is 65535 then insert the following line depending on your CCSID e.g. US = 37, DE = 1141
DefaultFsCCSID 37
- Insert these lines for the ability to run Web Services from Library
MYAPP
ScriptAliasMatch /myapp/(.*) /qsys.lib/myapp.lib/$1
<Directory /qsys.lib/myapp.lib>
SetEnv QIBM_CGI_LIBRARY_LIST "MYAPP;WEBSRVUTL;YAJL"
Require all granted
</Directory>
- Insert these lines for the ability to run Web Services from Library
MYAPP
and Basic Authentication against the IBM i User Profiles
<Directory /qsys.lib/myapp.lib>
SetEnv QIBM_CGI_LIBRARY_LIST "MYAPP;WEBSRVUTL;YAJL"
AuthType Basic
AuthName "My Applications"
PasswdFile %%SYSTEM%%
UserID %%CLIENT%%
Require valid-user
</Directory>
- When you want GZIP the data from server to browser then insert the following lines
#=========================================================================
# GZIP Options
#=========================================================================
# Deflate Module
LoadModule deflate_module /QSYS.LIB/QHTTPSVR.LIB/QZSRCORE.SRVPGM
# Insert Filter for Content Types except Images
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json application/xml
#
SetEnvIf User-Agent ^Mozilla/4 gzip-only-text/html
SetEnvIf User-Agent ^Mozilla/4\.0[678] no-gzip
SetEnvIf User-Agent \bMSIE !no-gzip
SetEnvIf User-Agent \bMSIE !gzip-only-text/html
SetEnvIf User-Agent \bMSI[E] !no-gzip
SetEnvIf User-Agent \bMSI[E] !gzip-only-text/html
#
# Compression Level Highest 9 - Lowest 1
DeflateCompressionLevel 3
#
#=========================================================================
# E-Tags
#=========================================================================
Header unset ETag
FileETag None
#=========================================================================
- Stop HTTP-Server Instance MYSERVER
ENDTCPSVR SERVER(*HTTP) HTTPSVR(MYSERVER)
- Start HTTP-Server Instance MYSERVER
STRTCPSVR SERVER(*HTTP) HTTPSVR(MYSERVER)
- Call
HelloWorld
from your browserhttp://yourIP:8010/myapp/HelloWorld.pgm
- Copy the file https://github.com/RainerRoss/WEBSRVUTL/blob/master/Examples/Customer.sql to your SRCPF in
MYAPP/QSQLSRC
- Create the Physical File Customer
RUNSQLSTM SRCFILE(MYAPP/QSQLSRC) SRCMBR(CUSTOMER)
and fill this File with data or copy your own Customer Physical File to the LibraryMYAPP
- Add MYAPP, WEBSRVUTL and YAJL to your Library List
ADDLIBLE LIB(MYAPP) POSITION(*LAST)
ADDLIBLE LIB(WEBSRVUTL) POSITION(*LAST)
ADDLIBLE LIB(YAJL) POSITION(*LAST)
- Copy the file https://github.com/RainerRoss/WEBSRVUTL/blob/master/Examples/WEBSRV01.RPGLE to your SRCPF in
MYAPP/QRPGSRC
- Compile the program
CRTBNDRPG PGM(MYAPP/WEBSRV01) SRCFILE(WEBSRV01/QRPGSRC)
- Call
WEBSRV01
from your browserhttp://yourIP:8010/myapp/Websrv01.pgm?id=1
- Copy the file https://github.com/RainerRoss/WEBSRVUTL/blob/master/Examples/Customer.sql to your SRCPF in
MYAPP/QSQLSRC
- Create the Physical File Customer
RUNSQLSTM SRCFILE(MYAPP/QSQLSRC) SRCMBR(CUSTOMER)
and fill this File with data or copy your own Customer Physical File to the LibraryMYAPP
- Add MYAPP and WEBSRVUTL to your Library List
ADDLIBLE LIB(MYAPP) POSITION(*LAST)
ADDLIBLE LIB(WEBSRVUTL) POSITION(*LAST)
- Copy the file https://github.com/RainerRoss/WEBSRVUTL/blob/master/Examples/WEBSRV02.SQLRPGLE to your SRCPF in
MYAPP/QRPGSRC
- Compile the program
CRTSQLRPGI PGM(MYAPP/WEBSRV02) SRCFILE(WEBSRV02/QRPGSRC)
- Call
WEBSRV02
from your browserhttp://yourIP:8010/myapp/Websrv02.pgm?id=1