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
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 reading the MDRDCFG file, 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.
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.
MDRAPI uses two IBM i environment variables to establish what pattern to use when reading the MDRDCFG file with SQL. Both can be set globally for the system, or in the httpd.conf for the HTTP instance used to handle the providers/apis.
Example on how to set these in httpd.conf. These can be set for the entire IBM i system, site, location, directory or filesmatch contexts.:
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 tells MDRAPI to behave in a different way when trying to find a record in MDRDCFG. It specifies how many of the parts of the URI PATH to use in trying to find a match in the MDRDCFG.MDRRSC column
If no value is set for MDREST4I_RESOURCE_MATCH it uses only the MDREST4I_RESOURCE_COMPONENT described above.
Provider URI Mapping Example
Lets say MDREST4I_RESOURCE_COMPONENT is 2, and MDREST4I_RESOURCE_MATCH is 5 and you have a path like this:
/mdrapi/two/three/four/five
MDRAPI will look look for the first entry in MDRDCFG by checking for the following keys (in the sequence displayed below):
If one of these has a program name found, it will stop searching and use that program (and library). If none do, it will not try to call a program named ‘two’ because MDREST4I_RESOURCE_MATCH is higher than 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.