Genero 4GL High-Level Web framework 高階web服務開發 (3.21+)

本文件旨在說明 FourJs Genero 4GL 3.21 及後續更高版本中,High-Level Web frame的開發方式,並與傳統方法進行比較,著重於其優勢和簡化之處。Genero3.21為鼎新/鼎捷 T100 ERP V3.1以上採用的Genero版本,用戶可透過 fglrun -V 檢視版本訊息。

1. High-Level Web Frame 與傳統寫法之比較

在 Genero 4GL 中,傳統的 Web Service 開發方式通常涉及較多的底層操作,例如手動處理 SOAP 訊息、WSDL 解析等。而 High-Level Web Frame的引入,旨在簡化這些流程,讓開發者能夠更專注於業務邏輯的實現。

1.1 傳統寫法

* 需要使用 `com.WebService` 和 `com.WebOperation` 等 COM 物件來定義 Web Service 和其操作。
* 需要較多地關注 WSDL 文件的細節。
* 錯誤處理和資料轉換需要較多手動編碼。
* 對於 RESTful 風格的 Web Service,支援相對較弱。

1.2 High-Level Web Framework

* **簡化:** 透過固定寫法的 server,呼叫『註冊』在主4gl內的 function,使用 `FUNCTION ATTRIBUTES` 設定REST參數、環境,即直接生成可運作的 service。
* **直觀:** 開發者可以使用熟悉的 4GL 語法,無需深入了解底層的 SOAP 或 WSDL。
* **RESTful 支援:** 提供對 RESTful 風格 Web Service 的良好支援,包括 HTTP 方法、URI 模板等。
* **效率:** 減少了開發所需的時間和程式碼量。

1.3 優勢總結

| 特性     | 傳統寫法                                 | High-Level Web Service                     |
| :------- | :--------------------------------------- | :------------------------------------------ |
| 開發難度   | 較高,需要理解底層細節                   | 較低,直面需求段 4GL 開發                   |
| 程式碼量   | 較多                                     | 少                                        |
| 可讀性     | 較差,程式碼較為冗長                     | 好,程式碼更簡潔易懂                      |
| 維護性     | 較差,修改和除錯較為困難                   | 好,程式碼結構清晰,易於維護                |
| REST 支援 | 較弱                                     | 良好                                        |

2. as.xcf 的設定方法

`as.xcf` 檔案是 Genero Application Server (GAS) 的主要設定檔。 High-Level Web Framework 仍歸屬於 Service部分,且建議將主要 as.xcf中額外配置子路徑,以便『減少維護的過程中必須因重啟服務造成停機』,可極大地減少用戶於更新時無法使用的困擾。

2.1 主要 as.xcf 中配置 service 路徑

在 `as-topprd.xcf` 檔案為例,在 <APPLICATION_SERVER> 的 <SERVICE_LIST>段落內,可調整配置如下:

```xml
<APPLICATION_SERVER>
  ...
  <SERVICE_LIST>
    <GROUP Id="top">$(res.zone.config)/xcf/high</GROUP>
  </SERVICE_LIST>
</APPLICATION_SERVER>
```

* `res.zone.config`:  `T100` 系統下 erp/cfg 配置路徑。
上述增加後,須完成 fastcgidispatch 的重啟 (或在系統可重啟的時間,重啟 web service),後續即可在 $ERP/cfg/xcf/high 目錄下維護 個別的 xcf 檔案,隨條即用,不須再做重新啟動 fastcgidispatch。

2.2 設定個別服務自己使用的 as.xcf

經過 2.1 設定後,即可前往 $TOP/erp/xcf/high 配置個別端口應用程式。例如:

```xml
<?xml version="1.0" encoding="UTF-8" ?>
<APPLICATION Parent="ws.default"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:noNamespaceSchemaLocation="https://4js.com/ns/gas/5.00/cfextws.xsd">
  <EXECUTION>
    <!-- ENVIRONMENT FOR Genero/DB -->
    <ENVIRONMENT_VARIABLE Id="LD_LIBRARY_PATH">/usr/lib64:/usr/lib/oracle/21/client64/lib:/usr/lib64::/usr/lib/jvm/java-17-openjdk-17.0.13.0.11-4.el9.x86_64/lib/server</ENVIRONMENT_VARIABLE>
    <ENVIRONMENT_VARIABLE Id="ORACLE_HOME">/usr/lib/oracle/21/client64</ENVIRONMENT_VARIABLE>
    <ENVIRONMENT_VARIABLE Id="ORACLE_SID">topprd</ENVIRONMENT_VARIABLE>
    <ENVIRONMENT_VARIABLE Id="TWO_TASK">topprd</ENVIRONMENT_VARIABLE>
    <ENVIRONMENT_VARIABLE Id="TNS_ADMIN">/u2/oracle/topprd</ENVIRONMENT_VARIABLE>
    <ENVIRONMENT_VARIABLE Id="NLS_LANG">AMERICAN_AMERICA.AL32UTF8</ENVIRONMENT_VARIABLE>
    <ENVIRONMENT_VARIABLE Id="FGLPROFILE">/u1/etc/fglprofile.topprd</ENVIRONMENT_VARIABLE>
    <PATH>$(res.zone.erp)/asa/42m</PATH>
    <MODULE>asa_asap000.42m</MODULE>
  </EXECUTION>
</APPLICATION>

```
* 若需要連結數據庫,則須將數據庫客戶端需求的環境變數加入此處,如ORACLE會需要 `ORACLE_HOME`、`ORACLE_SID`、`TNS_ADMIN`、`FGLPROFILE` 等。
* 子程式的部分,請以 IMPORT的方式撰寫,盡量避免使用 link連結的方法。

3. 撰寫服務的 4GL Function 與 ATTRIBUTES

使用 High-Level Web Framework 時,關鍵在於使用 `FUNCTION ATTRIBUTES` 子句來定義 4GL 函式的 Web Service 相關屬性。

3.1 FUNCTION ATTRIBUTES 設定

以下透過簡單的案例介紹 FUNCTION 後方的屬性 (ATTRIBUTES) 設定方法。
```4gl
PUBLIC FUNCTION Add( a INTEGER ATTRIBUTES(WSQuery),
                     b INTEGER ATTRIBUTES(WSQuery)  )
  ATTRIBUTES (WSGET, WSPath='/add',
              WSDescription='Simple query sample')
  RETURNS (INTEGER)
  RETURN a+b
END FUNCTION
```中,在變數部分的 ATTRIBUTES 為* **WSQuery**:標示此參數為傳入參數

在 FUNCTION層級的 ATTRIBUTES 為
* **WSGET**: 採用 GET 方法
* **WSPath**: URL路徑。整個路徑為:http://IP/ws/r/主as.xcf中配置的路徑/子xcf檔名/此處設定的路徑
* **WSDescription**: Service說明

3.2 主程式設定

主程式的部分,可以直接複製 $FGLDIR/demo/WebServices/books/server/BookService.4gl 的main段落來使用,或整隻參考

其中,註冊 WEB Service的部分為下列段落:
```4gl
    # Register all public function with a REST Verb of module Users.4gl as a rest service
    CALL Com.WebServiceEngine.RegisterRestService("BookService", "Books")```

注意,縱使如範例程式,其 Web Service也是在同一隻 4GL內,此 4GL 一樣要做註冊 (如本隻作業呼叫 RegisterRestService ,第一個參數是 4gl 名稱,第二參數是服務名稱。

更詳細的屬性說明,請參考 FourJs Genero 的官方文件。
https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/t_gws_restful_high_level_quick_start_service_module.html

FUNCTION內的屬性文件
https://4js.com/online_documentation/fjs-fgl-3.21.05-manual-html/#fgl-topics/r_gws_high_level_rest_api_attributes.html

4. 測試

測試時,可以用 http://IP/ws/r/主as.xcf中配置的路徑/子xcf檔名?OpenAPI.json 的方式查看輸出輸入所許要使用的參數,來查看程式是否可以正常運作。