本ブログを WordPress から WordPress + Next.js の Jamstack 構成にアップデートしました。色々と学びがあったので、アウトプットしておきます。WordPress との連携については、こちらのブログ記事がかなり参考になりました。

Next.jsを使った静的なHeadless WordPressサイトの作り方

今回はその中でも Rest API の URL を作るクラスを掘り下げてみようと思います。ソースコードの全容はこちらになります。

v3.katsushi-ougi.com/UrlBuilder.ts at main · ANTON072/v3.katsushi-ougi.com

使い方は以下のようになります。

const urlBuilder = WPAPIURLFactory.init(process.env.WORDPRESS_URL)
  .postType("posts")
  .startAt(1);

`urlBuilder.getURL()` 実行すると、 `https://hoge.com/posts&startAt=1` のような URL を得ることができます。jQuery 的なメソッドチェーンが美しいです。中身を掘り下げていきます。

クラス名の WPAPIURLFactroy からわかるようにデザインパターンの一種の Factory パターン ですね。

僕の言葉で置き換えると、”同じ「作る」という動作をするにしても、何を作るかは変わるよね(下記のサンプルコードだと「製品」でも、車とバイクがあったり。で、その「製品」を作る人は「作る」しか意識したくないし(=再利用製を高める)、作る対象もフレキシブルに増やしたりしたいから、その「作る」と「製品の具体的な内容」を疎結合にしたいパターンだよ、ですかね)”

https://mame0112.hatenablog.com/entry/2015/07/26/195821

「REST API の URL を作る」という行為は共通だが、どういう URL を作るかは変わる。「URL を作る」と「URL 具体的な内容」を疎結合にした、ということでしょうか。init で 独自のオブジェクト と 共通メソッド群をもったオブジェクトを返却しています。new してインスタンスを生成する、というのは定番でよくやるのですが、ファクトリーパターンを使うとシンプルで見栄えもよいですね。

const api = {
  path: "",
  queryString: { ... }
}

return {
  path(path: string) {
    api.path = path
    return this
  }
}

各メソッドで this を return することにより、チェーンメソッドが可能となっています。

最終的に getURL メソッドを実行すると、api オブジェクトを文字列化したものが return されます。

getURL(): string {
  const url = [endpoint, namespace, api.path].join("/");
  const queryStringList = Object.entries(api.queryString);

  const queryString = queryStringList
    .reduce((prevQueries, [key, value]) => {
      if (key === "embed" && value === true) prevQueries.push("_embed");
      if (key === "search" && !!value)
        prevQueries.push(`search=${value}`);
      if (key === "slug" && !!value) prevQueries.push(`slug=${value}`);
      if (key === "tags" && !!value) prevQueries.push(`tags=${value}`);
      if (key === "after" && !!value) prevQueries.push(`after=${value}`);
      if (key === "before" && !!value)
        prevQueries.push(`before=${value}`);
      if (key === "perPage") prevQueries.push(`per_page=${value}`);
      if (key === "startAt") prevQueries.push(`page=${value}`);
      if (key === "custom" && !!value) prevQueries.push(value);
      if (key === "nextjs") prevQueries.push(`nextjs=true`);

      return prevQueries;
    }, [] as (string | number | boolean)[])
    .join("&");

  return [url, queryString].join("?");
},

reduce で文字列を生成するのがクールですね。TypeScriptの場合、初期化時の配列を型で定義する必要がありました。`[] as (string | number | boolean)[]`

REST API を実行する際に、あらゆる個所でこのクラスを利用しています。とても勉強になりました。