Strapiでさくっとバックエンドをつくってみた

プログラミング

ヘッドレスCMSのStrapiをつかって、お手軽にバックエンドをつくってみました。

Strapi - Open source Node.js Headless CMS 🚀
Strapi is the next-gen headless CMS, open-source, javascript, enabling content-rich experiences to be created, managed and exposed to any digital device.

Strapiで制作したサイト「バスずかん」を公開しています。

バスずかん
バスの写真をたくさん掲載!仙台を中心としたバスの図鑑です!

フロントエンドにはNuxt.jsを採用し、静的サイトジェネレーター(SSG)モードで完全静的サイトとして公開しています。ぜひご覧ください!

スポンサーリンク

strapiとは?

StrapiはヘッドレスCMSのひとつです。

ヘッドレスCMSとは、フロントエンドを持たないCMS(コンテンツ管理システム)のことです。WordPressと同じように管理UIも有していますが、HTMLを返す代わりにJSONでデータを返してくれます。

WordPressとは異なり、別途フロントエンドも用意しなければなりませんが、その分柔軟性が増すというメリットがあります。

また、最近では、Nuxt.jsやReactなど、優秀なフロントエンドフレームワークがたくさん開発されています。これらのフレームワークを使うと、非常に効率よく開発をすすめることができます。昨今のWeb業界では、フロントエンドとバックエンドを分けて開発することが主流となっており、バックエンドをかんたんに開発する手法としてヘッドレスCMSが注目されているのです。

スポンサーリンク

npmでインストール!

インストールはnpmで行うことができます。

npx create-strapi-app my-project --quickstart

インストール完了後、管理者アカウントの作成ページが表示されるので、指示に従ってパスワードを設定します。

メールアドレスのチェックは行われないので、メールアドレスと氏名については適当でOKです。

とくにトラブルなく構築することができました!

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

まずはコンテンツタイプを作成しましょう。

コンテンツタイプとは、データベースでいうところのテーブルにあたるものです。どんなフィールド(カラム)を用意するのか、あらかじめ設定しておきます。

DIsplay nameにコンテンツの名前を入力します。データベースでいうところのテーブル名に該当するものです。ブログサイトであれば、postsなどを指定することになりますね。APIにアクセスする場合もこの名前を使用します。

つづけて、フィールドの追加を行います。

いろんなタイプを指定できるようになっています。

タイトルなど短めの文字列であればText、ブログ本文などエディタを使って編集したい場合はRich Textを選択します。

Relationをつかうと、ほかのコンテンツタイプ(モデル)を参照することもできます。

いくつか作成してみます。

3つほどフィールドを作成してみました。

最後に忘れずに保存します。

Saveをクリックすると、strapiがリスタートし、コンテンツタイプが作成されます。

無事作成できたようです。

なお、これらの設定はstrapiのディレクトリにあるapiディレクトリにJSONファイルとして保存されています。jsonファイルを直接編集しても設定することができます。

コンテンツを作成する

それではコンテンツを作成してみます。

Strapiではコンテンツの作成もGUIで行うことができます。WordPressのように手軽に利用できますし、開発者側としても自前で管理UIを作成しなくて良いので、大変便利です。

コンテンツのページに飛び、追加ボタンをクリックします。

すると、コンテンツ作成ページに移ります。

Rich Textフィールドについては、エディタを使用することができます。WordPressのようなデザインで、かんたんに操作できますね。

Mediaタイプのフィールドについては、ファイルアップローダーを利用することができます。

画像ファイルがアップロードされた場合は、自動的にリサイズ版も作成されます。ブログサイトなどでは、記事一覧ページのサムネイルなどのため、小さい画像も必要な場合がありますが、Strapiを使えばそれらの生成も自動的に行なってくれます。EXIFなどのメタデータも自動的に削除してくれるようです。

最後に保存をクリックします。

これで下書き保存されました。

となりにあるPublishをクリックすると、公開になります。Publishもクリックしましょう。

保存するだけでは公開はされません。

Publishをクリックし、このあと行うアクセス権の設定を済ますと、APIから取得できるようになります。

これでコンテンツが作成され、公開されました。

コンテンツの名前は適当に「asdfs」としてしまいましたが、このまま行くことにしましょう(^^;)本当はPostsとかにするべきでしたね。

アクセス権を設定する

ここまででデータを作成することはできています。

しかし、まだAPIから取得することはできません。APIからデータを取得するには、アクセス許可を設定しておく必要があります。

ログイン無しでAPIへアクセスする場合は、Publicロールが適用されます。Publicロールにアクセス許可を設定します。

「設定」>「ロールと権限」をクリックします。

Publicの編集マークをクリック。

すると、権限の設定ページが表示されます。

「権限」パネルに権限のリストがありますので、

  • count
  • find
  • findone

を許可しておきましょう。

選択できる権限については、以下のようになっています。

  • count
    /モデルの複数形(postsなど)/countにアクセスすると、件数を取得できます。
  • findone
    /モデルの複数形(postsなど)/idにアクセスすると、IDを指定してコンテンツを取得できます。
  • find
    /モデルの複数形(postsなど)で全件取得できます。
  • createdeleteupdate
    コンテンツの作成・削除・アップロードを許可します。

通常はcount,findone,findの3つを有効にしておけばいいでしょう。

終わったら保存をクリックします。

APIで投稿を取得してみる

それではstrapiのAPIをつかって、投稿を取得してみましょう。

コンテンツを取得するには、GETメソッドで次のようにアクセスします。

http://127.0.0.1:ポート番号/asdfses

ホスト名につづいて、取得したいモデルの複数形をつづけます。現在はモデル名をasdfsにしていたので、その複数形のasdfsesを指定すれば、コンテンツを取得できます。名前がPostなら、postsで取得できます。

ポート番号はstrapi起動時のシェルに表示されています。

Postmanを使って、APIへリクエストを投げてみましょう。Postmanがない方はブラウザで直接アクセスしてもかまいません。

取得できました!

JSON全体は次のようになっていました。

[
    {
        "id": 1,
        "hoge": "タイトル",
        "blog": "本文です。",
        "published_at": "2021-09-11T11:50:07.320Z",
        "created_at": "2021-09-11T11:37:15.896Z",
        "updated_at": "2021-09-11T11:50:07.353Z",
        "picture": [
            {
                "id": 2,
                "name": "SAMPLE-sm.jpg",
                "alternativeText": "",
                "caption": "",
                "width": 1024,
                "height": 683,
                "formats": {
                    "thumbnail": {
                        "name": "thumbnail_SAMPLE-sm.jpg",
                        "hash": "thumbnail_SAMPLE_sm_a409713b7d",
                        "ext": ".jpg",
                        "mime": "image/jpeg",
                        "width": 234,
                        "height": 156,
                        "size": 9.59,
                        "path": null,
                        "url": "/uploads/thumbnail_SAMPLE_sm_a409713b7d.jpg"
                    },
                    "large": {
                        "name": "large_SAMPLE-sm.jpg",
                        "hash": "large_SAMPLE_sm_a409713b7d",
                        "ext": ".jpg",
                        "mime": "image/jpeg",
                        "width": 1000,
                        "height": 667,
                        "size": 129.31,
                        "path": null,
                        "url": "/uploads/large_SAMPLE_sm_a409713b7d.jpg"
                    },
                    "medium": {
                        "name": "medium_SAMPLE-sm.jpg",
                        "hash": "medium_SAMPLE_sm_a409713b7d",
                        "ext": ".jpg",
                        "mime": "image/jpeg",
                        "width": 750,
                        "height": 500,
                        "size": 78.26,
                        "path": null,
                        "url": "/uploads/medium_SAMPLE_sm_a409713b7d.jpg"
                    },
                    "small": {
                        "name": "small_SAMPLE-sm.jpg",
                        "hash": "small_SAMPLE_sm_a409713b7d",
                        "ext": ".jpg",
                        "mime": "image/jpeg",
                        "width": 500,
                        "height": 333,
                        "size": 36.48,
                        "path": null,
                        "url": "/uploads/small_SAMPLE_sm_a409713b7d.jpg"
                    }
                },
                "hash": "SAMPLE_sm_a409713b7d",
                "ext": ".jpg",
                "mime": "image/jpeg",
                "size": 131.9,
                "url": "/uploads/SAMPLE_sm_a409713b7d.jpg",
                "previewUrl": null,
                "provider": "local",
                "provider_metadata": null,
                "created_at": "2021-09-11T11:35:09.055Z",
                "updated_at": "2021-09-11T11:35:09.079Z"
            }
        ]
    }
]

きちんとデータが取得できていますね。

mediaフィールド(今回はpictureという名前にしました)を確認すると、ちゃんとリサイズ版も生成されていることがわかります。

表示されているURLをAPIにリクエストすると、ファイルも取得することができます。

なかなか便利ですね!Laravelで実装するなら、ファイルの保存やリサイズのロジックまで組まなければならないわけですが、それらをすべて割愛することができます。かなりの負担軽減です!

あとはVue.jsやNuxt.js、ReactなどのフロントエンドからAPIを利用してやれば、あっというまにサイトを作成することができます。

npmコマンドで操作できる

strapiはnpmコマンドからほとんどの操作を行うことができます。

起動するには、コンソール(WindowsならPowerShell)でstrapiのディレクトリを開き、

npm run strapi dev

を実行すればOKです。

Shiftを押しながら、strapiのフォルダを右クリックし、「PowerShellで開く」をクリックし、さきほどのコマンドを入力します。

起動が完了すると、管理ページとAPIのURLがシェルに表示されます。

シェルでCtrl+Cを押せば、終了することができます。

本番環境ではnpm run strapiと入力し、実行します。この場合は、プラグインのインストールや重要な設定の変更などはできなくなります。

予想以上にかんたん!UIは要改良!

昨今流行りのHeadlessCMS

今回はじめて使ってみましたが、予想以上にかんたんで驚きました。

当記事ではWebUIを使用した方法を紹介しましたが、ソースコードを書き換えて、機能拡張を行うこともできます。

ソースはMVCモデルに基づいた設計になっているため、カスタマイズ性も良好です。WordPres開発だと独自の関数をたくさん覚えなければなりませんが、Strapiではそういったこともなく、独自のルーティングやコントローラーをかんたんに追加することができます。

デメリットを挙げるとすると、UIの弱さでしょうか。せっかくコンテンツページにチェックボックスがあるのに、一括編集に対応していなかったり、リレーションフィールドのサジェスト機能が不安定だったりと、まだまだ改善の余地はあるのかなあと思います。エディタも基本的なタグしか対応していないうえ、リアルタイムプレビューにも対応していないため、WordPressに比べると使い勝手はよくありませんでした。

とはいえ、静的Webサイトにニュースリリースを追加したい場合や、基本のプロジェクトにちょっとした投稿機能を追加したいようなニーズであれば、Strapiで十分そうです。

今後の開発に乞うご期待です!

コメント

タイトルとURLをコピーしました