TWEAKING YAJL - Configure the IBM i HTTP Server for YAJL (JSON)

Step 1 - Create your IBM i HTTP SERVER 

Since this was the previous lesson, we can assume that is complete and you now have an HTTP Server - which I will refer to as <NEWSERVER>

Step 2 - Create a dedicated User Profile for your webservice to use <WEBUSER

Why is it a good idea to create a dedicated user profile for ibm i webservices ?

Creating a dedicated user profile for IBM i web services is a good idea for several reasons:

  • Security: By having a dedicated user profile, you can limit the permissions and access rights specifically to what is needed for the web services. This minimizes the risk of unauthorized access or accidental changes to other parts of the system
  • Customization: A dedicated profile allows you to tailor the environment specifically for web services, including setting up customized sessions, message queues, and output queues
  • Isolation: It helps in isolating web services from other system activities. This isolation can prevent potential conflicts and makes it easier to manage and troubleshoot issues related to web services
  • Audit and Monitoring: With a dedicated profile, it becomes easier to track and audit activities related to web services. This can be crucial for compliance and security monitoring
  • Resource Management: You can allocate specific system resources to the dedicated profile, ensuring that web services have the necessary resources without impacting other users or applications
CRTUSRPRF USRPRF(WEBUSER)
PASSWORD(*NONE)
CURLIB(WEBSERVICE)
INLMNU(*SIGNOFF)
LMTCPB(*YES)
TEXT('User Profile Used by YAJL Webservices')

CRTLIB LIB(WEBSERVICE)
TYPE(*TEST)
TEXT('Webserver library used for REST YAJL Services')

CRTAUTL AUTL(WEBSERVICE)
TEXT('Webservice Authorization List')

GRTOBJAUT OBJ(WEBSERVICE/*ALL)
OBJTYPE(*ALL)
AUTL(WEBSERVICE)

Now you can easily control access to your system for all webservices coming into your new HTTP Server:

edtautl

Step 3 - Modify HTTP SERVER <NEWSERVER> to call your webservice

The HTTP Server will be updated so that it recognizes any incoming webservice requests and acts on them. The HTTP Server is providing an active internet connection and waiting to consume incoming webservice calls.

We need to tell <NEWSERVER> what to look for and how to act when it sees it!

Edit the HTTP Server config file you just created at '/www/<NEWSERVER>/conf/httpd.conf' and add a section of code to do essentially do three things:

  • Tell the HTTP Server which USRPRF to run with
  • Tell the HTTP SERVER to watch for a certain to pattern in the incoming connections URI
  • Tell the HTTP Server which program in the webservice library it should call

What is a URI?

A URI (Uniform Resource Identifier) is a string of characters that unambiguously identifies a particular resource on the internet. A URL (Uniform Resource Locator) is a type of URI that not only identifies a resource, but also provides the location or address of the resource, so that it can be accessed or retrieved. In other words, all URLs are URIs, but not all URIs are URLs.

For example, the following are both URIs:

  • mailto:user@example.com (identifies an email address)
  • https://www.example.com/index.html (identifies and locates a web page)

The first example is not a URL, because it does not provide a location or address for the resource. The second example is a URL, because it identifies and locates a web page.

In summary, URIs are used to identify resources, while URLs are used to locate and access resources.

For example, here I am looking for a URI something like: https://myibmisystem:8080/webservice/web2ifsyjl

testing a webservice

What code do we need to add to make this happen?

Add the User Profile that the incoming webservices will run under. 

We are going to create a User Profile called 'WEBUSER' and add this line to the httpd.conf file:

ServerUserID WEBUSER

The directory /www/WEBSERVICE/htdocs is typically used in web server environments to store documentation that might be served to users. Our webservice setup will not use this so we can delete these lines of code:

# DELETE THIS!!!!
<Directory /www/apachedft/htdocs>
 Require all granted
</Directory>

The 'ScriptAliasMatch' directive is for mapping a URL to a program call.

This literally says:

  • Always use a USRPRF(WEBUSER) for these requests
  • If you see a request coming with /webservice/ in the url
  • Then extract the name from the next part of the URI - ([a-z0-0]+)/.* 
  • Call the program in a library called LIB(WEBSERVICE) using a replacement value $1 (that will contain the extracted value from ([a-z0-0]+)/.* 
  • Set the Environment so that the *LIBL contains two libraries : YAJL and WEBSERVICE
  • Grant access to this request
# Define incoming URI=/webservice/ to call the program (defined in the next part of the URI) in LIB(WEBSERVICE)

ScriptAliasMatch ^/webservice/(.*) /qsys.lib/webservice.lib/$1.pgm
<Directory /qsys.lib/webservice.lib>
  SetEnv QIBM_CGI_LIBRARY_LIST "YAJL;WEBSERVICE"
  Require all granted
</Directory>

What code do we need to add to make this happen?

You can do this many ways, but let's look at my favorite three techniques:

  • using the browser based IBM WEB ADMINISTRATION FOR i, or
  • from the command line with native IBM i commands or
  • using Visual Studio Code

Let's look at these three different ways of doing exactly the same thing:

1

Technique 1 -- Edit using IBM WEB ADMINISTRATION FOR i

SPOILER ALERT - This is the recommended technique.

To activate your REST YUAJL web services, you can add the configuration directives to the configuration file easily from within the IBM Web Administration for i screen:

From your browser -- http://yourIBMiSystemName:2001/HTTPAdmin

Login and you will see a lovely UI where you can explore your new HTTP Server configuration:

Managing Apache Server

And click Edit Configuration File to make your changes:

Managing Apache Server - edit config

And you are going to add the serveruser (in my case WEBUSER), remove the htdocs and add the scriptalias for the webservice library:

Managing Apache Server - edit config with tweaks

Add the code in here - and remember to STOP and RESTART the HTTP SERVER for that code take effect. If the HTTP Server fails to start then check the errors logs in '/www/<NEWSERVER>/logs'

or if you like getting your hands dirty from the command line:

2

Technique 2 -- Edit using IBM i Command Line

You can edit this from the command line with WRKLNK

wrklnk '/www/NEWSERVER/conf'

and then edit with a 2:

wrklnk newserver and edit with 2
wrklnk newserver and edit with 2 in progress

Add the code in here - and remember to STOP and RESTART the HTTP SERVER for that code take effect. If the HTTP Server fails to start then check the errors logs in '/www/<NEWSERVER>/logs'

or if you like using the Bells and Whistles from VS Code:

3

Technique 3 -- Edit using Visual Studio Code

Connect to your IBM i System and goto the IFS Explorer.

Now add a filter looking at the IFS location '/www'

You will see a folder for all your WEBSERVERS and drill down into the '/www/<NEWSERVER>' folder. You will find the HTTPD.CONF file in the conf folder. You can edit and save here.

edit httpd.conf using VSCODE

Add the code in here - and remember to STOP and RESTART the HTTP SERVER for that code take effect. If the HTTP Server fails to start then check the errors logs in '/www/<NEWSERVER>/logs'

Finally, restart the <NEWSERVER> web server and now it's time to put your webservice code together (if you haven't already)

Follow my example of an RPG Program that will receive this incoming webservice call and handle the various methods.

Good Luck!

Want to see my entire HTTPD.CONF

Here is a copy of my complete HTTPSERVER Configuration File:

# Configuration originally created by Create HTTP Server wizard on Fri Sep 27 21:24:02 UTC 2024
LoadModule ibm_ssl_module /QSYS.LIB/QHTTPSVR.LIB/QZSRVSSL.SRVPGM
Listen *:8080
Listen *:443
DocumentRoot /www/yajl/htdocs
TraceEnable Off
Options -FollowSymLinks
LogFormat "%h %T %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%{Cookie}n \"%r\" %t" cookie
LogFormat "%{User-agent}i" agent
LogFormat "%{Referer}i -> %U" referer
LogFormat "%h %l %u %t \"%r\" %>s %b" common
CustomLog logs/access_log combined
LogMaint logs/access_log 7 0
LogMaint logs/error_log 7 0
SetEnvIf "User-Agent" "Mozilla/2" nokeepalive
SetEnvIf "User-Agent" "JDK/1\.0" force-response-1.0
SetEnvIf "User-Agent" "Java/1\.0" force-response-1.0
SetEnvIf "User-Agent" "RealPlayer 4\.0" force-response-1.0
SetEnvIf "User-Agent" "MSIE 4\.0b2;" nokeepalive
SetEnvIf "User-Agent" "MSIE 4\.0b2;" force-response-1.0
AlwaysDirectoryIndex Off
ServerUserID WEBUSER
SSLProxyProtocolDisable SSLv3 TLSv1 TLSv1.1

# NJL: deny root access
SetEnv HTTPS_PORT 443
<Directory />
  Require all denied
</Directory>

# Define incoming URI=/webservice/ to call the program (defined in the next part of the URI) in LIB(WEBSERVICE)

ScriptAliasMatch ^/webservice/(.*) /qsys.lib/webservice.lib/$1.pgm
<Directory /qsys.lib/webservice.lib>
  SetEnv QIBM_CGI_LIBRARY_LIST "YAJL;WEBSERVICE"
  Require all granted
</Directory>

<VirtualHost *:443>
SSLEngine On
SSLAppName QIBM_HTTP_SERVER_YAJL1
SSLProtocolDisable SSLv3 TLSv1 TLSv1.1
</VirtualHost>

HTTPSubsystemDesc QHTTPSVR/QHTTPSVR
HTTPStartJobDesc QHTTPSVR/QZHBHTTP
HTTPStartJobQueue *JOBD
HTTPRoutingData *JOBD
LogLevel Debug
{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}
>