這篇是某個晚上試玩 Strapi 這套 headless CMS 的心得,主要是談 Strapi 和 headless CMS 帶來的變革,不太會談到具體的操作過程。
先談談 headless CMS。
Headless CMS
Headless CMS 是前後端分離概念下的產物,headless CMS 可以簡單的理解為剝去前端的 CMS,headless CMS 以 API 的方式(通常是 RESTful API 或 GraphQL) 供應前端內容,前端(通常是 Aurelia、Svelte、Vue、React、Angular)也透過 API 與 headless CMS 溝通,取得內容呈現,或發送內容回 headless CMS。
在上面的前後端分離的架構下,headless CMS 必須具備幾項特性:
- 管理內容的能力,包括內容的欄位、資料型態、欄位關聯性、以及內容本身,以開發的角度講,就是 model 的制定與管理。另外一種內容是媒體管理,圖片、音檔、影片、PDF 等的媒體資產管理。
- 管理資料庫的能力,上面的內容都必須對應到資料庫,以開發的角度講,就是 ORM。
- 管理 API 的能力,上面的內容(model)除了向下對應到資料庫外,向外也要有對應的 API,並且 model、table、API 的連動是自動化的。
- 除了主要的內容外,還必須有權限、身份認證等系統必備的 API。
- 上面的每個特性都是有一個後台界面(Admin Panel)可以讓一般人操作,而不是只能透過程式碼的方式操作。
從上面幾點可以看出 headless CMS 相較於典型的 MCV web 框架(如 Masonite、Laravel),多了幾項特性:
- Model 是可以由用戶在 Admin Panel 自行定義的,不用由開發人員施工。
- Controller 是自動化建構的,只要在 Admin Panel 定義好 model,API 就會自動產生,不用開發人員施工。
在這樣的特性下,配合大前端時代的降臨,大部分的業務邏輯都往前端實做,開發人員的精力完全可以投注在前端工程上,headless CMS 的角色就專注於當個稱職的網站後端或應用後端,是不是很棒?
Strapi
Strapi 是個開源的 headless CMS 系統,底層則是 Node.js 的 web 框架 Koa。
依照 Strapi 的文件把範例建起來之後,在 Strapi Admin Panel 內建了一個 Restaurant 的 model(Strapi 稱為 Content Type):
Strapi 會自動幫我們產生 API 與文件:
而在專案目錄內,Strapi 會自動幫我們配置出 Restaurant 的路由、model 和 API:
my-project/
┣ api/
┃ ┗ restaurant/
┃ ┣ config/
┃ ┃ ┗ routes.json
┃ ┣ controllers/
┃ ┃ ┗ restaurant.js
┃ ┣ documentation/
┃ ┃ ┗ 1.0.0/
┃ ┃ ┣ overrides/
┃ ┃ ┗ restaurant.json
┃ ┣ models/
┃ ┃ ┣ restaurant.js
┃ ┃ ┗ restaurant.settings.json
┃ ┗ services/
┃ ┗ restaurant.js
┣ config/
┃ ┣ functions/
┃ ┃ ┣ responses/
┃ ┃ ┃ ┗ 404.js
┃ ┃ ┣ bootstrap.js
┃ ┃ ┗ cron.js
┃ ┣ database.js
┃ ┗ server.js
┣ extensions/
┃ ┣ documentation/
┃ ┣ email/
┃ ┣ upload/
┃ ┗ users-permissions/
┗ public/
┣ uploads/
┗ robots.txt
可以看到,如果有需要的話,可以再對 controller、model、service 做開發,下面分別看看這些原始碼的內容與架構。
Routing
{
"routes": [
{
"method": "GET",
"path": "/restaurants",
"handler": "restaurant.find",
"config": {
"policies": []
}
},
{
"method": "GET",
"path": "/restaurants/count",
"handler": "restaurant.count",
"config": {
"policies": []
}
},
{
"method": "GET",
"path": "/restaurants/:id",
"handler": "restaurant.findOne",
"config": {
"policies": []
}
},
{
"method": "POST",
"path": "/restaurants",
"handler": "restaurant.create",
"config": {
"policies": []
}
},
{
"method": "PUT",
"path": "/restaurants/:id",
"handler": "restaurant.update",
"config": {
"policies": []
}
},
{
"method": "DELETE",
"path": "/restaurants/:id",
"handler": "restaurant.delete",
"config": {
"policies": []
}
}
]
}
Model
欄位定義在 api/models/restaurant.settings.json:
{
"kind": "collectionType",
"collectionName": "restaurants",
"info": {
"name": "restaurant",
"description": ""
},
"options": {
"increments": true,
"timestamps": true,
"draftAndPublish": true
},
"attributes": {
"name": {
"type": "string",
"required": true,
"unique": true
},
"description": {
"type": "richtext"
},
"BGM": {
"collection": "file",
"via": "related",
"allowedTypes": [
"images",
"files",
"videos"
],
"plugin": "upload",
"required": false
}
}
}
在 Admin Panel 定義的 model(Content Type)以及欄位都會有相對的 JSON 定義檔產生,這樣的好處是可以讓欄位定義檔本身也被 Git 管理,這也才有辦法讓其他的程式邏輯(如 controller)和 model 一同接受版控的管理。
另外一個是 model 的程式邏輯,在 api/restaurant/models/restaurant.js:
'use strict';
/**
* Read the documentation (https://strapi.io/documentation/developer-docs/latest/concepts/models.html#lifecycle-hooks)
* to customize this model
*/
module.exports = {};
內容相當簡單,只有一段引導我們去看 model 開發文件的註解。
後面的 controller、service 也都是類似的內容。
Controller
檔案在 api/controllers/restaurant.js:
'use strict';
/**
* Read the documentation (https://strapi.io/documentation/developer-docs/latest/concepts/controllers.html#core-controllers)
* to customize this controller
*/
module.exports = {};
Service
檔案在 api/services/restaurant.js:
'use strict';
/**
* Read the documentation (https://strapi.io/documentation/developer-docs/latest/concepts/services.html#core-services)
* to customize this service
*/
module.exports = {};
Strapi 的擴充機制
實際在 Strapi Admin Panel 定義好 Restaurant 以及看過專案目錄內的檔案後,可以歸納一下 Strapi 的設計及它的擴充機制,前面提過,在商業邏輯往前端移動的大前端時代的背景下,像 Strapi 這樣傻瓜型的 headless CMS 可以很快速讓我們定義出 model 的欄位以及產出相對應的 API 及文件,但因為 Strapi 依然是基於傳統的 web 框架 Koa,它還是保留了所有後端開發的架構,這樣的設計兼顧了速度與彈性。
在 Admin Panel 方面,除了 model 的定義與內容的管理外,看起來略顯陽春,但根據 Straip 的文件,Admin Panel 也是可以被客製的,另外 Strapi本身也有設計 plugin 的機制,包括 Strapi 自己的 GraphQL 也是以一支獨立的 plugin 的方式被使用。
總結
歸納一下 Strapi 的特點:
- 有 Admin Panel 用於定義資料與管理資料。
- 定義的資料會自動產出 API 與 API 文件給前端使用。
- 在 Admin Panel 定義的資料型態都會以 JSON 的格式儲存,因此可以被版控系統管理。
- 還是可以自行做後端開發與客製。
- 開源,可以自架,資料庫也放在自己家。
好處很明顯,API 的制定變得簡單又快速,time to market 時間可以省掉一半(寫後端的那一半)。
同場加映幾個也頗具特色的 headless CMS 及其它相關專案:
- Slicknode:headless CMS「服務」,無開源,資料放在 Slicknode 家,特色是跑在 AWS serverless 平台上,感覺比 Strapi 能應付更大的存取需求。
- Directus:和 Strapi 特色類似,也是開源專案,目前底層是 PHP 和 Zend,下一版 Directus 9 會改用 Node.js。
- FastAPI:把 headless CMS 的前台界面(如 Strapi 的 Admin Panel)再剝離的 web 框架,FastAPI 顧名思義是專門為 API 設計的框架,在程式碼內定義好 route、model、function 後 FastAPI 就會自動產出 API 文件,FastAPI 還有其它專為 API 設計的特性,可以訪問 FastAPI 網站了解。
補充
Strapi 有提供 rich text 型態的欄位,它在編輯區是以 Markdown 的方式做編輯,如下圖:
不過大家都知道 Markdown 本身的格式是受限的,例如不能指定 id
、class
,也不能改文字顏色,雖然 Markdown 允許在內文中直接插入 HTML,不過這樣就失去了這個 Admin Panel 存在的重要特性之一:讓非開發人員可以在此管理內容,殘念です。
Top comments (0)