Typescript、NextJS、Strapi、GraphQLによるブログの作り方

はじめに、使う技術スタックを紹介しましょう。Typescriptは「強く型付けされたプログラミング言語で、任意のスケールでのツーリングを向上させるJavaScriptを拡張します」と言えます。簡単に言うと、Typescriptはコーディングの安全性を高め、ウェブにもっと多くのOOPをもたらします。

NextJSは「最新のReact機能を拡張してフルスタックウェブアプリケーションを作成できるフレームワーク」です。簡単に言うと、NextJSは広く使われているReactJSライブラリのアップグレードです。

StrapiはオープンソースのヘッドレスCMSです。CMSは「コンテンツ管理システム」を意味し、プログラミングの知識がなくても、ユーザーフレンドリーなインターフェースでコンテンツを作成・管理・修正・公開することを可能にします。ヘッドレスとは組み込みのエンドユーザーUIがないことを意味し、好きなフロントエンド技術を使えます。

GraphQLは「APIのためのクエリ言語であり、既存のデータでこれらのクエリを満たすためのランタイム」です。簡単に言うと、それはデータを問い合わせ、欲しいフィールドを取得するために使われる言語です。

注意:これは概要であり、スタイリングや最適なHTMLタグなどいくつかの側面には触れません。このブログは上記の技術を使ってブログを作成する機能を紹介するためのものです。

プロジェクトの初期化

早速コマンドラインを使ってフォルダーを作成しましょう(それがクールだからです)。最初のコマンドは、全てのファイルを含むフォルダを作成することです。

mkdir my-personal-website

それでは、NextJSとStrapiのフォルダを作りましょう。

cd my-personal-website
mkdir frontend, strapi

Strapiの初期化

cd strapi
npx create-strapi-app@latest . --ts --quickstart

パラメータ@latestは最新バージョンをインストールします。「.」は現在のフォルダにプロジェクトを作成することを意味し、--tsはTypeScriptを使用することを意味し、最後の--quickstartはデフォルト設定でインストールされるということです。インストールが終了すると、/admin/auth/register-adminアドレスの新しいウィンドウが開かれ、新しい管理者アカウントの作成を求められます。進んで新しいアカウントを作成してください。注:この投稿ではソースコードを変更しないので、--tsを使うのはオプションです。

NextJSの初期化

cd frontend
npx create-next-app@latest . --ts

最後に、Githubリポジトリを初期化することを忘れないでくださいが、この投稿ではカバーしません。

Strapiの開始

私はプロジェクトでバックエンドから始めるのが好きなので、バックエンドと見なされるStrapiから始めましょう。

GraphQLのインストール

Strapiの利点の一つは、GraphQLとの簡単な統合です。GraphQLプラグインをインストールするには、次のコマンドを実行する必要があります。

npm run strapi install graphql

_Duplicate "graphql" modules_ エラーが出たら心配しないでください。対処法は簡単です;全てが必要なのはnode_modulesフォルダとpackage-lock.jsonを削除し、パッケージを再インストールすることです。

rm -rf node_modules
rm package-lock.json
npm install
npm run strapi dev

インストールに成功したら、/graphqlのURLを訪れることができます。

ブログ投稿コレクションの作成

Strapiのホームページをhttp://localhost:1337/admin/で開き、サインインしたら、コンテンツタイプビルダーページに行き、新規コレクションタイプ作成ボタンをクリックし、表示名フィールドに適切な名前を入力します。私はブログ投稿を選びます。その後、続けてください。

新しいコレクションのフィールド選択に入るところです。好きなようにカスタマイズできますが、簡単にするために、タイトル用のテキストフィールド、説明用のもう一つのテキストフィールド、最後に本文用のリッチテキストフィールドを追加します。次に保存をクリックします。

コレクションを持つことができたら、データでそれを入力する必要があります。コンテンツマネージャーに行き、新しく作成されたコレクションが見えるはずです。それをクリックして、新しいエントリを作成ボタンをクリックして、好きなデータを入力し、保存して公開しましょう。

アクセス権限オプション1:公開アクセス可能

データにGraphQLを使ってアクセスできるようにする前に、アクセス可能にする必要があります。公開アクセス可能にすることもできますし、認証済みユーザーのみにすることもできます。私は機密データを保存していないので、公開アクセス可能なコレクションを選びます。

公開アクセス可能にするには、設定に行き、ロールをクリックし、パブリックをクリックし、作成したコレクションをスクロールして見つけ出します(私の場合はブログ投稿です)、それをクリックし、findfindOneにチェックを入れます。

アクセス権限オプション2:認証済みのみ

しかし認証済みの方法を選ぶ場合は、こうしてください。これを実現する方法は2つあります;1つ目は、設定ページでAPIトークンを作成し、リクエストに添付する必要があります。それをヘッダーにAuthorizationヘッダーとして追加して、値をbearerに設定します。2つ目の方法は、コンテンツマネージャーページを通じてユーザーコレクションに新しいエントリを作成し、その新しく作成したユーザーのユーザー名またはメールアドレスとパスワードを含むJSONボディを添えて/api/auth/localポストリクエストを送ることです。ストラッピーを初期化する際に作成した管理者アカウントではありません。

{
 "identifier": "email or username",
 "password": "password"
}

リクエストが成功したら、JWTフィールドを含む返事を受け取ります。次に、リクエストごとに同じことをして、ヘッダー内に送信し、Authorizationヘッダーの値をbearerと設定します。

アクセスするには、設定に行き、ロールをクリックし、認証済みをクリックします。作成したコレクションをスクロールして見つけ出します(私の場合はブログ投稿です)、それをクリックし、findfindOneにチェックを入れます。

GraphQLエンドポイントのテスト

GraphQLにアクセスするには/graphqlを訪れます。そして、左側の入力フィールドにクエリを入力してStrapiアプリケーションを問い合わせることができます。クエリの例:

query {
  blogPosts {
    data {
      id
      attributes {
        title
        description
        body
      }
    }
  }
}

私の場合の返事は:

  "data": {
    "blogPosts": {
      "data": [
        {
          "id": "1",
          "attributes": {
            "title": "test",
            "description": "test",
            "body": "test"
          }
        }
      ]
    }
  }
}

RESTエンドポイントのテスト

することは/api/blog-posts/にGETリクエストを送ることだけです。返事の例は:

{
    "data": [
        {
            "id": 1,
            "attributes": {
                "title": "test",
                "description": "test",
                "body": "test",
                "createdAt": "2023-01-30T20:28:28.141Z",
                "updatedAt": "2023-01-30T20:28:29.027Z",
                "publishedAt": "2023-01-30T20:28:29.025Z"
            }
        }
    ],
    "meta": {
        "pagination": {
            "page": 1,
            "pageSize": 25,
            "pageCount": 1,
            "total": 1
        }
    }
}

Strapiセクションはこれで終わりで、NextJSを続けます。

NextJSの開始

**pages**ディレクトリ内に新しいディレクトリを作成し、blogと名付けます。次に、新しいindex.tsxファイルを作成し、基本的なreactコンポーネントを初期化します。

import {NextPage} from "next";

interface Props {
}

const About: NextPage<Props> = (Props) => {
    return (
        <p>About Page</p>
    )
}

export default About;

これでblogを訪れてAboutページが見れます。

インターフェイスの作成

何個かのインターフェイスが必要になります。始めるにあたって、基本的なモジュールを含む**commonフォルダを新たに作成し、次に全てのタイプとインターフェイスを含むtypesフォルダを作成しましょう。そして新たなtypescriptを作成し、BlogInterfaces**と命名します。最初のインターフェイスはIBlogIdentificationで、私たちの識別フィールド、つまりブログ投稿のidを含むものになります。

export interface IBlogIdentification {
    id: string
}

次に、ブログのフィールドのタイトル、説明、本文を含むインターフェイスが必要です。それをIBlogFieldsと名付けます。

export interface IBlogFields {
    title: string,
    description: string,
    body: string
}

次に、GraphQLクエリから受け取るブログ属性のインターフェイスが必要です。それをIBlogAttributesと名付けましょう。

export interface IBlogAttributes {
    attributes: Partial<IBlogFields> & Pick<IBlogFields, 'title'>
}

私はIBlogFieldsの全てのフィールドをオプショナル(任意)にするためにPartial型とPick型を使用しました。ただしタイトルは除く。

最後に、ブログエントリ全体を扱うためのインターフェイスが必要です;それをIBlogと名付けましょう。

export interface IBlog extends IBlogIdentification, IBlogAttributes{}

**blog**ページのPropsインターフェイスを更新しましょう。

interface Props {
    blogs: IBlog[]
}

GraphQLワークス

データのフェッチを開始する前に、GraphQLワークスが必要になります。まず2つのパッケージ、graphql@apollo/clientパッケージをインストールする必要があります。

npm i graphql @apollo/client

次に、クエリを書く必要があります。ブログをリストするための最初のクエリ、二つ目は単独のブログを取得するためのクエリ、そして最後はブログIDのリストを取得するためのクエリです。**common**フォルダ内に新しいフォルダを作成しgraphqlと名付け、新しいファイルを作成しqueries.tsxと名付け、次のクエリを追加しましょう。

export const LIST_BLOG = gql(`query {
  blogPosts {
    data {
      id
      attributes {
        title
      }
    }
  }
}`)

export const SINGLE_BLOG = gql(`query ($blogId: string!) {
  blogPosts(filters: {id: {eq: $blogId}}) {
    data {
      id
      attributes {
        title
        description
        body
      }
    }
  }
}`)

export const LIST_ID = gql(`query {
  blogPosts {
    data {
      id
    }
  }
}`)

必要な次のことは、Strapiのアドレスを保存することです。最も便利な方法は環境変数の中に保存することです。NextJSには既に組み込みの環境変数モジュールがあるので、dotenvをインストールする必要はありません。やるべきことはnext-config.jsに行って、次のエクスポートを追加することです。

module.exports = {
  env: {
    STRAPI_ADDRESS: "http://127.0.0.1:1337/graphql"
  },
  nextConfig,
}

最後に必要なことは、GraphQLサーバーに接続するためのApolloClientです。**graphql**フォルダ内に新しいファイルを作成し、client.tsxと名付け、次のコードを追加します。

import {ApolloClient, InMemoryCache, NormalizedCacheObject} from "@apollo/client";

const client: ApolloClient<NormalizedCacheObject> = new ApolloClient({
    uri: process.env.STRAPI_ADDRESS,
    cache: new InMemoryCache(),
});

export default client;

注意:キャッシュはApolloClientが結果をキャッシュ

こちらの記事はdev.toの良い記事を日本人向けに翻訳しています。
https://dev.to/kadiemq/typescript-nextjs-strapi-and-graphql-an-overview-of-how-i-created-my-blog-61g