0
0

(CGI2)IBMiのAPIサーバをFFRPGのCGIで作成する(2)

Posted at

■概略

オープンソースエンジニア歴30年超の筆者が2023年からIBMiを学びだした学習記録です
(CGI1)IBMiのAPIサーバをFFRPGのCGIで作成する(1)」 で作成したサービスプログラム内の
関数を呼び出します

■CGIの要件

・以下のテーブルから指定した物件CDに該当する戸数を取得しJSONで返す
・物件CD未指定ときは 0001 を返す
・POST & GETの読み込み最大長は1024バイト(prototype.ffrpgで指定)
・CGIの出力最大長は2048000バイト=2MB(prototype.ffrpgで指定)
・CGIで引き渡すパラメータは最大10まで(prototype.ffrpgで指定)

◯対象テーブルとフィールド

BKNLIBF.GMBKAF(物件マスター)

COLUMN_NAME COLUMN_TEXT DATA_TYPE LENGTH
BKA001 物件CD CHAR 4
BKA002 物件枝番 NUMERIC 2
BKA003 戸数 NUMERIC 4

◯SQL

select * from BKNLIBF.GMBKAF
 where BKA001='{物件CD}'

◯URL(入力条件)

http://{サーバ}:8080/cgi-bin/BKNKOSU.PGM?bukken_cd={物件CD}

◯JSON(出力条件)

[{"bukken_cd":"物件CD","KOSU":"戸数"}]

■CGIのソースコード

◯POSTとGETから物件CD取得

getCGIVars()関数を呼び、パラメータをCGIkeysとCGIvaluesにいれる

メイン

exsr srGetCGIVars;    // POSTとGETからパラメータを取得

サブルーチン

begsr srGetCGIVars;
    getCGIVars(CGIkeys : CGIvalues);
    for i = 1 to CGIVarsNum;
        if     CGIkeys(i) = 'bukken_cd';
            bukken_cd = %trim(CGIvalues(i));
        endif;
    endfor;
endsr;

◯SQL生成

実行するSQLを文字列として生成する

注意) '(シングルクォーテーション)の扱い
 文字列フィールドを条件に指定する場合は、値を ' で囲む必要がある
 例 : where 文字列フィールド='値'
 RPGの文字列変数の値は'(シングルクォーテーション)で囲む必要がある
 "(ダブルクォーテーション)は使えない
 よって文字列に '(シングルクォーテーション)を含めるには、
 '' とシングルクォーテーションを2回繰り返すことでエスケープになる
 文字列変数 = '''' → 文字列変数の値は '(シングルクォーテーション)1個

メイン

exsr srCreateSQL;     // SQL生成

サブルーチン

begsr srCreateSQL;
    sql_str   = 'select * from BKNLIBF.GMBKAF';
    where_str = ' where BKA001=''' + bukken_cd + '''';
    if bukken_cd <> '';
        sql_str += where_str;
    endif;
endsr;

◯SQL実行と結果変数resultの取得

SQL組込み関数のカーソル機能で複数行を取得し、結果配列変数resultに代入する

なおresultはOS7.4から利用可能な動的配列を利用している
結果数は不明なので、初期配列数は0、最大20000まで動的に拡張する

メイン

exsr srExecSQL;       // SQLを実行しresultを取得する

サブルーチン

begsr srExecSQL;
    exec sql prepare sql1 from :sql_str;
    exec sql declare csr1 cursor for sql1;
    exec sql open csr1;
    dou SQLSTATE = END_OF_FILE;
        exec sql fetch csr1 into :dsGMBKAF;
        if SQLSTATE <> END_OF_FILE;
            i = %elem(result) + 1;
            result(i).key1 = 'bukken_cd';
            result(i).val1 = %char(dsGMBKAF.BKA001);
            result(i).key2 = 'KOSU';
            result(i).val2 = %char(dsGMBKAF.BKA003);
        endif;
    enddo;
    exec sql close csr1;
endsr;

◯結果変数resultをJSONに変換し出力

メイン

exsr srConvertJSON;   // resultをJSON変換しBufOutに入れる
responseHTTP(BufOut); // 出力する    

サブルーチン

begsr srConvertJSON;
    BufOut = '[';
    for i=1 to %elem(result);
        BufOut = %trim(BufOut) + '{';
        BufOut = %trim(BufOut) +
            '"' + result(i).key1 +'":' +
            '"' + result(i).val1 +'",' +
            '"' + result(i).key2 +'":' +
            '"' + result(i).val2 +'"';
        // JSON末尾の , はトル
        if i = %elem(result);
            BufOut = %trim(BufOut) + '}';
        else;
            BufOut = %trim(BufOut) + '},';
        endif;
    endfor;
    BufOut = %trim(BufOut) + ']';
endsr;

◯CGIの全ソースコード

prototype.ffrpgは(CGI1)IBMiのAPIサーバをFFRPGのCGIで作成する(1)と同じ

**free
// 2024/06/26 えむぼま高見禎成 作成
//
//【注意】
// POST & GETの読み込み最大長は1024バイト(prototype.ffrpgで指定)
// CGIの出力最大長は2048000バイト=2MB(prototype.ffrpgで指定)
// CGIで引き渡すパラメータは最大10まで(prototype.ffrpgで指定)
// Qtmh*呼出し時はvarchar不可。charでないとCGI実行エラーになる!
//
ctl-opt main(main);
ctl-opt text('物件別戸数取得CGI');

// プロトタイプ
/include ./prototype.ffrpg

// メイン関数
dcl-proc main;
    // CGI用変数(大文字始まりは外部連携利用)
    dcl-s  CGIkeys    char(BufInLen) dim(CGIVarsNum);
    dcl-s  CGIvalues  char(BufInLen) dim(CGIVarsNum);
    dcl-s  BufOut     char(BufOutLen);
    // 変数
    dcl-s  i          packed(4:0);
    dcl-s  bukken_cd  char(4) inz('0001');
    dcl-s  sql_str    varchar(255) inz('');
    dcl-s  where_str  varchar(255) inz('');
    // レコード様式 [JSON形式に応じて要変更]
    dcl-ds dsGMBKAF extname('GMBKAF') qualified;
    end-ds;
    // JSON展開前の結果変数 [JSON形式に応じて要変更]
    // 動的配列の最大サイズの16MBを超えないように定義すること
    // 物件数は7000強なので最大20000にした
    dcl-ds result     dim(*auto : 20000) qualified;
        key1 varchar(20) inz('');
        val1 varchar(20) inz('');
        key2 varchar(20) inz('');
        val2 varchar(20) inz('');
    end-ds;

    exsr srGetCGIVars;    // POSTとGETからパラメータを取得
    exsr srCreateSQL;     // SQL生成
    exsr srExecSQL;       // SQLを実行しresultを取得する
    exsr srConvertJSON;   // resultをJSON変換しBufOutに入れる
    responseHTTP(BufOut); // 出力する
    return;

    // -----------------サブルーチン---------------------
    // POSTとGETからパラメータを取得
    begsr srGetCGIVars;
        getCGIVars(CGIkeys : CGIvalues);
        for i = 1 to CGIVarsNum;
            if     CGIkeys(i) = 'bukken_cd';
                bukken_cd = %trim(CGIvalues(i));
            elseif CGIkeys(i) = 'token';
                token = %trim(CGIvalues(i));
            endif;
        endfor;
    endsr;

    // SQL生成 --ここにSQLを組込む
    // bukken_cdがなければ全件(whereなし)
    begsr srCreateSQL;
        sql_str   = 'select * from PMLIBF.GMBKAF';
        where_str = ' where BKA001=''' + bukken_cd + '''';
        if bukken_cd <> '';
            sql_str += where_str;
        endif;
    endsr;

    // SQLカーソルでresult取得 
    begsr srExecSQL;
        exec sql prepare sql1 from :sql_str;
        if SQLSTATE = SYNTAX_ERROR;
            leavesr;
        endif;
        exec sql declare csr1 cursor for sql1;
        exec sql open csr1;
        dou SQLSTATE = END_OF_FILE;
            exec sql fetch csr1 into :dsGMBKAF;
            if SQLSTATE <> END_OF_FILE; 
                i = %elem(result) + 1;
                result(i).key1 = 'bukken_cd';
                result(i).val1 = %char(dsGMBKAF.BKA001);
                result(i).key2 = 'KOSU';
                result(i).val2 = %char(dsGMBKAF.BKA003);
            endif;
        enddo;
        exec sql close csr1;
    endsr;

    // JSONに変換 
    begsr srConvertJSON;
        BufOut = '[';
        for i=1 to %elem(result);
            BufOut = %trim(BufOut) + '{';
            BufOut = %trim(BufOut) +
                '"' + result(i).key1 +'":' + 
                '"' + result(i).val1 +'",' + 
                '"' + result(i).key2 +'":' + 
                '"' + result(i).val2 +'"';
            // JSON末尾の , はトル
            if i = %elem(result);
                BufOut = %trim(BufOut) + '}';
            else;
                BufOut = %trim(BufOut) + '},';
            endif;
        endfor;
        BufOut = %trim(BufOut) + ']';
    endsr;
end-proc;

■CGIのコンパイルbash

◯個人ライブラリにコンパイル

#!/bin/bash
USER=`whoami`
#---
TARGET_LIB=${USER}"LIB"
PGM="BKNKOSU"
SRVPGM="CGILIB"
DIR="/home/${USER}/CGIs/QFFRPGSRC"
#---
# メインモジュール
file=$DIR"/"$PGM".SQLFFRPG"
target=$TARGET_LIB"/"$PGM
target_srv=$TARGET_LIB"/"$SRVPGM
system "DLTMOD MODULE($target)"
system "CRTSQLRPGI OBJ($target) SRCSTMF('$file') OBJTYPE(*MODULE) COMPILEOPT('TGTCCSID(5035)') RPGPPOPT(*LVL2)"

# プログラム
system "DLTPGM PGM($target)"
system "CRTPGM PGM($target) MODULE($PGM) BNDSRVPGM($SRVPGM)" 2>&1

◯developブランチをCGILIBへ出力

#!/bin/bash
USER=`whoami`
#---
TARGET_LIB='CGILIB'
PGM="CGITemplate"
SRVPGM="CGILIB"
DIR="/home/${USER}/CGIs/QFFRPGSRC"
#---
# gitでdevelopに変更し最新に更新する
git checkout develop && git pull origin --ff-only

# メインモジュール
file=$DIR"/"$PGM".SQLFFRPG"
target=$TARGET_LIB"/"$PGM
target_srv=$TARGET_LIB"/"$SRVPGM
system "DLTMOD MODULE($target)"
system "CRTSQLRPGI OBJ($target) SRCSTMF('$file') OBJTYPE(*MODULE) COMPILEOPT('TGTCCSID(5035)') RPGPPOPT(*LVL2)"

# プログラム
system "DLTPGM PGM($target)"
system "CRTPGM PGM($target) MODULE($PGM) BNDSRVPGM($SRVPGM)" 2>&1

# 元のbranchに戻る
git checkout -```
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0