iT邦幫忙

2021 iThome 鐵人賽

DAY 18
0
Software Development

Genero Packages - 可接替4GL的LowCode商業語言系列 第 18

[GWS] 服務簡單做-RESTful的開發方式

在Genero FGL上也可以做出 RESTful 的 WEB Service。

先將回應WEB Request的方式拆解出來。如同之前在GAS設定章節中提到的,SERVICE與APPLICATION 的設定方式非常類似 (APPLICATION_LIST配置方式若不太清楚,可參考 [GAS] GBC上運作的Hello world!最下方的段落。)

https://ithelp.ithome.com.tw/upload/images/20210919/200511698hILAf5VOC.png

as.xcf配置 SERVICE_LIST

整段 as.xcf 最下方就是配置 WEB SERVICE的 SERVICE_LIST段落。基底(parent) 基本都是 ws.default

方法1.配置在as.xcf內

若以 service 名稱 svms配置服務可參考下列範例:

      <APPLICATION Id="svms" Parent="ws.default" Abstract="TRUE">
        <EXECUTION>
          <PATH>$(res.zone)/svms/server</PATH>
          <MODULE>SvmsServer.42r</MODULE>
          <ACCESS_CONTROL>
            <ALLOW_FROM>$(res.access.control)</ALLOW_FROM>
          </ACCESS_CONTROL>
          <POOL>
            <START>0</START>
            <MIN_AVAILABLE>1</MIN_AVAILABLE>
            <MAX_AVAILABLE>1</MAX_AVAILABLE>
          </POOL>
        </EXECUTION>
      </APPLICATION>

與APPLICATION段落有差別的地方,主要在多了POOL設定。此設定可編配初始在 GAS啟動時,是否一併啟動此服務(START),最大同時在系統中可併行 (MAX_AVALIABLE)支數,最小留存在系統中(MIN_AVALIABLE)支數

最小留存隻數的存在是為了不要讓每次 REQUEST進來時,都要『等待』程式的啟動(還要跑fglrun、連結database等等事務),應該要留下『待命用的』程式,隨時隨地等著 REQUEST做快速、即時的響應。

但是,要掂量掂量自己手上的 license。一個留存的service占用 1 runtime license。請仔細估算。別忘了還要保留給日常作業執行。

方法2.在as.xcf內,只配置GROUP ID

與 APPLICATION_LIST相同,在 SERVICE_LIST中也可以配置 GROUP

      <GROUP Id="_default">$(res.zone.config)/xcf/gws-ws</GROUP>
      <GROUP Id="demo">$(res.path.fgldir.demo.services)</GROUP>
      <GROUP Id="svms">/u1/topprd4/svms</GROUP>

系統中也有預設提供的路徑,我們也可以加上自己有的路徑(svms)。這樣的配置好處仍舊是:不用每次調整個別的程式時,都要做 fastcgidispatch/httpdispatch的重啟

在指定的路徑下面(也就是上方標示的 /u1/topprd4/svms,若用RESOURCE_ID -$(res.xx)-替代,則需對應as.xcf最上方的訊息),則可以配置自己的應用程式名稱,例如:我們配置一個名為『Vehicle.xcf』時,未來調用此服務的路徑就會是『http://server_ip/wtopprd/svms/Vehicle 』開頭 (此路徑以下的拆解就會在程式內處理)。

配置 Server.4gl

下方的 server.4gl基本都可視為一個公版,主要在設定接收 WEB Service的設定。

IMPORT COM                 #取用httpd套件
IMPORT FGL ServiceVehicle  #實際進行服務處理的子程式

SCHEMA svms
MAIN
  DEFINE  req   com.HttpServiceRequest
  #設定發生錯誤前作可以等待的時間(預設:5sec)
  CALL com.WebServiceEngine.SetOption("readwritetimeout",60)
  #設定客?端、HTTPRequest和TCPRequest等待與server建立連線的最長時間(預設30,-1為無限)
  CALL com.WebServiceEngine.SetOption("connectiontimeout",25)
  #設定REST 操作中的 MIME類型的支持。有XML/JSON(預設BOTH)
  CALL com.webserviceEngine.SetOption("server_restdefaultformat","json")

  # Start server
  CALL com.WebServiceEngine.Start()  #開始等待

  WHILE TRUE
    TRY
      LET req = com.WebServiceEngine.GetHttpServiceRequest(-1)
      IF req IS NULL THEN
        IF int_flag THEN
          EXIT WHILE
        END IF
      ELSE
        CALL ProcessRequest(req)  #服務進線,往子程式傳遞處理
        LET int_flag = FALSE
      END IF
    CATCH
      EXIT WHILE
    END TRY
  END WHILE
END MAIN

這一段主程式主用途相當的固定。接下來看主程式內的 function 對照服務路徑的寫法:

FUNCTION ProcessRequest(req)
   DEFINE  req   com.HTTPServiceRequest
   DEFINE  path  STRING
   DEFINE  ind   INT
   LET path = req.getUrlPath()    #依照接續下來的路徑區分要呼叫的子 function

   #Request路徑 /List
   LET ind = path.getIndexOf("/List",1)
   IF ind>0 THEN
      LET path = path.subString(ind,path.getLength())
      CALL ServiceVehicle.ProcessListRequest(req, path)  #此處意思就是 /List就呼叫這個
      # 42m模組名.function名
      RETURN
   END IF
   #上述這一項,若 http://server_ip/wtopprd/svms/下除了List還有其他路徑,
   #均需要模仿此方式串接處理子程式
   #其他不合路徑一律列為未定義 Undefined request
   CALL req.sendTextResponse(400,NULL,"The Function Still UNSupport!")
END FUNCTION

主程式段,主要在做路徑對應處理的function,搭配提供的服務逐一配置即可。

子程式 ServiceVehicle.4gl 配置

子程式個別 function內,就是對應資料的處理。關於個別對應資料如何檢核、校正調整,並寫入database,就請參考相關章節進行編寫。

IMPORT com
IMPORT util
IMPORT FGL Helper     #FGL一些額外的套件
IMPORT FGL WSHelper   #FGL一些處理WS的額外套件
SCHEMA svms
PUBLIC FUNCTION ProcessListRequest(req, path)
  DEFINE  req     com.HTTPServiceRequest
  DEFINE  path    STRING

  CASE req.getMethod()   #確認要接的RESTful型態
    WHEN "GET"   CALL GetListRequest(req,path)   #GET方法的處理
    WHEN "POST"  CALL PostListRequest(req,path)  #POST方法的處理
    OTHERWISE
       CALL req.sendTextResponse(400,NULL, "暫時不支持本服務")
  END CASE
END FUNCTION

承接主程式的路徑後,接下來在此子程式做的就是 ** action種類的判讀**。從上述的範例可以看到,在這段作業中只接受 REST的GET與POST,而若是DELETE或其他動作傳入,則會回傳 400。

接下來以 GET的方法為例,說明處理方式:

PRIVATE FUNCTION GetListRequest(req,path)
  DEFINE req     com.HTTPServiceRequest
  DEFINE path    STRING
  DEFINE ops     Helper.OperationsType
  DEFINE txt     STRING
  DEFINE token   STRING
  DEFINE now     DATETIME YEAR TO SECOND
  DEFINE query   WSHelper.WSQueryType

  CALL Helper.SplitOperations(path,"/List") RETURNING ops  #確認List後面跟上的路徑是否有次層
  CALL req.getUrlQuery(query)

  CASE ops.getLength()
    WHEN 1   #Request發在本層的處理
       #在這裡寫接收到資料的處理方式
       LET response_string="xxxxx"  #如果回傳的是資料,記得轉換為json格式的字串
       #處理完成後要回傳的字串
       CALL req.setResponseHeader("Content-Type","application/json")  #回傳格式設為json
       CALL req.setResponseHeader("Cache","no-cache")       #不支持cache
       CALL req.sendTextResponse(200,NULL, response_string) #處理完成後,回傳200及對應訊息

    WHEN 2    #如果有兩層的 Request路徑,例如 /List/OnlyThisWeek  只找本周來的資料
      # 處理 /Commmant/Asktime
      IF ops[1]=="OnlyThisWeek" AND query.getLength()==1 THEN
        #放處理機制,回傳資料放入 response_this_week
        CALL req.sendTextResponse(200, NULL, response_this_week)
      END IF

    OTHERWISE  CALL req.sendTextResponse(400,NULL,"暫時不提供此路徑的服務")
  END CASE
END FUNCTION

透過上述程式的組裝,我們就可以完成基本的 RESTful 程式搭建。


上一篇
[FGL] 再探資料庫 - 使用 fgldbsch 工具
下一篇
[FGL] 程式開發(2) - 4類6個交談指令-功能選單部分
系列文
Genero Packages - 可接替4GL的LowCode商業語言32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
尾椎
iT邦新手 5 級 ‧ 2022-03-04 12:10:57

沒想到這個偏門語言有系列文,學到了不少東西,謝謝分享。

hjwang65 iT邦新手 4 級 ‧ 2022-03-08 09:16:39 檢舉

資料是有的,大多較為零散,透過 ithome 的環境可以串接起來

我要留言

立即登入留言