TypeScript SDK 和 REST API


      在本文中,我們將討論CUBA平台中已經存在很長時間的一個功能,但是很多人還不知道,這就是前端SDK生成器,並了解它如何與CUBA的REST API插件一起使用。

Java+JavaScript - 在 web 中喜結連理

      僅僅只是大概八年之前,我們 Java 開發者將 JavaScript(JS) 作為“二等公民”語言用在 Web 應用程序中。那時,用 JS 的目的只是為了在網頁中加入一些動效,網頁也是使用 JSF、Struts、Tapestry 或 Thymeleaf 等框架在服務器端生成的。如今,我們見證了 JS  作為使用React、Vue 或 Angular 等框架進行客戶端開發的第一語言,甚至連 Node.js 也出現在了服務端。

      實際應用中,我們開發的 Web 應用程序可能在不同的層上使用不同的語言:JS 用於客戶端UI,Java 用於業務邏輯處理,SQL 用於從數據庫中獲取數據,Python 用於數據分析,等等。然后再使用各種技術將所有這些語言組合到一個應用程序中。最常見的例子就是 REST API,基於平台無關的 HTTP 協議和簡單的 JSON 格式,現在已經成為連接客戶端 JS 和服務器端 Java 的默認方法。

      但是,即使是最好的裁縫也不能無縫縫制衣裳。 定義 API 始終存在一個問題:要調用的方法是哪個,數據模型是什么,還有比如說我們應該將街道地址作為結構化對象還是作為字符串傳遞?

      我們如何才能幫助我們的 JavaScript 同事更快地創建代碼還能避免溝通的不暢?

Swagger 會是終極答案嗎?

      也許你要說“Swagger”,沒錯。 Swagger 實際上已經是設計、構建、記錄和使用 REST API 的工業標准。也有許多代碼生成器可幫助生成用於不同語言的客戶端 SDK。

      CUBA 框架就支持 Swagger,每個帶有 REST API 擴展組件的應用程序都有一個 API 端點可以用來下載 .json 或 .yaml 格式的 Swagger 文檔。您可以使用這些文件來生成 JS 客戶端。

      但是事實上,Swagger 只是一個 API 文檔工具。那么前端開發人員希望在 API 中看到什么樣的信息呢? “經典”的做法是:將業務功能映射為服務,並構建一套定義規范的 API。再將這套 API 公開為一組 REST 服務,最后添加 Swagger 文檔,差不多就可以了。

      如果真的是這樣的話,為什么 GraphQL 會快速崛起並在前端開發人員中引起轟動呢? 我們注意到,GraphQL 的份額一直在不斷增長。到底是怎么回事?事實證明,遇到經常會變動的用例,提供更“通用”的 API 對前端人員來說更加合適,因為可以避免創建很多小的 API。比如,對於 Web UI 中的購物車情景,一個物品的價格只需要第一次調用時獲取,之后對於該物品只需要知道總數即可。另外,GraphQL 可以避免過度獲取數據或者數據獲取不足,還能一次調用多個 API 獲得復雜的返回數據結構。

      這樣的話,似乎應用程序不止應該開放服務的 API,還應該提供一些通用 API。這種方式使得前端開發人員可以調用復雜的業務功能,但是也為他們提供一定程度的靈活性。因此,如果他們只是需要針對不同 UI 獲取數據的不同展現形式,他們不會要求提供新的 API。

      還有一個問題是 Swagger 或 GraphQL 或 OData 都無法解決的,那就是如果更改了某些內容,針對之前已經生成的客戶端代碼,如何做適配呢?直接一次性生成代碼很容易,但是能支持業務的變化卻是另外一回事了。比如,我們刪除了實體的一個屬性,怎么保證前端應用程序不會出問題?

      所以,綜合來看,為了加速前端開發並簡化后端團隊與前端團隊之間的協作,我們需要:

         1.定義特定業務的 API 和通用 API

         2.根據后端數據模型和方法簽名來生成前端代碼

         3.如需修改生成的代碼,需要保證花費最小的人力並且盡量避免 bug

      我們在 CUBA 的 REST API 擴展組件和前端 SDK 生成器中也面臨着相同的所有挑戰。

CUBA TypeScript SDK

      在CUBA中,REST API 擴展組件提供以下功能:

         | 數據模型實體的 CRUD 操作

         | 執行預定義的 JPQL 查詢

         | 執行服務方法

         | 獲取元數據(實體,視圖,枚舉,數據類型)

         | 獲取當前用戶權限(訪問實體、屬性以及特定權限)

         | 獲取當前的用戶信息(名稱,語言,時區等)

         | 處理文件

      功能上說,我們提供了從任何前端客戶端訪問應用程序的所有功能。這些 API 都通過swagger YAML 文件或者 JSON 文件進行說明,對於前端開發來說,可以使用這些文檔立即進行開發。

      為 REST API 用戶設置安全規則也很重要,需要防止 API 端點意外暴露給所有用戶。首先要禁止所有用戶對於常規 REST API 訪問,然后為需要訪問某些功能的角色創建特殊的權限。

      CUBA 不止能提供 REST API,還可以生成前端使用的 SDK,該 SDK 可以作為任何前端開發框架的基礎,React、Angular、Vue 或者其他框架都能用。

      用這個生成器能生成一組 TypeScript 類,通過這些類可以在客戶端應用程序調用CUBA 的 API。

      如果要生成 SDK,可以運行下列命令:

             npm install -g @cuba-platform/front-generator

      然后:

             gen-cuba-front sdk:all

      該功能會創建所有的 SDK 類。甚至能基於 ReactJS 直接生成一個簡單的 UI,這樣客戶能立即使用基於 CUBA 的應用程序。雖然生成的 UI 非常基礎,但是由於集成了 CUBA,所有 CUBA 的功能都可以使用,包括身份驗證、基於角色的數據訪問、實體圖的查詢等等。

      下面我們看看 SDK 里面到底包含了什么。

數據模型

      應用程序的數據模型在 SDK 中是一組 TypeScript 的類。以快速開始中的 Session Planner 為例,Java 中有一個實體:

      然后在 SDK 中,會生成一個對應的類:

      所有的數據關聯關系和組合關系也都會保留,因此可以直接獲取實體關系圖而不需要調用多個 API 一個一個的獲取各個實體了。

      另外,這里也沒有 DTO,獲取到的數據跟后台描述的一樣。

業務邏輯服務

      在 SDK 中,所有開放的 CUBA REST 服務都會在 TypeScript 中得到體現。比如,如果我們用 REST API 開放了 Session Service 的接口,TypeScript 中的代碼會是這樣:

      可以在前端代碼中這樣調用:

      很方便吧?繁雜的 routine 工作都通過生成的代碼完成了。

通用 API

      如果自定義邏輯只需要在前端實現的話,可以直接使用在核心 CUBA 平台 REST 庫中定義的一組功能,例如:

            loadEntities<T>(entityName: string, options?: EntitiesLoadOptions, fetchOptions?: FetchOptions): Promise<Array<SerializedEntity<T>>>;

            deleteEntity(entityName: string, id: any, fetchOptions?: FetchOptions): Promise<void>;

      這些方法提供了對應用程序中實體 CRUD 粒度的訪問操作。訪問的安全性也依然存在,CUBA會在服務器端驗證所有非匿名調用,並防止用戶獲取不符合其角色的實體或屬性:

            cubaREST.loadEntities<Speaker>(Speaker.NAME).then( (result => {

               //Result handling

            }));

      通過使用這些通用的 API,開發人員可以用 JS 在基於實體 CRUD 之上創建自定義的 API 層應用程序,並將其部署至 Node.js,以實現“服務於前端的后端”架構模式。而且,用這種方式創建的 API 層可以是多個,比如我們可以為不同的客戶端創建不同的 API 層:ReactJS,原生 iOS等等。這種用例場景下,自動生成的 SDK 是最理想的工具。

      一般情況下,通用 API 的不足之處在於,獲取的屬性超過了所需的屬性或者API描述符中的屬性不足時,可能會導致數據獲取不足或獲取過多的風險。 但是,CUBA 的實體視圖在后端解決了這個問題,我們為前端開發人員也提供了同樣的方法! 對於每個生成的TypeScript類,我們創建能反映視圖的類型:

      因此,可以從后端獲取實體並且只獲取后端視圖指定的屬性。這樣的話,不需要去猜測到底拿到了哪些屬性,IDE 會自動幫你補全:

API 更新

      如之前所述,代碼生成只是開發過程中的很小一部分。代碼改動和持續的支持才是耗費時間的地方。CUBA 的 TypeScript SDK 生成器在隨后的運行期間會分析代碼,跟蹤改動並進行增量更新。 如果您將 TypeScript 作為前端的主要開發語言,TypeScript 編譯器也會確保您不會忘記更新使用 SDK 的自定義代碼。

總結

      除了基於 Vaadin 的通用 UI 之外,如果您還想為 CUBA 應用程序開發基於 JS 的客戶端(React / React Native,Angular 或 Vue 等),則可以使用 REST API 擴展插件和 TypeScript SDK。通過使用 TypeScript SDK,不論使用何種前端技術,您都可以只關注設計或者性能,以便提供最佳的用戶體驗,而不需要做重復冗余的工作。並且幾乎可以肯定 JS 和 Java 之間的通信以及支持 API 變化將會是您開發過程中最小的問題。

      了解 CUBA 平台,請訪問 CUBA 中文官網


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM