Contentfulの記事をAlgoliaのインデックスに登録する

公開日時
更新日時

全文検索SaaSのAlgoliaを試そうと思い、このブログに検索機能を追加した。

ContentfulとAlgoliaの連携方法については公式チュートリアルが用意されている。

導入手順

※ 前提:Algoliaのアカウントは作成済み

  1. Contetful APIを使って既存の記事データからAlgolia用のインデックスを生成する
  2. 記事作成、更新、削除時にインデックスが更新されるようにWebhookを設定する
  3. react-instantsearchを使ってアプリケーション側に検索機能を実装する

今回は手順1, 2についてまとめ、手順3は別記事にまとめる。

Contetful APIを使って既存の記事データからAlgolia用のインデックスを生成

Algoliaに登録するインデックスを↓と定義した。

{
    url: "記事URL",
    title: "タイトル",
    description: "記事概要",
    content: "MarkdownをPlainTextに変換した記事本文",
    objectID: "Contentfulの記事ID",
}

Contetful APIを使って既存の記事データを取得し、上記定義に沿ったjsonを出力するscriptを作成。

// generate_algolia_index.js
const contentful = require("contentful-management");
const removeMd = require("remove-markdown");

(async () => {
  const client = contentful.createClient({
    accessToken: process.env.ACCESS_TOKEN,
  });

  const space = await client.getSpace(process.env.SPACE_ID);
  const master = await space.getEnvironment("master");

  const entries = await master.getEntries({
    content_type: "blogPost",
    limit: 1000,
  });

  const algoliaIndexes = entries.items.map((entry) => {
    const indexFields = {
      url: `/posts/${entry.fields.slug["ja-JP"]}`,
      title: entry.fields.title["ja-JP"],
      content: removeMd(entry.fields.body["ja-JP"]),
      objectID: entry.sys.id,
    };

    if (entry.fields.description) {
      indexFields.description = entry.fields.description["ja-JP"];
    }
    return indexFields;
  });

  console.log(JSON.stringify(algoliaIndexes, null, 2));
})();

上記scriptを実行し、適当なファイルにjsonを出力する。

node generate_algolia_index.js > algolia_index.json

Algoliaの管理画面のIndicesメニューからjsonファイルをアップロードする。

algolia1

アップロードが完了すると管理画面上で登録済みのインデックスが確認できるようになる。

記事作成、更新、削除時にインデックスが更新されるようにWebhookを設定

Algoliaに登録したインデックス名と、API Keysメニューに記載されている

  • Application ID
  • Admin API Key

を確認しておく。

algolia2

続いて、ContentfulのSettings => Webhooksを表示し、「See All 18 Templates」をクリックしてAlgoliaのテンプレートを表示する。

algolia3

API Key等を入力しWebhook作成を実行すると、2つのWebhookが追加される。

  • Algolia - Index entries
  • Algolia - Delete unpublished entries

デフォルト設定だとAlgoliaに送信されるデータがContentfulのentryデータそのものになっているため、独自に定義したインデックスjsonと異なるjsonが登録されてしまう。

そこで、 Index entries , Delete unpublished entries それぞれの「Webhook settings」 => 「Payload」で「Customize the webhook payload」を選択し、独自定義のインデックスjsonを送信するように変更した。

algolia4
{
  "url": "/posts/{ /payload/fields/slug/ja-JP }",
  "title": "{ /payload/fields/title/ja-JP }",
  "description": "{ /payload/fields/description/ja-JP }",
  "content": "{ strip-markdown /payload/fields/body/ja-JP }",
  "objectID": "{ /payload/sys/id }"
}

MarkdownをPlainTextに変換するのをWebhookでどう実現しようかと思っていたが、 strip-markdown という変換Helperが利用できた。

これで、ContentfulからAlgoliaへインデックス登録を行う仕組みができた。

次回はアプリケーション側での実装方法についてまとめる。

=> Next.js + Algoliaで全文検索UIを実装する

参考


Related #contentful

GridsomeとContentfulとCircleCIを組み合わせて予約投稿ができるようにする

CircleCIのSchedule Jobsを使って定期ビルドするようにした

Contentfulに予約投稿機能が追加された

独自の予約投稿機能を作る必要がなくなって便利になった

Contentfulの料金プラン改定

嬉しいアップデート

ContentfulのContent modelにvalidationを設定する

slugに正規表現のvalidationを設定した

Contentful GraphQL APIで最終更新日時を取得する

sys.publishedAtで最終更新日時が取得できる