從頭建立一套 web-based 服務架構 (9) 開發 Loopback App

繼昨天介紹了 API Server 的基本架構後,今天要來簡單介紹 Loopback 為了快速開發而提供的諸多方便功能。

Config

Loopback 的概念處處充滿 declarative,也就是以 JSON 檔設定需要啟用的功能和它們的設定;這和自行呼叫程式碼進行設定的 imperative 相比,能夠更簡易、不出錯地進行環境設定,但也較不具彈性。 這些設定檔會放在 src/config 資料夾內。 除了使用 JSON 格式,所有的設定檔均能使用一般的 JavaScript 格式,寫成 CommonJS module 並於 module.exports 輸出和 JSON 檔相同的 JavaScript 物件即可。 這個作法可以用來和環境變數整合,讓有需要的設定值能夠於佈署時期決定。 以下介紹一些常用的設定值:

  • config.json: Server instance 本身的相關設定
    • restApiRoot: 設定 RESTful API 的 root path,一般而言不會使用 server 本身的根路徑 /,而是用一兩層 path 進行包裝,例如 /api/api/v1
    • hostport 用來傳給 Node.js 原生的 http module 中的 server.listen API。
    • remoting.rest.normalizeHttpPath 把 URL path 正規化(underscore 變 dash、Camel case 變 Kebab case
    • remoting.rest.xml: 設定是否要接受 appliaction/xml 類型的 Content-Type
    • remoting.json: 傳給 bodyParser 用的參數設定
    • remoting.urlencoded: 傳給 bodyParser.urlencoded 用的參數設定
  • datasources.json: Loopback 允許設定複數的 ORM/ODM 綁定,支援範圍包括 MySQL、MongoDB 甚至 in-memory 的 redis 均可。不同的 datasource 類型以 connector 做區分,並需要安裝對應的 loopback-connector-* 套件。
  • component-config.json: Loopback 可以額外安裝不同的 plugin(稱為 Loopback component),而 Loopback 會用這個檔案來設定 component,例如 Swagger UI 使用的 loopback-component-explorer
  • model-config.json: 這裡需要設定的是所有在 src/common/models 定義的 model 資料所對應的 datasource,也可以用 public 設定是否要為這些 model 開放 RESTful API。

Bootstrapping Scripts

loopback-boot 套件會讀取使用者指定的路徑,將裡面所有的 bootstrapping scripts 依照檔案名稱順序全部執行一次。常用的 bootstrapping script 包括:

  1. 讀取 roles 設定
  2. 替這個 API Server 建立一個 default 的 admin 使用者
  3. 進行 database migration

Model Definition

Loopback 最棒的價值在於直接定義好 model 就能自動生成 RESTful API endpoints 和 database schema。 這些 model definition 會放在 src/common/models,每個 JSON 檔對應一個 model。

Roles

Roles 是用於 Access Control List (ACL),可以非常精細的控制不同的 API 的存取權限。

Remote Methods

除了 Loopback 預設生成的 RESTful API,我們當然能自行宣告客製化的 API 掛載到 model 上,這些客製化的部份稱為 remote method。 宣告 remote method 需要在 src/common/model 宣告 model 的 JSON 檔時,一起宣告一個 .js 的 JavaScript 檔案(例如 Assignment.jsonAssignment.js)。 Loopback 會在 bootstrapping 時期將 Model 類別作為參數傳入 JS 檔 export 出來的 function,讓開發者在 function 內進行 remote method 的宣告。 通常要宣告一個 remote method 有兩個步驟:

1) 定義 method 本體 的 function。 這個 function 的輸入參數是標準的 Node.js callback style,由前面的輸入參數和最後一個 callback 參數構成,所有的回傳值也要以 callback(err, result) 傳回。 在 function 內部就能透過其他的 Model method 來對 datasource 操作,取得想要的結果後再以 callback 回傳。 Method 有分 static methodobject method 兩種,顧名思義就是分別定義於 Model class 和 Model instance 上的 method,兩者可分別用 Model.aMethodModel.prototype.aMethod 進行定義。

2) 呼叫 Model.remoteMethod 並傳入 remote method 的設定值。 在設定裡面可以細部定義這個 API 的細節,包括 API 的 verb、URL path、有哪些輸入參數(要傳給 (1) 定義的 function 用的)、輸入參數的來源(query string、URL path argument、request header/body 等)、response body 的結構定義等。 以下用 user model 為例,在 user instance 上宣告一個改變密碼的 remote method:

module.exports = User => {
    User.prototype.changePassword = function changePassword(newPassword, callback) {
        this.updateAttributeAsync('password', newPassword)
            .then(user => callback(null, { message: 'success' }))
            .catch(err => callback(err));
    };
    User.remoteMethod('changePassword', {
        isStatic: false,
        accepts: [
            { arg: 'newPassword', type: 'string' }
        ],
        returns: {
            arg: 'info', type: 'object', root: true
        },
        http: { path: '/password', verb: 'put' },
        description: 'Change password of a user'
    });
};

用 loopback-component-passport 設定 local login

Loopback 在 loopback-component-passport 套件實作了基於 access token 的登入流程,提供 user、access token 等 model 後便能直接使用:

import { PassportConfigurator } from 'loopback-component-passport';

app.use(loopback.token({
    model: app.models.accessToken
}));
const passportConfigurator = new PassportConfigurator(app);
passportConfigurator.init(true);
passportConfigurator.setupModels({
    userModel: app.models.user,
    userIdentityModel: app.models.userIdentity,
    userCredentialModel: app.models.userCredential
});
passportConfigurator.configureProvider('local', {
    authScheme: 'local',
    provider: 'local',
    module: 'passport-local',
    usernameField: 'username',
    passwordField: 'password',
    authPath: '/auth/local'
});

整合 Swagger UI

Swagger UI 是個功能強大的 API「瀏覽器」。這個介面會將所有 RESTful API 以 Model 為分隔各自列出,並條列每個 API 的細節,最重要的是可以直接在這個 web app 上呼叫這些 API 進行手動測試。 Loopback 使用 loopback-component-explorer 將 Swagger UI 整合到 Loopback 系統內,稱為 Strongloop API Explorer。 在 component-config.json 宣告設定細節:

{
    "loopback-component-explorer": {
        "mountPath": "/explorer",
        "apiInfo": {
            "title": "API explorer",
            "description": "API explorer"
        }
    }
}

以下是 Strongloop API Explorer 的畫面:

Strongloop API Explorer

從 API 測試區域也能看到根據 remote method 的設定而生成的 UI:

remote method

results matching ""

    No results matching ""