フロントエンジニアにおくるstrapiことはじめ[2019/12版]

## Strapi
[strapi](https://strapi.io/)はNode.js製のオープンソースHeadlessCMSです。3.0.0-alphaからbetaになったことで、導入手順などが変わったようなので、現時点での最新版の導入方法のメモになります。

[公式のクイックスタートガイド](https://strapi.io/documentation/3.0.0-beta.x/getting-started/quick-start.html)

## 下準備
- Node.js
- データベース（文中ではPostgresQL）

ちなみに下記環境で書いています。
- macOS Catalina 10.15.1
- Chrome バージョン: 79.0.3945.79

strapi公式の求める3.0.0-beta時点での各種バージョン

```
# Node.js
Node.js >= 10.x
NPM >= 6.x

# Database
MongoDB >= 3.6
MySQL >= 5.6
MariaDB >= 10.1
PostgreSQL >= 10
SQLite >= 3
```
https://strapi.io/documentation/3.0.0-beta.x/getting-started/install-requirements.html

### （おまけ）docker-composeで環境を用意する記事を書きました

[Docker composeでstrapi+PostgreSQL開発環境を作る
](https://qiita.com/teixan/items/037ba91e37b936ed378a)

このチュートリアルと合わせて読んで頂く場合、ホストやURL辺りは少し読み替えていただく必要があります。が、手っ取り早いのでおすすめ。このチュートリアルやった直後に捨てられます！（要らなくなったコンテナやイメージの捨て方はおググりくださいませ…）

### Node.js

ローカルマシンのグローバルにNode.jsをインストールされる場合は、[nodenv, nodebrewなどでバージョン管理](https://qiita.com/teixan/items/1005767b2ed665d81e44)推奨です。
僕は最近管理が億劫になってきたので、[Dockerでローカル開発環境作って](https://qiita.com/teixan/items/73e7d631453776184160)ます。インストール済みNode.jsを使ってローカルで初める方が多いですかね。

今回は13.2.0の環境を用意してみました。

```
# node -v
v13.2.0
```

### DB
DBこそMacにインストールして、というのはなにかと面倒になりがちなので、Dockerで開発環境を作ることをおすすめします。

こちらでとてもシンプルなPostgreSQLをDockerで立ち上げる方法を紹介してくださってます。
[公式Dockerイメージ PostgreSQL メモ - Qiita](https://qiita.com/dyoshikawa/items/c3c4269e02433551278b)

僕もだいたいこの流れでPostgresのDockerを立ち上げています。

後述しますがこのようなDBは必須ではなく、お試しするだけの場合はquickstartで用意されるSQLiteでもよいです。僕は以前にすごく後悔したので、このチュートリアルではPostgresを使う流れで進めます。

```
# psql --version
psql (PostgreSQL) 10.11
```

## strapiのapp作成

strapiのドキュメントでは`yarn`推しですが、`npm`(npx)でも問題ないようです。

Dockerの場合はコンテナの中の任意のディレクトリで、ローカルではプロジェクトを管理しやすい場所で、下記を実行。`app名`のディレクトリが作成され、自動的にセットアップされます。

```
npx create-strapi-app <app名>
```

今回は[自作Google拡張「still-useful」](https://qiita.com/teixan/items/7a050e227a163dd2fc21)のためのバックエンドを構築する想定なので以下のようにしました。

```
npx create-strapi-app still-useful
```

実行すると対話型で必要事項を入力していくようになります。前述のようにDockerなどでローカルにDBを立ち上げた場合はこのような感じになるかと。（両方をDockerにした場合は、Host設定に注意）

```terminal
$ npx create-strapi-app still-useful
npx: 85個のパッケージを11.033秒でインストールしました。
Creating a new Strapi application at /Users/teixan/htdocs/still-useful/still-useful.

? Choose your installation type Custom (manual settings)
? Choose your default database client postgres
? Database name: postgres
? Host: 127.0.0.1
? Port: 5432
? Username: postgres
? Password: ******
? Enable SSL connection: No
```

数分で準備が完了します。以下ログ。

```terminal
Creating a project with custom database options.
Creating files.
Dependencies installed successfully.Your application was created at /Users/teixan/htdocs/still-useful/still-useful.
Available commands in your project:

  yarn develop
  Start Strapi in watch mode.

  yarn start
  Start Strapi without watch mode.

  yarn build
  Build Strapi admin panel.

  yarn strapi
  Display all available commands.

You can start by doing:

  cd /Users/teixan/htdocs/still-useful/still-useful
  yarn develop
```

### （余談）なぜ`--quickstart`を使わないのか

strapiには`--quickstart`というファーストステップ用の素晴らしいオプションが用意されています。

```quickstartの例
npx create-strapi-app <app名> --quickstart
```

何も設定の必要がなく、コマンドを実行するだけで管理画面を開くところまでやってくれます。初めて触る際にはとてもおすすめです。
`quickstart`はデータベースに`SQLite`を用いており、お手軽で別途DBを用意する必要がないのがお手軽でよいです。しかし、このappはHerokuにて運用する予定で、HerokuではSQLiteのデータ永続化が出来ないようです。なので、Postgresを使うためにquickstartは使いません。

[SQLite on Heroku \| Heroku Dev Center](https://devcenter.heroku.com/articles/sqlite3#disk-backed-storage)

`create-strapi-app`のこのステップでpostgresを選ぶ（quickstartでは省略される）

```
? Choose your default database client
```


## 起動

前述の`create-strapi-app`の最後にこうあるので、

```
〜略〜
You can start by doing:

  cd /Users/teixan/htdocs/still-useful/still-useful
  yarn develop
```
導入したフォルダに移動して、`yarn develop`（もしくは`npx strapi develop`（もしくは`npm run strapi develop`））してみましょう。

```
$ npx strapi develop

> test-app@0.1.0 strapi /Users/teixan/htdocs/test-postgres/test-app
> strapi "develop"


 Project information                                                          

┌────────────────────┬──────────────────────────────────────────────────┐
│ Time               │ Fri Dec 13 2019 18:32:41 GMT+0900 (GMT+09:00)    │
│ Launched in        │ 5909 ms                                          │
│ Environment        │ development                                      │
│ Process PID        │ 7799                                             │
│ Version            │ 3.0.0-beta.17.8 (node v10.16.3)                  │
└────────────────────┴──────────────────────────────────────────────────┘

 Actions available                                                            

Welcome back!
To manage your project 🚀, go to the administration panel at:
http://localhost:1337/admin

To access the server ⚡️, go to:
http://localhost:1337

```
（もしかしたら初回はちょっと表示内容が違ったかもしれません。）
**導入手順としては終わりです。もうコマンド実行などの手順は、コミットやデプロイまでありません。**

管理画面（[http://localhost:1337/admin](http://localhost:1337/admin)）のURLが案内されています。アクセスしてみると、管理者登録フォームが表示されます。管理者を作成してログインしましょう。
![register.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/13712ef4-e728-da61-84bf-b18fe81bf115.jpeg)

以降は同じURLでログインフォームが表示されるようになります。

![login.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/b104a3fa-b1de-252f-9a53-c9351de5dda0.jpeg)

## 「コンテンツタイプ」を作成する

コンテンツタイプとは、**どのような入出力項目を持った入れ物を作っておくか**という感じで、WPで言うところの`カスタム投稿タイプ`、PHPのフレームワークで言うところの`Model(+Controller)`的なものです。一般的なブログに、[タイトル][本文][カテゴリ]と入力するようになっているのは、そういう入れ物があるからです。

Strapiでは管理画面上で新規作成や管理が可能ですが、**本番環境（`Production`）では、コンテンツタイプを作成することができません。**
なので、ローカル（`Development`）で予め作成->デプロイが必要です。

### サイドナビ[コンテンツタイプ作成] - [コンテンツタイプを追加]

![add-content-type-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/140093d2-2316-ec54-5de4-b52392bbc407.jpeg)

この後はフィールドを追加していきますが、設計などに不慣れな方はとりあえず[String] - 名前に[Title]など入力し、[Done]でいいです。

### 忘れがちな[保存]
![save-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/b967d696-e5b2-d201-6efd-8a1b08cf0d3a.jpeg)

忘れないで！

## アクセス権限の設定
###サイドナビ[ロールと権限] - [Public]

今作ったコンテンツタイプに対して、どのようなアクセスを許可するかを設定します。
少しわかりにくいですが、今回は外からの（Publicな）アクセスを許可しておく（誰でもAPIにアクセスできるようにしておく）必要があるので、[ロールと権限] - [Public]をクリック。
![role-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/7aa77c40-c846-ce8f-fd23-70fc86cfeb4d.jpeg)

そうすると、下部の権限の枠に先程作ったコンテントタイプが表示されているかと思います。僕は今回は`find, create, update`などをオンにしました。

![role-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/e4e4ae4f-f3d3-091c-7f25-6086b71bb824.jpeg)

保存を忘れずに。

## サンプルデータを入力してみる

サイドナビ上の、作ったコンテントタイプをクリック

一覧部分に「〜〜はありません」と表示されていると思います。
[〜〜を追加]をクリック

![post-sample_01-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/587da1cd-2b72-f209-faed-5199fb5ef5da.jpeg)

先程作ったコンテントタイプのフィールドが表示されています。
適当にサンプルデータを入力しておきます。
[保存]をクリック
![post-sample_02-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/be2932ee-44ef-9b99-9702-16bceb284354.jpeg)

前画面に戻り、今入力したものが表示されています。
![post-sample_03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/5e2b22b7-1674-4c5b-5fb7-fff5153286ab.jpeg)

コンテンツの準備が完了。

## アクセスを試してみる

権限の設定時にお気づきかもしれませんが、`find`, `create`などの各アクションの項目をクリックした際に右下にメソッド（`GET`, `POST`など）とルート（URL）が表示されています。歯車アイコンをクリックすることでも確認できます。

### GET
例えば、この例ではコンテンツタイプ`posts`に対して`find`を実行するルートが、`GET`で`/posts`だと表示されています。（このサンプルのコンテントタイプが`posts`で`POST`と混同しやすく恐縮です…）
![url.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/426d2099-c7c9-45c3-8cfe-d169cc7df530.jpeg)

パブリック設定でGETなのでそのままブラウザで実行して確認できます。
今回はベースのURLが`http://localhost:1337/`なので、`http://localhost:1337/posts`になります。

[http://localhost:1337/posts](http://localhost:1337/posts)にブラウザでアクセス
![access.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/94c080b5-b6bc-614e-4c8d-8263072bc9b7.jpeg)

先程入力したデータ（+日付）のデータが表示されました。
Chrome拡張である[JSONView](https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc?hl=ja)などをインストールしておくとこのように整えて表示してくれるのでおすすめです。

コンテンツをこの管理画面上でしか入力せず、APIとしては`GETリクエスト`しか扱わない場合はこれでバッチリです。個別のエントリーを取得する場合は末尾に`id`をつけたりすることになりますが、デフォルトで用意されているものに関しては下記リファレンスを読めばだいたい分かるようになっています。

[API Endpoints | Strapi Documentation](https://strapi.io/documentation/3.0.0-beta.x/content-api/api-endpoints.html#endpoints)

### PUTやPOST

フロントエンドに依存しますので、具体的な手法は省きますが、確認だけはしておきましょう。
バックエンド構築時の確認などには[Postman](https://www.getpostman.com/)というAppが便利です。

[Postman \| The Collaboration Platform for API Development](https://www.getpostman.com/)

少しUIの情報量が多くややこしいかもしれませんが、左上[New]から[Request]作成。


![postman.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/35355881-063e-caf9-d6bb-cdd8eac49806.jpeg)

[メソッド]（`GET` or `POST` or etc）、[URL]を入力。
`GET`ならそのまま[Send]で結果が表示されます。（先程のブラウザでの確認と同様です。）

今回は`POST`を試してみますので、リクエストの内容が必要になります。

[メソッド]部分を`POST`に、URLは`http://localhost:1337/posts`でした。
あとは[Header]と[Body]があればリクエストできます。

[Headerタブ]にてこちらをセット。

| Key | Value |
|:-:|:-:|
| Content-Type | application/json  |

[Bodyタブ]では、[raw]を選択。作成したコンテントタイプのフィールドに合わせて。

```
{
    "title": "Yahoo",
    "url": "www.yahoo.com",
    "score": 888
}
```
[Send]をクリックで結果が表示されます。

うまく行かない場合は、権限の設定が間違っているか、[Header]の記述のミスなどが考えられますが、レスポンスの内容を確認すれば手がかりはあると思います。

```json:権限の設定が間違っていて、403エラーとなっている例
{
    "statusCode": 403,
    "error": "Forbidden",
    "message": "Forbidden"
}
```

うまく行っていれば、先程の管理画面上の一覧にも新しいエントリーが表示されます。

Postmanで開発を進めていくなら、Collectionなども活用し効率的に検証できるようにしておくととてもはかどります。ちなみに大きな開発で使う場合は有料となりますので、ご注意ください。
[Postman \| Plans & Pricing](https://www.getpostman.com/pricing)

## 完成

自前のAPIにデータを登録したり、そのデータを動的に読み出すことが出来るようになりました。

## まとめ

さて、これで**自分の定義した、コンテンツを格納でき / 読み出せるAPI**が用意できました。これをインターネット上でアクセス出来るようにすれば、はれてオリジナルのAPIの公開が出来るわけです。

なぜフロントエンドエンジニアを対象にしたかというと、Node.js製のフロントエンドフレームワークを使えるのに（もしくは勉強中なのに）、バックエンドを作ることが出来ないがゆえに、「サービス」のイメージを出来ないままチュートリアルノマドしているフロントエンドエンジニアが多いのでは？と思った次第です。

もちろん、数多くのチュートリアルを完結したくさんの専門書を読了し、**優れたコードで優れたUXを提供できるようになることはめちゃくちゃ重要**で、それがフロントエンドエンジニアの本分であるということには、大賛成です。道をはずれてもらいたいわけではなく、少し幅を広げてもらいたいなぁと。

現場にいればフロントエンドエンジニアにはAPIの仕様書や既存のガッチガチに固まったJSONデータのリストなどがどこからともなく降ってくることもしばしばだと思いますが、それだけだとまぁ面白くないじゃないですか。とりあえずこんな感じで最低限のバックエンドは簡単につくれますし、Node.js製なのでカスタマイズも出来ます。「エンドポイントってこんな感じで作られてたんか〜」って思っていただくくらいでもいいかとは思うんですが、これをカスタマイズできればサービス・アプリを構築できることを覚えておいてもらえたらなぁという想いです。

以前作った[Chrome拡張もstrapiで簡単なバックエンドを構築しています](https://qiita.com/teixan/items/7a050e227a163dd2fc21)が、これにユーザー登録機能を実装して、マイページ作ったりしたらサービスになりそうじゃないですか？「デザインと仕様書から画面作る係」でいるのがそろそろ退屈だなぁって感じている方はこういう辺りを深めてもらって新しい世界に進んでもらえたらなぁと思います。

ところでフロントエンドエンジニア略してフロントエンジニアってことでいいんですかね？