Qt5にRest APIクライアントを作成します

はじめに



最近、デスクトップREST APIクライアントを開発しています。 かなり多くの作業は、サーバーとの対話にあります。 要求の処理を最適化するために、次の機能を持つRequesterクラスが作成されました。











このクラスを使用するプログラマは、次の3つの機能を使用する必要があります。







void initRequester(const QString& host, int port, QSslConfiguration *value); //     void sendRequest(const QString &apiStr, const handleFunc &funcSuccess, const handleFunc &funcError, Type type = Type::GET, const QVariantMap &data = QVariantMap()); //   GET        void sendMulishGetRequest( const QString &apiStr, const handleFunc &funcSuccess, const handleFunc &funcError, const finishFunc &funcFinish);
      
      





funcSuccess-要求が成功した場合に呼び出されるコールバック

funcError-エラーの場合のコールバック







  typedef std::function<void(const QJsonObject &)> handleFunc; typedef std::function<void()> finishFunc; enum class Type { POST, GET, PATCH, DELET };
      
      





DELETEはWINDOWSでビルドされないため、DELETはタイプミスではありません。







実装



サーバーと対話するには、3つのQtクラスを使用します。QNetworkAccessManager-サーバー要求メカニズムを実装し、QNetworkReply-要求に対するサーバーの応答、QNetworkRequest-要求自体です。







initRequester関数の実装を説明する理由がないので、すぐにSendRequestに進みましょう。 考え方は、QNetworkRequestクラスのオブジェクトを作成することです。 リクエストのタイプに応じて、追加のデータ(リクエストボディがある場合)とともにQNetworkAccessManagerクラスのオブジェクトに渡します。 応答は応答に書き込まれます(QNetworkReplyクラスのオブジェクト)。 リクエストは非同期に実行されるため、応答から終了したシグナルでラムダを呼び出します。ラムダはエラーがあるかどうかを確認し、対応するコールバックを呼び出します。また、リソースを解放します。

次のコードを使用してリクエストを作成します。







 QNetworkRequest Requester::createRequest(const QString &apiStr) { QNetworkRequest request; QString url = pathTemplate.arg(host).arg(port).arg(apiStr); request.setUrl(QUrl(url)); request.setRawHeader("Content-Type","application/json"); //       if (sslConfig != nullptr) request.setSslConfiguration(*sslConfig); return request; }
      
      





そして、これはサーバー要求のための関数自体のコードです:







 void Requester::sendRequest(const QString &apiStr, const handleFunc &funcSuccess, const handleFunc &funcError, Requester::Type type, const QVariantMap &data) { QNetworkRequest request = createRequest(apiStr); QNetworkReply *reply; switch (type) { case Type::POST: { QByteArray postDataByteArray = variantMapToJson(data); reply = manager->post(request, postDataByteArray); break; } case Type::GET: { reply = manager->get(request); break; } case Type::DELET: { if (data.isEmpty()) reply = manager->deleteResource(request); else reply = sendCustomRequest(manager, request, "DELETE", data); //  break; } case Type::PATCH: { reply = sendCustomRequest(manager, request, "PATCH", data); break; } default: reply = nullptr; } connect(reply, &QNetworkReply::finished, this, [this, funcSuccess, funcError, reply]() { //       ,      json QJsonObject obj = parseReply(reply); if (onFinishRequest(reply)) { if (funcSuccess != nullptr) funcSuccess(obj); } else { if (funcError != nullptr) { handleQtNetworkErrors(reply, obj); funcError(obj); } } reply->close(); reply->deleteLater(); } ); }
      
      





注意深い読者は、一部のDELETEクエリとすべてのPATCHについて、sendCustomRequest関数を使用してQNetworkReplyオブジェクトを作成していることに気付きました。 これは、QNetworkAccessManagerが、ボックスからの本文を使用してDELETEリクエストを送信する方法を知らず、パッチを適用する方法を知らないためです。 この問題を解決するために、小さなラッパー関数を作成します。







 QNetworkReply* Requester::sendCustomRequest(QNetworkAccessManager* manager, QNetworkRequest &request, const QString &type, const QVariantMap &data) { request.setRawHeader("HTTP", type.toUtf8()); QByteArray postDataByteArray = variantMapToJson(data); QBuffer *buff = new QBuffer; buff->setData(postDataByteArray); buff->open(QIODevice::ReadOnly); QNetworkReply* reply = manager->sendCustomRequest(request, type.toUtf8(), buff); buff->setParent(reply); return reply; }
      
      





sendMulishGetRequest関数を上記で説明したものと似ているため、詳細に検討する意味はありません。 違いは、リクエストが最初に正常に実行された後、次のページへのリンクが応答から取り出され、その後再帰呼び出しが発生することです。 次のページがない場合、funcFinish関数が実行されます。







おわりに



結果として得られるクラスは、非常にシンプルなインターフェースを使用しており、多くの日常的なアクションからも私たちを救います。







https://github.com/Bragaman/QtRestApiRequester








All Articles