diff options
author | Juha Vuolle <[email protected]> | 2023-11-20 12:56:10 +0200 |
---|---|---|
committer | Juha Vuolle <[email protected]> | 2023-12-08 15:53:36 +0200 |
commit | 8da4156da7ed2eff7b44bdda51eb92870bdfbc57 (patch) | |
tree | e98d8d196f8b9b5003794b1de33ed24f35a6b0bb | |
parent | a80ed49b1049478957edca1cfbcd90f9f4b83cb3 (diff) |
Add PATCH support for QRestAccessManager
It is somewhat common HTTP method with RESTful use cases
(partial updates on resources)
Task-number: QTBUG-114637
Change-Id: Id252d3f4b54c3ebb8df5c93259e64a4af2d0ca2f
Reviewed-by: Marc Mutz <[email protected]>
Reviewed-by: Ivan Solovev <[email protected]>
Reviewed-by: MÃ¥rten Nordheim <[email protected]>
6 files changed, 166 insertions, 0 deletions
diff --git a/src/network/access/qrestaccessmanager.cpp b/src/network/access/qrestaccessmanager.cpp index 2a2c1247d88..146d8b24b93 100644 --- a/src/network/access/qrestaccessmanager.cpp +++ b/src/network/access/qrestaccessmanager.cpp @@ -108,6 +108,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li \c post() \li \c put() \li \c head() + \li \c patch() \li \c deleteResource() \li \c sendCustomRequest() \row @@ -116,6 +117,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li - \li - \li X + \li - \li X \li - \row @@ -124,6 +126,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li X \li X \li - + \li X \li - \li X \row @@ -132,6 +135,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li X \li X \li - + \li X \li - \li - \row @@ -140,6 +144,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li X \li X \li - + \li X \li - \li - \row @@ -148,6 +153,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li X \li X \li - + \li X \li - \li - \row @@ -157,6 +163,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li X \li - \li - + \li - \li X \row \li QIODevice @@ -164,6 +171,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li X \li X \li - + \li X \li - \li X \endtable @@ -439,6 +447,77 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") */ /*! + \fn template<typename Functor, if_compatible_callback<Functor>> QRestReply *QRestAccessManager::patch( + const QNetworkRequest &request, const QJsonObject &data, + const ContextTypeForFunctor<Functor> *context, + Functor &&callback) + + Issues an \c {HTTP PATCH} based on \a request. + + The optional \a callback and \a context object can be provided for + handling the request completion as illustrated below: + + \snippet code/src_network_access_qrestaccessmanager.cpp 10 + + Alternatively the signals of the returned QRestReply* object can be + used. For further information see + \l {Issuing Network Requests and Handling Replies}. + + The \c patch() method always requires \a data parameter. The following + data types are supported: + \list + \li QByteArray + \li QJsonObject *) + \li QJsonArray *) + \li QVariantMap **) + \li QIODevice* + \endlist + + *) Sent in \l QJsonDocument::Compact format, and the + \c Content-Type header is set to \c {application/json} if the + \c Content-Type header was not set + **) QVariantMap is converted to and treated as a QJsonObject + + \sa QRestReply, QRestReply::finished(), QRestAccessManager::requestFinished() +*/ + +/*! + \fn template<typename Functor, if_compatible_callback<Functor>> QRestReply *QRestAccessManager::patch( + const QNetworkRequest &request, const QJsonArray &data, + const ContextTypeForFunctor<Functor> *context, + Functor &&callback) + + \overload +*/ + +/*! + \fn template<typename Functor, if_compatible_callback<Functor>> QRestReply *QRestAccessManager::patch( + const QNetworkRequest &request, const QVariantMap &data, + const ContextTypeForFunctor<Functor> *context, + Functor &&callback) + + \overload +*/ + +/*! + \fn template<typename Functor, if_compatible_callback<Functor>> QRestReply *QRestAccessManager::patch( + const QNetworkRequest &request, const QByteArray &data, + const ContextTypeForFunctor<Functor> *context, + Functor &&callback) + + \overload +*/ + +/*! + \fn template<typename Functor, if_compatible_callback<Functor>> QRestReply *QRestAccessManager::patch( + const QNetworkRequest &request, QIODevice *data, + const ContextTypeForFunctor<Functor> *context, + Functor &&callback) + + \overload +*/ + +/*! \fn template<typename Functor, if_compatible_callback<Functor>> QRestReply *QRestAccessManager::head( const QNetworkRequest &request, const ContextTypeForFunctor<Functor> *context, @@ -800,6 +879,52 @@ QRestReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request, return d->executeRequest([&]() { return d->qnam->put(request, data); }, context, slot); } +static const auto PATCH = "PATCH"_ba; + +QRestReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request, + const QJsonObject &data, const QObject *context, + QtPrivate::QSlotObjectBase *slot) +{ + Q_D(QRestAccessManager); + return d->executeRequest( + [&](auto req, auto json){ return d->qnam->sendCustomRequest(req, PATCH, json); }, + data, request, context, slot); +} + +QRestReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request, + const QJsonArray &data, const QObject *context, + QtPrivate::QSlotObjectBase *slot) +{ + Q_D(QRestAccessManager); + return d->executeRequest( + [&](auto req, auto json){ return d->qnam->sendCustomRequest(req, PATCH, json); }, + data, request, context, slot); +} + +QRestReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request, + const QVariantMap &data, const QObject *context, + QtPrivate::QSlotObjectBase *slot) +{ + return patchWithDataImpl(request, QJsonObject::fromVariantMap(data), context, slot); +} + +QRestReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request, + const QByteArray &data, const QObject *context, + QtPrivate::QSlotObjectBase *slot) +{ + Q_D(QRestAccessManager); + return d->executeRequest([&]() { return d->qnam->sendCustomRequest(request, PATCH, data); }, + context, slot); +} + +QRestReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request, QIODevice *data, + const QObject *context, QtPrivate::QSlotObjectBase *slot) +{ + Q_D(QRestAccessManager); + return d->executeRequest([&]() { return d->qnam->sendCustomRequest(request, PATCH, data); }, + context, slot); +} + QRestReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request, const QByteArray& method, const QByteArray &data, const QObject *context, diff --git a/src/network/access/qrestaccessmanager.h b/src/network/access/qrestaccessmanager.h index 3ff23bee905..9656853f43d 100644 --- a/src/network/access/qrestaccessmanager.h +++ b/src/network/access/qrestaccessmanager.h @@ -114,6 +114,11 @@ public: QREST_METHOD_WITH_DATA(put, const QByteArray &) QREST_METHOD_WITH_DATA(put, QHttpMultiPart *) QREST_METHOD_WITH_DATA(put, QIODevice *) + QREST_METHOD_WITH_DATA(patch, const QJsonObject &) + QREST_METHOD_WITH_DATA(patch, const QJsonArray &) + QREST_METHOD_WITH_DATA(patch, const QVariantMap &) + QREST_METHOD_WITH_DATA(patch, const QByteArray &) + QREST_METHOD_WITH_DATA(patch, QIODevice *) QREST_METHOD_CUSTOM_WITH_DATA(const QByteArray &) QREST_METHOD_CUSTOM_WITH_DATA(QIODevice *) QREST_METHOD_CUSTOM_WITH_DATA(QHttpMultiPart *) diff --git a/src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp b/src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp index 20bb5d521d0..fcc8dbaef52 100644 --- a/src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp +++ b/src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp @@ -89,3 +89,11 @@ manager->sendCustomRequest(request, "MYMETHOD", myData, this, [this](QRestRepl // ... }); //! [9] + + +//! [10] +manager->patch(request, myData, this, [this](QRestReply *reply) { + if (reply->isSuccess()) + // ... +}); +//! [10] diff --git a/tests/auto/network/access/qrestaccessmanager/httptestserver.cpp b/tests/auto/network/access/qrestaccessmanager/httptestserver.cpp index dfa2b45063d..089342ff8bf 100644 --- a/tests/auto/network/access/qrestaccessmanager/httptestserver.cpp +++ b/tests/auto/network/access/qrestaccessmanager/httptestserver.cpp @@ -147,6 +147,8 @@ bool HttpTestServer::readMethod(QTcpSocket *socket) method = Method::Get; else if (fragment == "PUT") method = Method::Put; + else if (fragment == "PATCH") + method = Method::Patch; else if (fragment == "POST") method = Method::Post; else if (fragment == "DELETE") diff --git a/tests/auto/network/access/qrestaccessmanager/httptestserver_p.h b/tests/auto/network/access/qrestaccessmanager/httptestserver_p.h index d1819fcc21a..1498c4bdb7e 100644 --- a/tests/auto/network/access/qrestaccessmanager/httptestserver_p.h +++ b/tests/auto/network/access/qrestaccessmanager/httptestserver_p.h @@ -54,6 +54,7 @@ public: Head, Get, Put, + Patch, Post, Delete, Custom, diff --git a/tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp b/tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp index f66968bf1cf..b2cfcf4a754 100644 --- a/tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp +++ b/tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp @@ -108,6 +108,7 @@ void tst_QRestAccessManager::networkRequestReply() const QByteArray methodPOST{"POST"_ba}; const QByteArray methodGET{"GET"_ba}; const QByteArray methodPUT{"PUT"_ba}; + const QByteArray methodPATCH{"PATCH"_ba}; const QByteArray methodCUSTOM{"FOOBAR"_ba}; // DELETE @@ -209,6 +210,27 @@ void tst_QRestAccessManager::networkRequestReply() VERIFY_REPLY_OK(methodPUT); QCOMPARE(serverSideRequest.body, ioDeviceData); + // PATCH + manager.patch(request, byteArrayData, this, callback); + VERIFY_REPLY_OK(methodPATCH); + QCOMPARE(serverSideRequest.body, byteArrayData); + + manager.patch(request, jsonObjectData, this, callback); + VERIFY_REPLY_OK(methodPATCH); + QCOMPARE(QJsonDocument::fromJson(serverSideRequest.body).object(), jsonObjectData); + + manager.patch(request, jsonArrayData, this, callback); + VERIFY_REPLY_OK(methodPATCH); + QCOMPARE(QJsonDocument::fromJson(serverSideRequest.body).array(), jsonArrayData); + + manager.patch(request, variantMapData, this, callback); + VERIFY_REPLY_OK(methodPATCH); + QCOMPARE(QJsonDocument::fromJson(serverSideRequest.body).object(), jsonObjectData); + + manager.patch(request, &bufferIoDevice, this, callback); + VERIFY_REPLY_OK(methodPATCH); + QCOMPARE(serverSideRequest.body, ioDeviceData); + //These must NOT compile //manager.get(request, [](){}); // callback without context object //manager.get(request, ""_ba, [](){}); // callback without context object @@ -219,6 +241,9 @@ void tst_QRestAccessManager::networkRequestReply() //manager.post(request); // data is required //manager.put(request, QString()); // wrong datatype //manager.put(request); // data is required + //manager.patch(request, 123); // wrong datatype + //manager.patch(request, QString()); // wrong datatype + //manager.patch(request); // data is required //manager.deleteResource(request, "f"_ba); // data not allowed //manager.head(request, "f"_ba); // data not allowed //manager.post(request, ""_ba, this, [](int param){}); // Wrong callback signature |