QNetworkAccessManager send PUT request with JSON - c++

I want to send a put request with JSON body, but with QNetworkAccessManager doesn't have the option to send a request with JSON so I converted it to QByteArray, the structure of the body, when converted to QByteArray, is not a JSON format so that I received an Error with
"Error downloading https://example.api.com/something/DataSet('123456780XYZ') - server replied: Forbidden"
The JSON format I want is like this:
{
"d": {
"Duration": "0.000",
"Id": "123456780XYZ",
"LoadCumulLimit": "0.000",
"Notes": "send from postman in Json format"
}
}
Here is what did I do
QJsonObject data;
data["Duration"] = workplace->data["duration"];
data["Id"] = id;
data["LoadCumulLimit"] = workplace->data["load_cumul_limit"];
data["Notes"] = workplace->dataText["Notes"];
QJsonObject newData;
newData["d"] = data;
QJsonDocument doc(newData);
qDebug() << url;
QByteArray finalData = doc.toJson();
qDebug() << finalData;
reply = manager->put(request, finalData);
connect(reply, &QNetworkReply::finished, [=](){
if(reply->error() == QNetworkReply::NoError){
QString contents = QString::fromUtf8(reply->readAll());
qDebug() << contents;
}
else{
QString err = reply->errorString();
qDebug() << err;
}
reply->deleteLater();
});
But I received the QByteArray like this:
"{\n \"d\": {\n \"Duration\": 8,\n \"IgelId\": \"123456780XYZ\",\n \"LoadCumulLimit\": 25,\n \"Notes\": \"send from IGEL\"\n }\n}\n"

Related

How to send JSON with QTcpSocket

I can send JSON object from client to server but can not get an item from JSON object on the server.
I've tried several examples that I found when I researched I can not solve the problem.
Code to send JSON:
QJsonObject levan{
{"id",1},
{"tipo","reforço"},
{"ca", 10},
{"cb",0},
{"cc",0},
{"cd",0},
{"ce",0},
{"cf",0},
{"cg",0},
{"ch",0},
};
QJsonArray jsarray {levan};
QJsonDocument jsDoc(jsarray);
QString jsString = QString::fromLatin1(jsDoc.toJson());
this->tcpSocket->write(jsString.toLatin1());
Code to receive JSON:
QString str = this->socket->readAll();
QJsonDocument jsonResponse = QJsonDocument::fromJson(str.toLatin1());
QJsonObject jsonObject = jsonResponse.object();
QJsonArray jsonArray = jsonObject["levantamento"].toArray();
qDebug()<< jsonResponse.object().value("levan");
if (jsonResponse.array().empty()) {
qDebug() << "empty";
}
I can present JSON as text, but I cannot get the items from the JSON.
You're creating a single QJsonObject and then creating a QJsonArray using that object. So, the final output is one JSON object with a nested array with only one object. I'm not sure if you intend to have only one object in array or an array of all those objects.
And, the JSON created in request is not what you're trying to read in response. There's no key levantamento or levan in your request so you cannot find anything against those in response. You need to work on population of objects in request JSON. The below example uses some of your test data for request population and extraction in response. Hope that helps!
Example:
#include <QDebug>
#include <QString>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
int main()
{
// Request: Create JSON objects and array of objects
const auto jArrKey = "levan";
const auto jTstKey = "test";
const auto jRqObj1 = QJsonObject{ { "id", 1 } };
const auto jRqObj2 = QJsonObject{ { "cb", 0 } };
const auto jRqObj3 = QJsonObject{ { "cc", 0 } };
const auto jReqArr = QJsonArray{ jRqObj1, jRqObj2, jRqObj3 };
const auto jTstObj = QJsonObject{ { "Hello", "World" } };
const auto jReqObj = QJsonObject{ { jArrKey, jReqArr }, { jTstKey, jTstObj } };
const auto jReqDoc = QJsonDocument{ jReqObj };
const auto jReqStr = QString::fromLatin1( jReqDoc.toJson() );
qDebug() << "Request:\n" << qPrintable( jReqStr );
// Response: Read JSON document and inspect its elements
const auto jRspDoc = QJsonDocument::fromJson( jReqStr.toLatin1() );
const auto jRspObj = jRspDoc.object();
const auto jRspArr = jRspObj[ jArrKey ].toArray();
const auto jRspTst = jRspObj[ jTstKey ].toObject();
qDebug() << "Response:" << jRspArr;
qDebug() << "Test Obj:" << jRspTst;
qDebug() << ">> Hello:" << jRspTst.value( "Hello" ).toString();
return 0;
}
Output:
Request:
{
"levan": [
{
"id": 1
},
{
"cb": 0
},
{
"cc": 0
}
],
"test": {
"Hello": "World"
}
}
Response: QJsonArray([{"id":1},{"cb":0},{"cc":0}])
Test Obj: QJsonObject({"Hello":"World"})
>> Hello: "World"
You put an array as the document root, so retrieve it first:
QJsonDocument jsonResponse = QJsonDocument::fromJson(str.toLatin1());
QJsonArray jsonArray = jsonResponse.array();
Check if it's empty, if not get the first item (the levan object):
if(!jsonArray.isEmpty())
{
QJsonObject jsonObject = jsonArray.first().toObject();
You can now read the object keys, e.g.:
qDebug()<< jsonObject.value("tipo");
will print:
QJsonValue(string, "reforço")
Notice that levan is not a key, but a variable name. So this line:
jsonResponse.object().value("levan");
will never work.
If the issue persists, here's a couple of hints to debug your code.
First, check for parsing errors, this way:
QJsonParseError parseError;
QJsonDocument jsonResponse = QJsonDocument::fromJson(str.toLatin1(), &parseError);
if(parseError.error != QJsonParseError::NoError)
{
qDebug() << "Parse error: " << parseError.errorString();
}
If one occurs, just inspect the string (better: inspect it anyway), to see what came in:
qDebug() << str.toLatin1().data();
The expected output is:
[
{
"ca": 10,
"cb": 0,
"cc": 0,
"cd": 0,
"ce": 0,
"cf": 0,
"cg": 0,
"ch": 0,
"id": 1,
"tipo": "reforço"
}
]

Get bad request from Google calendar API

I'm trying to insert an event to google calendar using Qt C++.
Before inserting events, I am able to clear the primary calendar using these lines
const QUrl clearPrimaryUrl("https://www.googleapis.com/calendar/v3/calendars/primary/clear");
void GoogleWrapper::clearPrimaryCalendar()
{
QNetworkReply *reply = google.post(clearPrimaryUrl);
connect(reply, &QNetworkReply::finished, [=]()
{
reply->deleteLater();
if(reply->error() != QNetworkReply::NoError)
{
qCritical() << "Google error:" << reply->errorString();
return;
}
emit primaryCalendarCleared();
});
}
google is an QOAuth2AuthorizationCodeFlow object.
Now to insert events, I use these lines:
const QUrl insertEventUrl("https://www.googleapis.com/calendar/v3/calendars/primary/events");
void GoogleWrapper::insertEvent(const QByteArray &eventData)
{
qDebug() << eventData;
QNetworkReply *reply = google.post(insertEventUrl, eventData);
connect(reply, &QNetworkReply::finished, [=]()
{
reply->deleteLater();
if(reply->error() != QNetworkReply::NoError)
{
qCritical() << "Google error:" << reply->errorString();
return;
}
emit eventInserted();
});
}
But the output I received from qCritical was always Error transferring https://www.googleapis.com/calendar/v3/calendars/primary/events - server replied: Bad Request.
I tried output the eventData to a file and copy paste it to Google's try this API and the below json data works perfectly
{
"description": "some teacher name",
"end": {
"dateTime": "2018-12-19T11:15:00Z"
},
"location": "Room",
"start": {
"dateTime": "2018-12-19T09:30:00Z"
},
"summary": "Subject Name"
}
Anyone have any idea what I did wrong?
The issue is solved thanks to #thuga's comment.
My code was missing the line
google.setContentType(QAbstractOAuth2::ContentType::Json);

QNetworkReply Never emit a finished signal

I am writing a simple qt network application. I try to read the data from the QNetworkReply but it seems that the finished signal never emit. What happens?
QByteArray utils::Login(QString account)
{
QNetworkAccessManager* manager = new QNetworkAccessManager();
QNetworkRequest* request = new QNetworkRequest();
request->setUrl(QUrl(Urls::loginUrl));
request->setRawHeader("Host", "10.136.2.5");
request->setRawHeader("Referer", "http://10.136.2.5/jnuweb/");
request->setRawHeader("Content-Type", "application/json; charset=utf-8");
request->setRawHeader("Connection", "keep-alive");
request->setRawHeader("X-Requested-With", "XMLHttpRequest");
request->setRawHeader("Accept", "*/*");
request->setRawHeader("Accept-Encoding", "deflate");
QJsonObject* requestContent = new QJsonObject();
requestContent->insert("user", QJsonValue(account));
requestContent->insert("password", QJsonValue(Urls::initPassword));
QNetworkReply* reply = manager-> post(*request, QJsonDocument(*requestContent).toJson(QJsonDocument::Compact));
QObject::connect(reply, &QNetworkReply::finished, [=]()
{
QList<QPair<QByteArray, QByteArray>> responses = reply -> rawHeaderPairs();
qDebug() << responses;
});
}

unexpected result in parsing nested json in qt (array does not exist)

I am new in qt and I also searched in stack overflow but I can't get my answer so this not a duplicated post because all similar post have array [] but in this code i have not any array
I want to parse this complex JSON file:
{
"query": {
"lang": "en-US",
"results": {
"channel": {
"units": {
"distance": "mi",
"pressure": "in"
},
"ttl": "60",
"location": {
"city": "city",
"country": "not important",
"region": " kkk"
},
"wind": {
"chill": "99",
"direction": "180",
"speed": "14"
}
}
...(more code)
i want to get chill data but out put is " " , please help me to print chill data in qt
its a part of my code:
QNetworkAccessManager manager;
QNetworkReply *response = manager.get(QNetworkRequest(QUrl(url)));
QEventLoop event;
connect(response, SIGNAL(finished()), &event, SLOT(quit()));
event.exec();
json = response->readAll();
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
QJsonObject jsonObj = doc.object();
foreach (const QJsonValue &value, jsonObj) {
QJsonObject jsonobj = value.toObject();
qDebug() << jsonobj["chill"].toString();
}
output of qDebug()<<doc.object(); is
D/libuntitled7.so(13258): : ** QJsonObject({"query":{"count":1,"created":"2017-07-06T21:21:16Z","lang":"en-US","results":{"channel":{"astronomy":{"sunrise":"5:48 am","sunset":"8:15 pm"},"atmosphere":{"humidity":"16","pressure":"875.0","rising":"0","visibility":"16.1"},"description":"Yahoo! Weather","image":{"height":"18","link":"http://weather.yahoo.com","title":"Yahoo! Weather","url":"http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif","width":"142"},"item":{"condition":{"code":"31","date":"Fri, 07 Jul 2017 12:30 AM IRDT","temp":"85","text":"Clear"},"description":"<![CDATA[<img src=\"http://l.yimg.com/a/i/us/we/52/31.gif\"/>\n<BR/>\n<b>Forecast:</b>\n<BR /> Fri - Sunny. High: 97Low: 78\n<BR /> Sat - Sunny. High: 100Low: 79\n<BR /> Sun - Sunny. High: 101Low: 81\n<BR /> Mon - Sunny. High: 100Low: 81\n<BR /> Tue - Mostly
D/libuntitled7.so(13258): ..\untitled7\dialog2.cpp:84 (void Dialog2::on_pushButton_clicked()):
and next out put is 86
As I comment #MohammedB.B. a way is to manually search through the keys, another way is to create a function that searches through the keys, in this case I present the second form:
QJsonObject findObject(QString key, QJsonObject object){
if(object.isEmpty())
return QJsonObject();
if(object.keys().contains(key)){
return object;
}
else{
for(const QString& _key: object.keys()){
if(object[_key].isObject()){
const QJsonObject& result = findObject(key, object[_key].toObject());
if(!result.isEmpty()){
return result;
}
}
}
}
return QJsonObject();
}
QJsonValue findValuebyKey(QString key, QJsonDocument doc){
QJsonObject obj_key = findObject(key, doc.object());
return obj_key[key];
}
Example:
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
qDebug()<<findValuebyKey("chill", doc).toString();
Output:
"99"
Note:If you generate problems the "for" enable c ++ 11, you can do this by adding CONFIG += c++11 to your .pro
You need to iterate in your channels array too. Easy solution:
const QJsonDocument doc = QJsonDocument::fromJson(response->readAll().toUtf8());
// Access to "query"
const QJsonObject queryObject = doc.object();
// Access to "results"
const QJsonObject resultsObject = queryObject.value("results").toObject();
// Access to "chanels"
const QJsonObject channelsObject = resultsObject.value("channels").toObject();
// Access to "wind"
const QJsonObject windObject = channelsObject.value("wind").toObject();
// And then access to "chill"
const QJsonValue chill = windObject.value("chill");
Best practice its to create a recursive function to parse the JSON recursively.

How to read data from nested json file with Qt

I have been trying all day to read data from a json file like below with Qt but can't find a way to do it properly. I tried many things but could not get it right. Can someone help me how to get this correctly?
{
"RawData": {
"Sensors": {
"Channel1" : "10",
"Channel2" : "22",
"Channel3" : "3",
"Channel4" : "48",
"Channel5" : "1",
"Channel6" : "8",
"Channel7" : "16",
"Channel8" : "44"
}
}
}
for now my code looks something like this, though i tried many things with different manners.
QFile jsonCfg("config.json");
if (!jsonCfg.open(QIODevice::ReadOnly)) {
qWarning("Couldn't open json config file.");
return false;
}
QByteArray saveData = jsonCfg.readAll();
QJsonDocument loadDoc(QJsonDocument::fromJson(saveData));
QJsonObject config = loadDoc.object();
QVariantMap root_map = config.toVariantMap();
QVariantMap raw = root_map["RawData"].toMap();
QVariantMap sensor = raw["Sensors"].toMap();
qDebug() << "channel 1" << sensor["Channel1"].toDouble();
you can use QJsonDocument and QJsonObject just like:
QJsonParseError jsonErr;
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonStr,&jsonErr);
if(jsonErr.error == QJsonParseError::NoError)
{
QJsonObject myJsonObject = jsonDoc.object();
if(myJsonObject["RawData"].isObject())
{
//do somethine your want;
}
}