繼昨天介紹了 API Server 的基本架構後,今天要來簡單介紹 Loopback 為了快速開發而提供的諸多方便功能。
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
。host
和 port
用來傳給 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。loopback-boot
套件會讀取使用者指定的路徑,將裡面所有的 bootstrapping scripts 依照檔案名稱順序全部執行一次。常用的 bootstrapping script 包括:
Loopback 最棒的價值在於直接定義好 model 就能自動生成 RESTful API endpoints 和 database schema。這些 model definition 會放在 src/common/models
,每個 JSON 檔對應一個 model。
Roles 是用於 Access Control List (ACL),可以非常精細的控制不同的 API 的存取權限。
除了 Loopback 預設生成的 RESTful API,我們當然能自行宣告客製化的 API 掛載到 model 上,這些客製化的部份稱為 remote method。宣告 remote method 需要在 src/common/model
宣告 model 的 JSON 檔時,一起宣告一個 .js
的 JavaScript 檔案(例如 Assignment.json
和 Assignment.js
)。Loopback 會在 bootstrapping 時期將 Model 類別作為參數傳入 JS 檔 export 出來的 function,讓開發者在 function 內進行 remote method 的宣告。
通常要宣告一個 remote method 有兩個步驟:
callback
參數構成,所有的回傳值也要以 callback(err, result)
傳回。在 function 內部就能透過其他的 Model method 來對 datasource 操作,取得想要的結果後再以 callback
回傳。Method 有分 static method
和 object method
兩種,顧名思義就是分別定義於 Model class 和 Model instance 上的 method,兩者可分別用 Model.aMethod
和 Model.prototype.aMethod
進行定義。
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 在 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 是個功能強大的 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 的畫面:
從 API 測試區域也能看到根據 remote method 的設定而生成的 UI: