複数のAPIから横断的にコンテンツを取得し、まとめてソートする方法は?

microCMSをご利用いただくなかで、複数のAPI(例えば、「ニュース」と「ブログ」)を横断的に取得し、それらのコンテンツをまとめてソートしたうえで表示したいケースがあるかと思います。

実例として、microCMSのコーポレートサイトの「お知らせ」ページでは、上記のように複数のAPIから記事を取得し、まとめて表示しています。

この記事では、このような表示を実現する実装方法をご紹介します。

前提

まず、前提として以下の2つのAPIがあると仮定します。

1. ニュース

エンドポイント:"news"

APIスキーマは以下の通りとします。

title: 本文(テキストフィールド)
body: 内容(リッチエディタ)

2. ブログ

エンドポイント:"blog"

APIスキーマは以下の通りとします。

title: 本文(テキストフィールド)
body: 内容(リッチエディタ)

分かりやすさのために、APIスキーマは必要最低限の設定としています。

 

また、ニュースおよびブログにてそれぞれ以下のようにコンテンツを用意します。

1. ニュース

  1. 「1つ目のニュース記事」(publishedAt: 2023-12-31T15:00:00.000Z)
  2. 「2つ目のニュース記事」(publishedAt: 2024-01-02T15:00:00.000Z)

2. ブログ

  1. 「1つ目のブログ記事」(publishedAt: 2024-01-01T15:00:00.000Z)
  2. 「2つ目のブログ記事」(publishedAt: 2024-01-03T15:00:00.000Z)

両者をまとめると、時系列(降順)としては以下の順序となります。

  1. 「2つ目のブログ記事」(publishedAt: 2024-01-03T15:00:00.000Z)
  2. 「2つ目のニュース記事」(publishedAt: 2024-01-02T15:00:00.000Z)
  3. 「1つ目のブログ記事」(publishedAt: 2024-01-01T15:00:00.000Z)
  4. 「1つ目のニュース記事」(publishedAt: 2023-12-31T15:00:00.000Z)

やりたいこと

上記の前提で、「ニュース」および「ブログ」のコンテンツを同時に取得し、まとめ、publishedAtの降順に出力するケースを考えます。

サンプルコード

以下、JavaScriptのサンプルコードです。microCMSのAPIへのリクエストには、microcms-js-sdkを利用しています。

import { createClient } from 'microcms-js-sdk';

const client = createClient({
  serviceDomain: "some-domain",
  apiKey: "some-api-key"
});

// 各エンドポイントから記事を取得する関数
async function getArticles(endpoint) {
  try {
      const articles = await client.getAllContents({
        endpoint,
      })

      // 取得した記事にsourceプロパティを追加
      articles.forEach((article) => {
        article.source = `"${endpoint}"`;
      });

      return articles;
  } catch (error) {
    console.error("Failed to fetch articles");
    return [];
  }
}

// 記事を一つのリストにマージする関数
async function mergeArticles() {
  const newsArticles = await getArticles('news');
  const blogArticles = await getArticles('blog');
  return newsArticles.concat(blogArticles);
}

// 記事を日付順(publishedAtの降順)にソートする関数
function sortArticlesByPublishedDate(articles) {
  return articles.sort((a, b) => new Date(b.publishedAt) - new Date(a.publishedAt));
}

// メインの処理
async function main() {
  const allArticles = await mergeArticles();
  const sortedArticles = sortArticlesByPublishedDate(allArticles);

  // ソートされた記事をコンソールに表示する
  sortedArticles.forEach((article) => {
    console.log("===")
    console.log("title:", article.title,`(publishedAt: ${article.publishedAt})`);
    console.log("body:", article.body);
    console.log("source:", article.source);
  });
}

main();
getArticles関数でAPIの記事を取得する際に、microcms-js-sdkの全記事取得のためのメソッドであるgetAllContentsを利用しています。

サンプルコードの実行結果

サンプルコードの実行時にコンソールに出力される内容です。

===
title: 2つ目のブログ記事 (publishedAt: 2024-01-03T15:00:00.000Z)
body: <p>2つ目のブログ記事のbodyです。</p>
source: "blog"
===
title: 2つ目のニュース記事 (publishedAt: 2024-01-02T15:00:00.000Z)
body: <p>2つ目のニュース記事のbodyです。</p>
source: "news"
===
title: 1つ目のブログ記事 (publishedAt: 2024-01-01T15:00:00.000Z)
body: <p>1つ目のブログ記事のbodyです。</p>
source: "blog"
===
title: 1つ目のニュース記事 (publishedAt: 2023-12-31T15:00:00.000Z)
body: <p>1つ目のニュース記事のbodyです。</p>
source: "news"

公開日時(publishedAt)の降順に、ニュースの記事とブログの記事がマージされて出力されています。

なお、どちらのAPIから取得したコンテンツかを判定しやすくするために、source プロパティを付与し、エンドポイント名("news" or "blog")を持たせています。

発展的なアイデア

例えば、年別にページを分けたりする場合などは、filtersパラメータのbegins_with等をご活用いただくなどのアイデアもございます。

また、今回のケースでは同一サービスの複数APIからの取得でしたが、同様にサービスをまたいだコンテンツの取得も可能です。

ご利用のユースケースに合わせ、ぜひご活用ください。

コンテンツの件数が多くページングを取り入れる場合、API間の公開順にバラつきがありうまく機能しない場合がございます。その際は、期間ごとに分けてページを区切る方法などをご検討ください(例:microCMSコーポレートサイトの「お知らせ」)。

CleanShot 2024-01-22 at 14.40.47