strapiのGETで関連テーブルのデータ取得を制御する方法

こんにちは。株式会社dottの山上です。
Strapi Advent Calenderの11日目の本日は、strapiのGETメソッドでのリレーションしているテーブルのデータの取得方法について書いて行きたいと思います。

Strapi Advent Calenderのその他の記事は[こちら](https://qiita.com/advent-calendar/2020/strapi)

# デフォルトの挙動

テスト用に、Contents type builderで以下のようなモデルを作成します。

```
baseModel: emailを持っていて、relationalModelに1:1のリレーションが張られている
relationalModel: name, summaryを持っていて、baseModelに1:1のリレーションが張られている
```

この状態でbaseModelをGETすると、デフォルトではrelationalModelのデータは自動で展開された状態でGETされます。

こんな感じでリクエストすると、

```shell
curl --location --request GET 'http://localhost:1337/base-models' \
--header 'Authorization: Bearer {token}'
```

レスポンスはこんな感じで帰ってきます。

```json
[
    {
        "id": 1,
        "email": "test@example.com",
        "relational_model": {
            "id": 1,
            "summary": "関連テーブルのデータです",
            "name": "テストさん",
            "base_model": 1,
            "created_by": 1,
            "updated_by": 1,
            "created_at": "2020-12-10T07:44:21.424Z",
            "updated_at": "2020-12-10T07:44:36.100Z"
        },
        "created_by": {
            "id": 1,
            "firstname": "user",
            "lastname": "test",
            "username": null
        },
        "updated_by": {
            "id": 1,
            "firstname": "user",
            "lastname": "test",
            "username": null
        },
        "created_at": "2020-12-10T07:44:36.093Z",
        "updated_at": "2020-12-10T07:44:36.111Z"
    }
]
```

# settings.jsonから設定する
常に同じ項目に対して同じ制御になるのであれば、`/api/{model-name}/models/{model-name}.settings.json`を手動で編集することで、データ取得の制御が可能です。

## 1. privateをtrueに設定する
`relational_model`の、privateをtrueに設定します。

```json:/api/base-model/models/base-model.settings.json
{
  "kind": "collectionType",
  "collectionName": "base_models",
  "info": {
    "name": "baseModel"
  },
  "options": {
    "increments": true,
    "timestamps": true
  },
  "attributes": {
    "email": {
      "type": "email"
    },
    "relational_model": {
      "model": "relational-model",
      "via": "base_model",
      "private": true
    }
  }
}
```

その場合は、以下のように、`relational_model`と言う項目そのものが返却されません。

```json
[
    {
        "id": 1,
        "email": "test@example.com",
        "created_by": {
            "id": 1,
            "firstname": "user",
            "lastname": "test",
            "username": null
        },
        "updated_by": {
            "id": 1,
            "firstname": "user",
            "lastname": "test",
            "username": null
        },
        "created_at": "2020-12-10T07:44:36.093Z",
        "updated_at": "2020-12-10T07:44:36.111Z"
    }
]
```

## 2.autoPopulateをfalseに設定する
`relational_model`の、autoPopulateをfalseに設定します。

```json:/api/base-model/models/base-model.settings.json
{
  "kind": "collectionType",
  "collectionName": "base_models",
  "info": {
    "name": "baseModel"
  },
  "options": {
    "increments": true,
    "timestamps": true
  },
  "attributes": {
    "email": {
      "type": "email"
    },
    "relational_model": {
      "model": "relational-model",
      "via": "base_model",
      "autoPopulate": false
    }
  }
}
```

こっちの場合は、以下のように、`relational_model`と言う項目そのものは返却されますが、ID以外は返却されません。

```json
[
    {
        "id": 1,
        "email": "test@example.com",
        "relational_model": 1,
        "created_by": {
            "id": 1,
            "firstname": "user",
            "lastname": "test",
            "username": null
        },
        "updated_by": {
            "id": 1,
            "firstname": "user",
            "lastname": "test",
            "username": null
        },
        "created_at": "2020-12-10T07:44:36.093Z",
        "updated_at": "2020-12-10T07:44:36.111Z"
    }
]
```

# jsで制御する
動的に制御したい場合はライフサイクルフックが用意されているので、そちらを利用します。
`/api/{model-name}/models/{model-name}.js`を編集します。

```js:/api/base-model/models/base-model.js
module.exports = {
  lifecycles: {
    async afterFind(results, params, populate) {
      // ユーザーの権限などなんらかの条件で分岐させる
      if ('何かの条件') {
        // relational_modelを削除する場合はこんな感じ
        // この場合はprivate設定と同じ結果になる
        results.map(result => {
          delete result.relational_model;
        })
      }
    }
  }
};
```

# reference
https://strapi.io/documentation/v3.x/concepts/models.html#define-the-attributes
https://strapi.io/documentation/v3.x/concepts/models.html#lifecycle-hooks

# まとめ
- strapiは特に何もしなくてもリレーションしているテーブルのデータを引っ張ってこられる
- もし引っ張って来たくない場合は、private, autoPopulate, ライフサイクルフックなどを利用して制御する

ではまた次回〜。