Qt 6.7以降のRESTfulクライアントアプリケーション

本記事は「RESTful Client Applications in Qt 6.7 and Forward」の抄訳です。
 

Qt 6.7では、典型的なRESTful/HTTPクライアントアプリケーションの実装に便利な改善が導入されています。目標は、小さいながらも系統的に繰り返されるニーズにもっと便利な方法で対応することにより、繰り返しのネットワーク定型コードを最大40%まで削減することです。

これには、HTTPヘッダーを表す新しいQHttpHeadersクラス、API固有のリクエストを作成するためのQNetworkRequestFactory、小さくて頻繁に繰り返されるコードを扱うQRestAccessManagerクラス、およびレスポンスからデータを抽出してエラーをチェックするQRestReplyクラスが含まれています。QNetworkRequestFactoryQRestAccessManager、およびQRestReplyは、Qt 6.7で技術プレビューとしてリリースされています。

以下は、これらの新しい機能を使用しているQt Colorpalette Clientのサンプルアプリケーションのスクリーンショットです。このクライアントアプリケーションは、REST APIと 'color' および 'user' リソースを視覚化します。

colorpaletteclient

RESTの要点

RESTは現在のほとんどのネットワークアプリケーションで使用されているアーキテクチャスタイルです。 「REST」は厳密な技術仕様ではなく、リソースの整理とアクセスに関する制約と推奨事項群です。技術的には、HTTPリクエストの送信と処理に帰結し、しばしばHTTPクライアントとRESTfulクライアントを同義に使用することが一般的です。

Qt 4.4(2008年)以降、C ++側でRESTful/HTTPクライアントアプリケーションを開発するための主要クラスはQNetworkAccessManagerです。このクラスを使用すると、HTTPリクエストを発行し、レスポンスを処理するためにシグナルスロット接続を使用できます。

QMLおよびJavaScript側では、同様の目的のためにXmlHttpRequestsクラスがあります。より複雑なQMLアプリケーションでは、C ++のQNetworkAccessManagerを使用してネットワーキングをQMLにデータおよび制御タイプ/要素としてブリッジ/公開することもあります。

Qt 6.7の新規機能:QHttpHeaders

Qtでは、HTTPヘッダーはQMapQHash、ペアのリスト、QMultiMap、またはQMultiHashで表されます。これは機能しますが、正確なタイプはAPI固有のものであり、一般的なヘッダーの便利な操作、パフォーマンスの最適化、またはたとえば、ヘッダーの名前と値がRFC仕様に準拠しているか否かをチェックすることができません。

Qt 6.7では、HTTPヘッダーを表すためのQHttpHeadersクラスが導入されています。現時点では、このクラスは主に内部で使用されています。将来のQtリリースでは、このクラスをサポートするために公開ネットワーキングAPIが拡張されます。

これによって可能になる内部のパフォーマンス最適化の例は、100以上のよく知られているヘッダーのいずれかを表すために文字列ではなく列挙型を内部で使用できることです。これにより、ルックアップとストレージが計算上より効率的になります。

Qt 6.7の新規機能:QNetworkRequestFactory

多くのRESTサーバーAPIは、リクエストごとに繰り返される情報が必要です。つまり、URL、クエリパラメータ、SSL構成、認証詳細などです。これらのリクエストには、通常、リソースパスやクエリパラメータなど、リクエストごとに変更される部分もあります。

QNetworkRequestFactory を使用すると、共通のパラメータを一度だけ定義し、その後は新しいリクエストを作成する際にリクエスト固有のパラメータのみを渡すことができます。作成されたリクエストは、その後、QNetworkAccessManagerまたはQRestAccessManagerに渡されます。

対象となる各APIについてファクトリを持つことが一般的な使用方法です。

// アプリケーション内の適切な場所でネットワークアクセスマネージャをインスタンス化
QNetworkAccessManager manager;
// ...managerを初期化

// アプリケーション内の適切な場所でファクトリをインスタンス化
QNetworkRequestFactory exampleApi{ {"https://example.com/v1"_L1} };
// bearerトークンを設定
exampleApi.setBearerToken("my_token");
// 共通のヘッダーを埋める
QHttpHeaders commonHeaders;
exampleApi.setCommonHeaders(commonHeaders);
// ...クエリパラメータなどを設定...
// リクエストを作成して、"https://example.com/v1/models" に送信 manager.get(exampleApi.createRequest("models"_L1));

QNetworkRequestFactoryクラスは、Qt 6.7でテクニカルプレビューとしてリリースされ、初期ユーザーフィードバックのお陰で、Qt 6.8向けにさらに改良されました。

Qt 6.7の新規機能:QRestAccessManager 及び QRestReply

QRestAccessManagerと関連するQRestReplyは、QNetworkAccessManagerQNetworkReplyの上に軽量の、所有していない便利なラッパーです。これらは、典型的なRESTful/HTTPクライアントのニーズを合理化します。

  • JSONやその他の種類をリクエストデータとして直接受け入れる
  • JSONやその他の種類(特にテキスト)をレスポンスとして提供する
  • エラー処理(ネットワークエラーとHTTPエラーを区別)
  • リクエストの発行時に直接コンテキストを持つコールバックを受け入れる
  • その他、patch()リクエストを送信するための名前付きAPIを含む

これらの改善は、単独で非常に大きいとは限りませんが、必要な冗長なコードと考え込むことを減らします。以下は、JSONの送信と受信の例です。これにより、複数の方法で必要なコードを削減し、便利さを向上させます:

  • JSONデータを直接送信する(myJson)。手動で変換したり、Content-Type: application/jsonヘッダーを設定する必要はありません。
  • コールバックを直接定義する(thisは、thisが削除された場合にクリーンアップするためのコンテキストオブジェクトとして使用されます)
  • レスポンスのJSONを直接読み取る(readJson())。QByteArrayからの変換を書く必要はありません。必要に応じてJSONのパースエラーも利用可能です。この例では成功チェックを省略していますが、reply.isSuccess()を使用して行うこともできます。
manager->post(request, myJson, this, [this](QRestReply &reply) {
    if (auto json = reply.readJson()) {
        // *jsonを使用
    }
});

データがテキストである場合、到着時に読み取ることができます(ストリーミング)。QRestReplyはストリーミングテキストのデコードを実装し、指定された charset パラメータ(例:UTF-8)を使用します。

注:これらは単なる所有していない便利なラッパーですが、引き続き既存のQNetworkAccessManagerコードを使用し、例えば、受信したQNetworkReply*QRestReplyでラップすることができます。

QRestAccessManagerQRestReplyはQt 6.7でテクニカルプレビューとしてリリースされています。

今後の展望

今後の展望として、計画段階にある関連アイテムがさらに多くあります。皆様からのフィードバックを歓迎しております。


Blog Topics:

Comments