Skip to content

REST API - Provider

The common used term for a REST API is a Provider. A REST Client is referred to as a Consumer.

Runtime Architecture

MDRest4i MDRFRAME API Runtime

The runtime architecture a REST API/Provider is self contained on the IBM i using native components.

An HTTP server is created using the MDRST/MDRHTTPAPI command. This server instance is configured to receive requests from a REST client and call the MDRAPI controller program.

The Provider program is the program generated by the SDK and is called by MDRAPI.

MDRAPI

MDRAPI is an ILE program. It is the only program called as a CGi program by the HTTP server. Its roll is to control the flow of data between the HTTP server and the REST API program.

MDRAPI allocates a unique "handle", gathers all the inbound message data from a request, and sets this up in memory using pointers keyed by the "handle" for each request.

It then calls the REST API program(written by the developer), passing some of the inbound data(handle, method, body) in the initial call. The REST API program, then manipulates the data in memory using calls to the MDRFRAME service program procedures, passing the "handle" passed in by MDRAPI each time.

The REST API program then passes control back to MDRAPI, and MDRAPI returns the response to the REST Client request, via the HTTP server, releasing any CGi JOB resource allocation created with the initial "handle".

ScriptAliasMatch Directive

Because MDRAPI must always be called as a CGi script from the HTTP server instance, the minimum directive required in the httpd.conf is:

ScriptAliasMatch mdrapi /QSYS.LIB/MDRSTT14.LIB/MDRAPI.PGM

Using the above ScriptAliasMatch , these two different URIs would call the MDRSTAPI/MDRAPI CGi program: http://yourapiserver.com/mdrapi/callme or http://yourapiserver.com/mdrapi/group/callmetoo

The command MDRHTTPAPI automatically adds this directive when creating an API HTTP instance.

Custom ScriptAliasMatch

It is important therefore to either explicitly specify "mdrapi" in the uri to invoke a REST API in V14, or use your own ScriptAliasMatch directive in the httpd.conf file if a different value is preferred. In both cases an httpd.conf server directive must be set to ensure MDRAPI is called. Here are some custom examples:

HTTPD.conf Directive Request URI
ScriptAliasMatch v1 /QSYS.LIB/MDRSTV14T.LIB/MDRAPI.PGM http://yourapiserver.com/v1/group/callmetoo
ScriptAliasMatch ^/MDCMST86/AZURE/RELEASE/CALLBACK /QSYS.LIB/MDCMST86.LIB/MDRAPI.PGM http://yourapiserver.com//MDCMST86/AZURE/RELEASE/CALLBACK

URI to API/Provider Program Mapping

MDRAPI determines which API program to call by comparing the path from the URI request, and MDRDCFG.MDRRSC file.value.

Table MDRDCFG is located in the library list of the CGi job for the HTTP server. It maps the request URI and method to the MDRDCFG two primary keys.

MDRAPI first checks for the specific path and method provided in the request, and then if it doesn't find it, it looks for a the path and a blank method.

The path value it uses from the request is either a single element from the path, or a composite value. The control of hwo it matches these two is determined using the environment variables described below in section Provider-API URI Mapping Environment Variables.

MDRDCFG Table

Column Description
Root Resource
MDRRSC
This is user friendly resource name used to invoke the API. MDRAPI will resolve this and call the Program below
Method
METHOD
The HTTP request METHOD
Program Name of the API program called by MDRAPI
Library Library name used in the call. No value will cause MDRAPI to use *LIBL to make the call

Maintaining MDRDCFG Records

The command MDRST/MDRSTCFG is used to maintain records in the MDRST/MDRDCFG table.

The MDRest4i SDK Provider generator, creates the MDRDCFG records when it generates the Provider source.

Provider-API URI Mapping Environment Variables

URL/URI and Path

The word "path" used in multiple places in the document, refers to the orange Path to the file section in the URL example below.

URL Breakdown

Ref: https://developer.mozilla.org/en-US/docs/Learn_web_development/Howto/Web_mechanics/What_is_a_URL

Example URL `http://myserver.com:2598/mdrapi/two/three/four/five?qryParm1=parmvalue1

MDRAPI uses four IBM i environment variables to establish what pattern to use when reading the MDRDCFG file with SQL. They can be set globally for the system, or in the httpd.conf for the HTTP instance used to handle the providers/apis.

There are essentially two patterns used to determine a match between the URI path and the value in MDRDCFG.MDRRSC.

  • Individual Path Value - uses MDREST4I_RESOURCE_COMPONENT to extract a specific value in the path.
  • Composite Path Values - uses MDREST4I_RESOURCE_MATCH to extract all of part of the URL path.

Here are the descriptions of each of these and their related Environment Variables:

ENVVAR Description
MDREST4I_RESOURCE_COMPONENT This variable tells MDRAPI which part of the URI PATH (the part after the host and port number), contains the key to use when reading the MDRDCFG file to determine which program to call.
If no value is set for MDREST4I_RESOURCE_COMPONENT, MDRAPI just uses the value of 2.
MDREST4I_RESOURCE_MATCH This variable forces MDRAPI to trigger a reverse, cascading search pattern when trying to find a record in MDRDCFG.
The number provided in the MDREST4I_RESOURCE_MATCH value, specifies which part of the URI PATH to start the reverse, cascading search pattern at, when trying to find a match in the MDRDCFG.MDRRSC column.
For example, if MDREST4I_RESOURCE_MATCH 4 is set, then MDRAPI takes the first 4 parts together to try and find a match in MDRDCFG.MDRRSC, and then the first 3 and so on.
If no value is set for MDREST4I_RESOURCE_MATCH it uses only the MDREST4I_RESOURCE_COMPONENT described above.
MDREST4I_RESOURCE_MATCH_ONLY This variable tells MDRAPI to NOT USE MDREST4I_RESOURCE_COMPONENT if no match for the resource is found using the MDREST4I_RESOURCE_MATCH search pattern described above.
This helps exposing programs being called in the LIBL, that are mistakenly found by MDRAPI when the resource does NOT actually match any resource value in MDRDCFG.MDRRSC.
There are two possible values 1 for on and 0 for off. By default it is set to 0/off.
MDREST4I_LOG_RESOURCE_LOOKUP Y When this is set to Y, the paths that MDRAPI tries to do database lookups on will be printed to the job log, making it easier to determine why mapping might be failing.
By default this value is not set.

URL/URI Mapping Examples

Environment variables can be set globally for an LPAR or by CGi job.

To set an environment variable for a specific context on an HTTP server instance, use the SetEnvVar directive within the context it must be applied. These contexts might include:

  • directory
  • location
  • filesematch

In the two examples below, we look at how single and composite values are defined.

Single Path Value Example
Example for HTTPD.CONF
<Directory /QSYS.LIB/MYAPILIB.LIB>
 Require all granted
 SetEnv MDREST4I_LOG_RESOURCE_LOOKUP Y
 SetEnv MDREST4I_RESOURCE_MATCH 6
 SetEnv MDREST4I_RESOURCE_MATCH_ONLY 1
 DefaultNetCCSID 1208
 CgiConvMode binary
 ServerUserID mdowner
</Directory>
MDRSTCFG Settings
MDRSTCFGR                       Edit Config                        21.07.25
QPADEV000M                                                         15:05:20

Root Resource. . . : two/three/four                                   

Method . . . . . . :                                                       

Program. . . . . . : MDRHELLO           Library . : 

Example Request URL `http://myserver.com:2598/mdrapi/two/three/four?qryParm1=parmvalue1

MDRAPI will look look for the first entry in MDRDCFG by checking for the following keys (in the sequence displayed below):

two/three/four
two/three
two

If any of these matches, it will stop searching and use the program and library defined in MDRDCFG.MDPGM and MDRDCFG.MDLIB respectively. If no match is found, the HTTP response will be:

{
    "id": "MDR0101",
    "text": "Path not found in MDRDCFG.",
    "severity": 40
}

MDREST4I_RESOURCE_COMPONENT always used

Unless ENVVAR MDREST4I_RESOURCE_MATCH_ONLY 1 is set, MDRAPI will ALWAYS attempt to match using the value of MDREST4I_RESOURCE_COMPONENT

Provider Program

MDRAPI calls the provider program passing three parameters:

Parameter Description
handle unique threadsafe memory key used by MDRFRAME to allocate and deallocate memory structures
method the HTTP method of the request
body the HTTP message request body (if applicable)

The general flow of the provider program is:

  • Handle the extraction of inbound of REST headers, parameters, attachments, parsing payloads etc.
  • Call or run your business logic, DB/IFS IO, and calls to IBM i applications/Stored procedures etc.
  • Set any error messages.
  • Build REST headers and payloads.
  • Set the HTTP status.
  • Return control to MDRAPI which sends the response via the HTTP server to the REST Client.

This data extraction of the request, and writing of the response is executed by calling the appropriate MDRFRAME procedures (found in the MDRFRAME service program).

Examples

Below is an example of a simple REST Provider program that uses a POST method. The source of these examples can be found in MDRST/EXAMPLES.

Info

In the COBOL example below the MDR-DATAGEN SECTION is used to generate JSON. This function is unique to MDRFRAME, and overcomes the limitation that IBM's DATA-GEN procedure is only available in RPGLE or from V7R2 upwards. The Copybook "MAPIC001C" below shows how the MDR_DATAGEN and MDR_DATAINTO functions use a special 'schema' to parse or generate JSON via the MDRFRAME framework. The MDR_DATAINTO-MDR_DATAGEN section has the details about how to use this.

**free
// CRTBNDRPG PGM(&O/&ON) SRCFILE(&L/&F) OPTION(*EVENTF) DBGVIEW(*ALL) -
// USRPRF(*OWNER) TGTRLS(V7R2M0)

// RPGLE REST API Template Using DATA-GEN and DATA-INTO for JSON.
ctl-opt dftactgrp(*no) actgrp(*new);
ctl-opt BNDDIR('MDRFRAME');

/copy mdrframe

dcl-ds output qualified;
message char(50); // example only : change as required
end-ds;

dcl-ds input qualified;
message char(50); // example only : change as required
end-ds;

dcl-pi *n;
handle    like(MDR_Handle_t);
method    char(32) const;
body      varchar(500000); // MAxSize: 16000000
end-pi;

dcl-s result varchar(1000);

// Logic to process request body
MDR_genParseOptions(handle: 'document_name=input');
data-into input %data('':'')
                %parser('MDRFRAME(PARSER)':handle);

eval-corr output = input;
// Logic to process response
MDR_genParseOptions(handle: 'document_name=output');
data-gen output %data(result: '')
                %gen('MDRFRAME(GENERATOR)':handle);

*Inlr = *On;
PROCESS varchar
        apost
        nomonoprc
        nosync
        nostdtrunc

IDENTIFICATION DIVISION.
PROGRAM-ID.   MAPIC001.
AUTHOR.       Midrange Dynamics.

*>  CRTCBLMOD MODULE(&O/&ON) SRCFILE(&L/&F) DBGVIEW(&DV) -
*>            OPTION(*SOURCE *EVENTF *IMBEDERR)
*>  CRTPGM PGM(&O/&ON) MODULE(&O/&ON) BNDDIR(MDRFRAME) -
*>         ACTGRP(*NEW)
*****************************************************************
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SOURCE-COMPUTER. IBM-I.
OBJECT-COMPUTER. IBM-I.

SPECIAL-NAMES.
* MDRest4i Special Names for MDRFRAME Procedures
* Please insert any program specific SEPCIAL NAMES BEFORE this
* COPYBOOK, and the COPYBOOK delimits the divsion with a period
COPY MDRCBLSPC OF QLBLSRC.

*****************************************************************
DATA DIVISION.
*****************************************************************
WORKING-STORAGE SECTION.
* MDRest4i REQ/RSP Payload Schemas
COPY MAPIC001C OF QLBLSRC.
* MDRest4i Framework Variables
COPY MDRCBLWSC OF QLBLSRC.
* MDRest4i Large Framework Variables
COPY MDRCBLWSVS OF QLBLSRC.

* ===============================================================
LINKAGE SECTION.
COPY MDRCBLLSC OF QLBLSRC.

* MDR-HTTP-METHOD - To recive supplied HTTP method
******************************************************************
01  MDR-HTTP-METHOD      PIC X(10).

* MDR-INPUT-DATA - To recive input JSON request.
******************************************************************
01  MDR-INPUT-DATA.
    10 MDR-INPUT-DATA-LEN      PIC 9(9) USAGE BINARY.
    10 MDR-INPUT-DATA-BUFFER   PIC X(5000000).

* MDR-BODY-TYPE - To recive Body type ( *CAR or *VARCHAR)
******************************************************************
01  MDR-BODY-TYPE              PIC X(10).

PROCEDURE DIVISION USING MDR-HANDLE
                        MDR-HTTP-METHOD
                        MDR-INPUT-DATA
                        MDR-BODY-TYPE.

0000-MAIN-CONTROL SECTION.

BEG.

* Clear the MDR-SCHEMA and MDR-PAYLOAD before process the
* MDR-DATAGEN.
    INITIALIZE MDR-SCHEMA.
    INITIALIZE MDR-PAYLOAD.

* Logic to load response into response data structure.
    MOVE 1 TO MDR-NUM-STOCK OF MDR-A00001-RSP.
    MOVE 'MTB' TO MDR-DEPARTMENT OF MDR-A00001-RSP(1).
    MOVE 'Bikes' TO MDR-MAINCATEGORY OF MDR-A00001-RSP(1).
    MOVE 'MTB' TO MDR-SUB-CATEGORY OF MDR-A00001-RSP(1).
    MOVE 1 TO MDR-NUM-SIZES OF MDR-A00001-RSP(1).
    MOVE 55 TO MDR-SIZES OF MDR-A00001-RSP(1, 1).
    MOVE 1 TO MDR-NUM-COLOURS OF MDR-A00001-RSP(1).
    MOVE 'Red' TO MDR-COLOURS OF MDR-A00001-RSP(1, 1).

* Set the MDR_PAYLOAD from response data structure.
    MOVE MDR-A00001-RSP TO MDR-PAYLOAD.

* Set response Schema into MDR-SCHEMA.
    MOVE MDR-A00001-RSP-SCHEMA TO MDR-SCHEMA.

* Set Data options into MDR-DATA-OPTIONS.
    MOVE 'countprefix=num- renameprefix=name-'
    TO MDR-DATA-OPTIONS
* Generate JSON and send back to output response.
    PERFORM MDR-DATAGEN.

    GOBACK.
*  Default Procedures for MDRest4i Framework
COPY MDRCBLPRC OF QLBLSRC.
*************************************************************************
*// Copybook generated by MDRest4i on 2024-03-07
* ***********************************************************************
*------------------------------------------------------------------------
* MDR-START-UUID : A00001
*------------------------------------------------------------------------
* Response Format UUID : A00001
01  MDR-A00001-RSP-SCHEMA.
    10  MDR-A00001-RSP-LEN PIC 9(8) USAGE BINARY VALUE 720.
    10  MDR-A00001-RSP-001 PIC X(256) VALUE 'hex:7B226E756D2D53746F
-         '636B223A7B223D74797065223A22696E74222C223D6C656E223A313
-         '07D2C2253746F636B223A7B223D64696D223A392C22446570617274
-         '6D656E74223A7B223D74797065223A2263686172222C223D6C656E2
-         '23A337D2C2243617465676F7279223A7B224D61696E43617465676F
-         '7279223A7B223D'.
    10  MDR-A00001-RSP-002 PIC X(256) VALUE '74797065223A2263686172
-         '222C223D6C656E223A357D2C225375622D43617465676F7279223A7
-         'B223D74797065223A2263686172222C223D6C656E223A367D7D2C22
-         '6E756D2D53697A6573223A7B223D74797065223A22696E74222C223
-         'D6C656E223A31307D2C2253697A6573223A7B223D74797065223A22
-         '696E74222C223D'.
    10  MDR-A00001-RSP-003 PIC X(208) VALUE '6C656E223A31302C223D64
-         '696D223A397D2C226E756D2D436F6C6F757273223A7B223D7479706
-         '5223A22696E74222C223D6C656E223A31307D2C22436F6C6F757273
-         '223A7B223D74797065223A2263686172222C223D6C656E223A352C2
-         '23D64696D223A397D7D7D'.

* Response Payload UUID : A00001
* Created: 2024-03-07-11.34.39.125000
* Path: /MDRTST14/json/bikes_new.json
01  MDR-A00001-RSP.
    05  MDR-NUM-STOCK PIC S9(8) USAGE BINARY VALUE 0.
    05  MDR-STOCK OCCURS 9.
    10  MDR-DEPARTMENT PIC X(3).
    10  MDR-CATEGORY.
        15  MDR-MAINCATEGORY PIC X(5).
        15  MDR-SUB-CATEGORY PIC X(6).
    10  MDR-NUM-SIZES PIC S9(8) USAGE BINARY VALUE 0.
    10  MDR-SIZES PIC S9(9) USAGE BINARY OCCURS 9.
    10  MDR-NUM-COLOURS PIC S9(8) USAGE BINARY VALUE 0.
    10  MDR-COLOURS PIC X(5) OCCURS 9.