Closed6

HeadlessCMS Strapiキャッチアップ

ピン留めされたアイテム
hirohiro

業務でNext.jsとHeadlessCMSであるstrapiを連携させることになったのでキャッチアップしていく

結論

  1. strapiでコレクション(投稿タイプ)を作成
  2. それをAPIとして公開する
  3. Next.js側でコールしてUI構築

https://strapi.io/features

hirohiro

初期セットアップ

npx create-strapi@latest ${project-name} を実行するだけ。
${project-name}は任意のプロジェクト名。
あとはいつも通りに npm installを実行し依存関係をインストールする。

ローカルサーバー起動

package.jsonを見れば一目瞭然だが、npm run develop でローカルサーバーを起動できる。
以下のようなダッシュボード画面になる。

コレクションの作成

コレクションとは、複数のデータを管理するためのコンテンツタイプのこと。
Wordpressでいうカスタム投稿タイプに近そう。

公式ドキュメントでは「Restaurant」というコレクションを追加して複数のフィールドを追加した。
WordpressのACFみたいな印象を受けた。

  • unique
  • required

などの制約をつけることも可能

リレーションも設定できる!
便利!

デプロイ

npm run strapi deployでデプロイ可能。
調査が甘いかもしれないが、デプロイ先はデフォルトではstrapi cloudになるが、vercel,aws,gcpなどにもデプロイできそう。

今回はstrapi cloudを使用する。

デプロイコマンドを流したあとはURLが発行されるのでそちらにアクセスすることで確認できる。

APIをコールしてみる

今回はUIを構築していないのでcurlでコールしてレスポンスだけ確認してみる。

# 雛形
curl https://プロジェクトURL/api/{コレクション名}

curl https://プロジェクトURL/api/restaurants

レスポンスはJSONで返ってきていた

{
  "data": [
    {
      "id": 2,
      "documentId": "jx5qpxx0obt31bcf7oilii1g",
      "Name": "Biscotte Restaurant",
      "Description": [
        {
          "type": "paragraph",
          "children": [
            {
              "text": "Welcome to Biscotte restaurant! ",
              "type": "text"
            }
          ]
        },
        {
          "type": "paragraph",
          "children": [
            {
              "text": "Restaurant Biscotte offers a cuisine based on fresh, quality products, often local, organic when possible, and always produced by passionate producers.",
              "type": "text"
            }
          ]
        }
      ],
      "createdAt": "2025-03-03T08:25:12.011Z",
      "updatedAt": "2025-03-03T08:32:32.200Z",
      "publishedAt": "2025-03-03T08:32:32.408Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "pageSize": 25,
      "pageCount": 1,
      "total": 1
    }
  }
}

ご覧の通りdatametaが分かれて返ってくるのでとても扱いやすそう

hirohiro

一通り目を通してわかったこと

・デプロイは必須ではない(当たり前)

http://localhost:1337/api/${コレクション名} のようにデータにアクセスすることができるのでローカルでデータを取得可能

・privareフィールドにしていなくてもデフォルトで返ってこないフィールドがある

The REST API by default does not populate any relations, media fields, components, or dynamic zones.
https://docs.strapi.io/dev-docs/api/rest/populate-select#population

直訳すると、REST APIはデフォルトでリレーション、メディアフィールド、コンポーネント、ダイナミックゾーンを返さない、とのこと。
そういった類のフィールドを返したい場合は、populate パラメータをリクエストに付与する必要がある。
詳しくはこちらをみる https://docs.strapi.io/dev-docs/api/rest/populate-select#population

  const response = await fetch("http://localhost:1337/api/posts?populate=*", {
    cache: "no-store",
  });

・Rich text (Block)を表示する方法

プラグインを使用する必要がある
https://github.com/strapi/blocks-react-renderer

型も定義されているので使いやすい

"use client";

import {
  BlocksRenderer,
  type BlocksContent,
} from "@strapi/blocks-react-renderer";

interface Props {
  title: string;
  id: number;
  documentId: string;
  slug: string;
  excerpt: string;
  content: BlocksContent;
}

export default function PostItem({
  title,
  id,
  documentId,
  slug,
  excerpt,
  content,
}: Props) {
  return (
    <div>
      <h1 className="text-4xl font-bold mb-4 text-white">{title}</h1>
      <p>id: {id}</p>
      <p>documentId: {documentId}</p>
      <p>slug: {slug}</p>
      <p>expert: {excerpt}</p>
      <BlocksRenderer content={content} />;
    </div>
  );
}
hirohiro

ページネーション

pagination パラメータを使用することでページネーションを実装(レスポンスを分割)できる

pageによるページネーションの場合

パラメータ 説明 default
pagination[start] int ページ番号 1
pagination[limit] int ページの大きさ(1ページ当たりの件数) 25
pagination[withCount] bool コンテンツの総数とページ数をレスポンスに追加するかどうか true
1ページ目の10件のみを取得する場合

GET /api/articles?pagination[page]=1&pagination[pageSize]=10

{
  "data": [
    // ...
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "pageSize": 10,
      "pageCount": 5,
      "total": 48
    }
  }
}

offsetによるページネーションの場合

パラメータ 説明 default
pagination[page] int 開始値(つまり、返される最初のエントリ) 1
pagination[pageSize] int 返されるエントリの数 25
pagination[withCount] bool エントリの合計数を表示するかどうか true
最初の10件のみを取得する場合

GET /api/articles?pagination[start]=0&pagination[limit]=10

{
  "data": [
    // ...
  ],
  "meta": {
    "pagination": {
      "start": 0,
      "limit": 10,
      "total": 42
    }
  }
}

https://docs.strapi.io/dev-docs/api/rest/sort-pagination#pagination

hirohiro

日本語化

  • src/admin/app.example.tsx を複製し app.tsx にリネーム
  • リネームした app.tsxconfig.locales['ja'] のコメントアウトを外す
    app.tsx
    import type { StrapiApp } from "@strapi/strapi/admin";
    
    export default {
      config: {
        locales: ["ja"],  // これ
      },
      bootstrap(app: StrapiApp) {
        console.log(app);
      },
    };
    
  • 再ビルドして、再起動
    npm run buildnpm run dev
  • ダッシュボード画面の左下にプロフィールがあるのでそこから使用する言語を変更する
このスクラップは19日前にクローズされました