# Strapi基本概念及架構(Strapi介紹-中篇)
<!-- Put the link to this slide here so people can follow -->
來源: https://strapi.io/documentation/3.0.0-beta.x/concepts/concepts.html
[前篇(快速入門)](https://hackmd.io/oXdEw-gBTSGheNsARMJYVg)
[中篇(概念架構介紹)](https://hackmd.io/LqgfRVBXQf-OYFrvdiT7Hw)
[後篇(部署及設定)](https://hackmd.io/-2zeYcrgR52aI-gssI-XFQ)
:cat: 簡單介紹Strapi的概念與架構
---
## 1. Strapi 檔案結構(僅介紹API, config檔案)
### API, config, ...
- **(其他資料夾)
- /api
- **(你的API名稱,ex: restaurant)
- config
- controllers
- models
- services
- /config
- environments
- ...
---
## 2. Strapi 概略運作流程
```flow
st=>start: Request請求
e=>end: Response最終回應!
cond1=>inputoutput: ROUTE(分配)
cond=>condition: have policy?
(有無分配規則?)
sub=>subroutine: Policy(執行規則)
(e.g., isAnthenticated?...)
op=>operation: Controller(控制器)
op2=>operation: Service(執行服務)
st(right)->cond1->cond
cond(no)->op()->op2(right)->e
cond(yes)->sub->op
```
:::info
以 restaurant 資料為例
:::
### Request
(此Request介紹為一般的客戶端請求,非原文檔中的Request)
來自客戶端的請求
發送請求給==Route==端處理
```javascript=
Url: http://localhost:1337/restaurants
Method: GET
//axios 取得所有restaurants的資料
axios({
url: http://localhost:1337/restaurants,
method: 'GET',
})
.then(res => {
console.log(res.response.data);
})
.catch(err => {
console.log('An error occurred:', err.response);
});
```
### Route(包含分配方法及policies)
[原文連結](https://strapi.io/documentation/3.0.0-beta.x/guides/policies.html#how-to-create-a-policy)
取得請求後,依照各API的routes.json檔案去做請求的分配,分配給==controller==處理
- 檔案路徑- `./api/restaurant/config/routes.json`
```json=
{
"routes": [
{
"method": "GET",
"path": "/restaurants",
"handler": "Restaurant.find", //controller的方法
"config": {
"policies": [ //如沒有則不處理policy
"global.isAuthenticated"
]
}
}
]
}
```
### Controller
[原文連結](https://strapi.io/documentation/3.0.0-beta.x/guides/controllers.html)
從Route中的 **handler** 取得的方法來做任務執行(類似redux 的 action),將執行==services==中的方法
- 以下為strapi的原本方法的原始碼
- 檔案路徑(自訂方法會直接覆蓋原有方法)- `./api/restaurant/controllers/Restaurants.js`
`find`
```javascript=
module.exports = {
/**
* Retrieve records.
*
* @return {Array}
*/
//可自訂使用的service方法
find(ctx) {
if (ctx.query._q) {
//將執行product中的service的search方法
return strapi.services.restaurant.search(ctx.query);
}
return strapi.services.restaurant.find(ctx.query);
//也可以不往service,直接丟出資料
//return 'Hi'
},
};
```
### Service
[原文連結](https://strapi.io/documentation/3.0.0-beta.x/guides/services.html)
取得來自controller的方法呼叫,執行對應的service方法
- 檔案路徑(自訂方法會直接覆蓋原有方法)- `./api/restaurant/services/Restaurants.js`
`find`
```javascript=
module.exports = {
/**
* Promise to fetch all records
*
* @return {Promise}
*/
find(params, populate) {
return strapi.query(Restaurant).find(params, populate);
},
};
```
### Response
[原文連結(response原始資料)](https://strapi.io/documentation/3.0.0-beta.x/guides/responses.html#response)
取得service或是controller的資料
e.g., 取得find的資料(API取得的資料)
`find`
```json=
//API拿到的資料
[{"id":1,"restaurant":"Strapi Restaurant","description":"Strapi restaurant is a cosy restaurant delivering one of the very fastest and nicest dining experiences in the world, combining nods to tradition with fierce modernity, warmth with daring.","created_at":"2019-07-31T03:41:56.793Z","updated_at":"2019-07-31T03:44:09.395Z","categories":[{"id":1,"category":"Convenient","created_at":"2019-07-31T03:42:15.241Z","updated_at":"2019-07-31T07:17:32.389Z"},{"id":2,"category":"Time Saving","created_at":"2019-07-31T03:43:25.358Z","updated_at":"2019-07-31T03:43:25.364Z"}]}]
```
---
## 3. Model 資料模型
[原文連結](https://strapi.io/documentation/3.0.0-beta.x/guides/models.html)
簡單來說,就是在[strapi快速入門](https://hackmd.io/oXdEw-gBTSGheNsARMJYVg?view)中,用==新增欄位==功能產生的資料模型
而我們可以直接使用指令或是修改檔案的方式,來直接新增或是修改欄位!
:::info
在新建一個API之後,strapi會自動產生model檔
:::
如果在該API資料夾中無model檔案,可以透過以下CLI指令新建一個
`strapi generate:model restaurant name:string`
### attributes 格式(type)
有以下格式可以使用
`string, text, integer, biginteger, float, decimal, password, date, time, datetime, timestamp, boolean, binary, uuid, enumeration, json, email`
### validations 驗證
有以下驗證可以使用
`required (boolean)`: 是否必須
`unique (boolean)`: 是否唯一
`index(boolean)`: 是否加上索引值(僅適用mongoDB)
`max (integer)`: 最大值(整數)
`min (integer)`: 最小值(整數)
### 以restaurant為例
路徑- `./api/restaurant/models/Restaurant.settings.json`
```json=
{
"connection": "default",
"collectionName": "restaurants",
"info": {
"name": "restaurant", //api名稱
"description": "" //api描述
},
"options": {
"increments": true,
"timestamps": true,
"comment": ""
...
//選項解釋詳見原文
},
"attributes": {
"restaurant": { //restaurant的欄位
"unique": true, //驗證: 唯一
"required": true, //驗證: 必須
"type": "string" //格式: 字串
},
"description": {
"type": "text" //格式: 文字
},
"categories": { //此為多個restaurants對多個categories(多對多)
"collection": "category", //關聯的欄位(多個的集合)
"via": "restaurants" //關聯到自己的欄位(多個)
}
}
}
```
### relations 資料關係
[詳細範例以及controller相關使用方法請看這邊](https://strapi.io/documentation/3.0.0-beta.x/guides/models.html#relations)
- One-way 單向
- One-to-one 一對一
- One-to-many 一對多
- Many-to-many 多對多
#### One-way 單向
資料之間只有單向的連結,例如`pet`的`owner`連結到某位`user`,而`user`不會有相應的`pet`關係
Example:
Path — `./api/pet/models/Pet.settings.json`
```json=
{
"attributes": {
"owner": {
"model": "user"
}
}
}
```
#### One-to-one 一對一
資料之間為一對一的連結關係,例如`user`會有一個`address`,且`address`也會有一個相應的`user`欄位
Example:
Path - `./api/user/models/User.settings.json`
```json=
{
"attributes": {
"address": {
"model": "address", //連結address
"via": "user"
}
}
}
```
Path - `./api/address/models/Address.settings.json`
```json=
{
"attributes": {
"user": {
"model": "user"
}
}
}
```
#### One-to-many 一對多(多對一)
資料之間為一對多(多對一)的連結關係,例如`user`會有很多個`articles`,且`article`也會有相應的`user(article)`欄位
Example:
`user`
Path - `./api/user/models/User.settings.json`
```json=
{
"attributes": {
"articles": {
"collection": "article",
"via": "author"
}
}
}
```
`article`
Path - `./api/article/models/Article.settings.json`
```json=
{
"attributes": {
"author": {
"model": "user"
}
}
}
```
#### Many-to-many 多對多
資料之間為多對多的連結關係,例如`restaurant`會有很多個`categories`,且`category`也會有相應的`restaurant`欄位
Example:
`restaurant`
Path - `./api/user/models/Restaurant.settings.json`
```json=
{
"attributes": {
"categories": {
"collection": "category",
"via": "restaurants"
}
}
}
```
`category`
Path - `./api/article/models/Category.settings.json`
```json=
{
"attributes": {
"restaurants": {
"collection": "restaurant",
"via": "categories",
"dominant": true
}
}
}
```
---
## 4. 常用CLI(Command Line Interface)指令
### `strapi new`
新建一個strapi專案(常用的為--quickstart,即為快速建立專案)
選項:
```javascript
[--debug|--quickstart|--dbclient=<dbclient> --dbhost=<dbhost> --dbport=<dbport> --dbname=<dbname> --dbusername=<dbusername> --dbpassword=<dbpassword> --dbssl=<dbssl> --dbauth=<dbauth> --dbforce]
```
### `strapi develop|dev`
在 `http://localhost:1337` 開啟==開發模式==的strapi頁面
加上 `/admin` 進入儀表板頁面
### `strapi start`
在 `http://localhost:1337` 開啟==產品模式==的strapi頁面
加上 `/admin` 進入儀表板頁面
### `strapi build`
將目前的strapi專案程式打包建構為產品版本
### `strapi generate:<api名稱>`
可以在指令後面直接加上欄位相關的設定
例如 - `strapi generate:restaurant name:string`
會自動建立model, controller ...等相關資料夾
### `strapi install <plugin插件名稱>`
將會安裝指定插件
例如 - `strapi install graphql` 就會安裝graphQL的插件(plugin)
{"metaMigratedAt":"2023-06-14T23:17:06.863Z","metaMigratedFrom":"YAML","title":"Strapi 概念架構介紹","breaks":true,"description":"Strapi brief introduction!","contributors":"[{\"id\":\"b742f78e-a93a-4d14-a695-c7a70118116d\",\"add\":8461,\"del\":6089}]"}