Disqus APIを使用してフォーラムのスレッドと投稿を取得する方法


[Disqus](https://disqus.com/)は、ウェブサイトにコメント機能を追加するための人気のあるプラットフォームです。この記事では、Javaを使用してDisqus APIからフォーラムのスレッドと投稿を取得する方法を解説します。

# 1. 必要なライブラリのインポート

まず、以下のライブラリをプロジェクトに追加する必要があります。
- `OkHttpClient`: HTTPリクエストを行うためのライブラリ
- `Gson`: JSONのシリアル化およびデシリアル化のためのライブラリ

`OkHttpClient`と`Gson`をMavenプロジェクトに追加するには、`pom.xml`ファイルに対応する依存関係を追加する必要があります。

以下は、それぞれのライブラリのMaven依存関係です：

1. **OkHttpClient**:
    ```xml
    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>okhttp</artifactId>
        <version>4.9.1</version> <!-- 最新のバージョンを使用してください -->
    </dependency>
    ```

2. **Gson**:
    ```xml
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.8</version> <!-- 最新のバージョンを使用してください -->
    </dependency>
    ```

これらの依存関係を`pom.xml`の`<dependencies>`セクションに追加してください。そして、プロジェクトをビルドすると、Mavenはこれらのライブラリをダウンロードしてプロジェクトに追加します。

注意: 上記のバージョンは執筆時点のものです。常に最新のバージョンを使用することをおすすめします。Maven Central Repositoryで最新のバージョンを確認できます。

# 2. APIキーの取得

[Disqus API](https://disqus.com/api/docs/)のApplicationsからAPIキーを取得してください。このキーは、APIリクエストを認証するために必要です。

# 3. コードの概要

以下のコードは、Disqus APIを使用してフォーラムのスレッドと投稿を取得するためのサンプルです。

```java
package jp.livlog.shoppingstreet.helper.disqus;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.gson.Gson;

import jp.livlog.shoppingstreet.helper.disqus.data.PostResponse;
import jp.livlog.shoppingstreet.helper.disqus.data.PostsResponse;
import jp.livlog.shoppingstreet.helper.disqus.data.ThreadResponse;
import jp.livlog.shoppingstreet.helper.disqus.data.ThreadsResponse;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;

/**
 * DisqusAPI クラスは、Disqus の API を利用して、
 * フォーラムのスレッドと投稿を取得するためのヘルパークラスです。
 */
public class DisqusAPI {

    private static final String           THREADS_API_URL = "https://disqus.com/api/3.0/forums/listThreads.json";

    private static final String           POSTS_API_URL   = "https://disqus.com/api/3.0/forums/listPosts.json";

    private static final String           API_KEY         = "YOUR_API_KEY";

    private static final int              LIMIT           = 50;

    private static final SimpleDateFormat ISO_8601_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");

    /**
     * メインメソッドです。
     * @param args コマンドライン引数
     */
    public static void main(final String[] args) {

        try {
            final var forumShortName = "machikado"; // 例として"machikado"を使用
            final var threads = DisqusAPI.fetchThreads(forumShortName, null);
            for (final ThreadResponse thread : threads) {
                System.out.println(thread);
            }

            final var posts = DisqusAPI.fetchPosts(forumShortName, null);
            for (final PostResponse post : posts) {
                System.out.println(post);
            }

        } catch (final Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 指定されたフォーラムのスレッドを取得します。
     * @param forumShortName フォーラムのショートネーム
     * @param since 指定された日付以降の投稿を取得
     * @return スレッドのレスポンスのリスト
     * @throws Exception APIの呼び出し中にエラーが発生した場合
     */
    public static List <ThreadResponse> fetchThreads(final String forumShortName, final Date since) throws Exception {

        final List <ThreadResponse> allThreads = new ArrayList <>();
        String cursor = null;
        var cnt = 0;
        do {
            final var response = DisqusAPI.fetchFromAPI(forumShortName, since, cursor, DisqusAPI.THREADS_API_URL, ThreadsResponse.class);
            allThreads.addAll(response.getResponse());
            cnt = response.getResponse().size();
            cursor = response.getCursor().getNext();
        } while (cnt == DisqusAPI.LIMIT);
        return allThreads;
    }


    /**
     * 指定されたフォーラムの投稿を取得します。
     * @param forumShortName フォーラムのショートネーム
     * @param since 指定された日付以降の投稿を取得
     * @return 投稿のレスポンスのリスト
     * @throws Exception APIの呼び出し中にエラーが発生した場合
     */
    public static List <PostResponse> fetchPosts(final String forumShortName, final Date since) throws Exception {

        final List <PostResponse> allPosts = new ArrayList <>();
        String cursor = null;
        var cnt = 0;
        do {
            final var response = DisqusAPI.fetchFromAPI(forumShortName, since, cursor, DisqusAPI.POSTS_API_URL, PostsResponse.class);
            allPosts.addAll(response.getResponse());
            cnt = response.getResponse().size();
            cursor = response.getCursor().getNext();
        } while (cnt == DisqusAPI.LIMIT);
        return allPosts;
    }


    /**
     * 指定されたAPI URLからデータを取得します。
     * @param forumShortName フォーラムのショートネーム
     * @param since 指定された日付以降の投稿を取得
     * @param cursor ページネーションのカーソル
     * @param apiUrl APIのURL
     * @param responseType レスポンスの型
     * @param <T> レスポンスの型のジェネリクス
     * @return APIのレスポンス
     * @throws Exception APIの呼び出し中にエラーが発生した場合
     */
    private static <T> T fetchFromAPI(final String forumShortName, final Date since, final String cursor, final String apiUrl,
            final Class <T> responseType)
            throws Exception {

        final var client = new OkHttpClient();
        final var gson = new Gson();

        final var urlBuilder = HttpUrl.parse(apiUrl).newBuilder();
        urlBuilder.addQueryParameter("forum", forumShortName);
        urlBuilder.addQueryParameter("api_key", DisqusAPI.API_KEY);
        urlBuilder.addQueryParameter("limit", String.valueOf(DisqusAPI.LIMIT));

        if (since != null) {
            urlBuilder.addQueryParameter("since", DisqusAPI.ISO_8601_FORMAT.format(since));
        }

        if (cursor != null && !cursor.isEmpty()) {
            urlBuilder.addQueryParameter("cursor", cursor);
        }

        final var request = new Request.Builder()
                .url(urlBuilder.build())
                .build();

        final var response = client.newCall(request).execute();
        return gson.fromJson(response.body().string(), responseType);
    }
}

```

# 4. コードの説明

- `THREADS_API_URL` と `POSTS_API_URL`: これらのURLは、スレッドと投稿を取得するためのAPIエンドポイントを指しています。
- `fetchThreads` と `fetchPosts`: これらのメソッドは、指定されたフォーラムのスレッドと投稿を取得するためのものです。ページネーションをサポートしており、すべてのデータを取得するために複数回APIを呼び出すことができます。
- `fetchFromAPI`: この汎用メソッドは、任意のAPI URLからデータを取得するためのものです。

# 5. jsonschema2pojoを使用したモデルクラスの自動生成

Disqus APIから取得したJSONデータをJavaのモデルクラスに変換する際、手動での変換は時間がかかることがあります。そこで、`jsonschema2pojo`という便利なツールを使用して、モデルクラス(POJO)を自動生成する方法を紹介します。

## 手順:

1. [jsonschema2pojo](http://www.jsonschema2pojo.org/)の公式サイトにアクセスします。
2. 「JSON」タブを選択し、Disqus APIから取得したJSONデータをテキストエリアにペーストします。
3. 必要な設定を選択します。以下は一般的な設定の例です：
   - **Package**: 生成されるクラスのパッケージ名を指定。
   - **Class Name**: 生成されるクラスの名前を指定。
   - **Source Type**: 「JSON」を選択。
   - **Annotation Style**: 使用するライブラリに合わせて選択。例えば、Gsonを使用する場合は「Gson」を選択。
4. 「Preview」ボタンをクリックして、生成されるJavaクラスをプレビューします。
5. 問題がなければ、「Zip Archive」ボタンをクリックして、生成されたJavaクラスをZIPファイルとしてダウンロードします。
6. ダウンロードしたZIPファイルを解凍し、Javaプロジェクトにインポートします。

これにより、APIから取得したJSONデータをJavaのモデルクラスに簡単に変換することができます。`jsonschema2pojo`を使用することで、モデルクラスの生成作業を効率的に行うことができます。

# 6. 注意点
APIキーはハードコードされていますが、セキュリティ上の理由から、本番環境では環境変数や設定ファイルに保存することをおすすめします。
APIのレートリミットに注意してください。大量のリクエストを短時間に送ると、一時的にAPIの使用が制限される可能性があります。


# まとめ
Disqusは、ウェブサイトにコメント機能を追加するための強力なツールです。この記事では、Javaを使用してDisqus APIを操作する方法を学びました。特に、jsonschema2pojoを使用してモデルクラスを自動生成する方法は、開発の効率を大幅に向上させることができます。Disqusを使用することで、ウェブサイトやブログのエンゲージメントを向上させることができます。