Qt/C++ get Json request - c++

I'm new to Qt Framework and I'm trying to get the list of earthquakes from EMSC api. My code looks like this:
void MainWindow::getJsonData(QNetworkAccessManager *mNetworkManager) {
const QUrl json("https://www.seismicportal.eu/fdsnws/event/1/query?limit=100&format=json");
QNetworkRequest *mNetworkRequest = new QNetworkRequest;
mNetworkRequest->setUrl(json);
mNetworkRequest->setRawHeader("Content-Type", "application/json");
mNetworkRequest->setRawHeader("Accept", "application/json");
QNetworkReply *mNetworkReply = mNetworkManager->get(*mNetworkRequest);
QString replyString = (QString) mNetworkReply->readAll();
QJsonDocument document = QJsonDocument::fromJson(replyString.toUtf8());
QJsonObject object = document.object();
QJsonValue type = object["type"].toString();
QJsonArray featuresArray = object["features"].toArray();
qDebug() << type;
qDebug() << featuresArray;
}
The problem is that I'm not getting any response from the server.

Qt is a library (not a framework) that handles all transactions asynchronously through signals and slots, so don't expect the response to be obtained synchronously.
#include <QCoreApplication>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
class Client: public QObject{
public:
void startRequest(){
const QUrl json("https://www.seismicportal.eu/fdsnws/event/1/query?limit=100&format=json");
QNetworkRequest request;
request.setUrl(json);
request.setRawHeader("Content-Type", "application/json");
request.setRawHeader("Accept", "application/json");
QNetworkReply *reply = mNetworkManager.get(request);
connect(reply, &QNetworkReply::finished, this, &Client::processRequest);
}
private:
void processRequest(){
QNetworkReply * reply = qobject_cast<QNetworkReply *>(sender());
if(!reply) return;
QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
QJsonObject object = document.object();
QJsonValue type = object["type"].toString();
QJsonArray featuresArray = object["features"].toArray();
qDebug() << type << featuresArray;
reply->deleteLater();
}
QNetworkAccessManager mNetworkManager;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Client client;
client.startRequest();
return a.exec();
}
Output:
QJsonValue(string, "FeatureCollection") QJsonArray([{"geometry":{"coordinates":[16.23,45.4,-2],"type":"Point"},"id":"20210202_0000178", ...

Here's some of my code:
QNetworkRequest req (QUrl(QString::fromStdString(url)));
req.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
if (authHeader.length() > 0) {
req.setRawHeader(QByteArray("Authorization"), QByteArray::fromStdString(authHeader));
}
QByteArray bodyArray;
if (body.length() > 0) {
bodyArray.append(QString::fromStdString(body).toUtf8());
}
QNetworkReply * reply = method(req, bodyArray);
QObject::connect(reply, &QNetworkReply::finished, [=]{
.... });

Related

Post a form with QT

I am working with a team on a C++ project using Qt. As part of our project, we have to be able to retrieve coordinates of any given address in France. The French government provivdes an API that handles that for us.
The call to the API looks like this:
curl -X POST -F data=#path/to/file.csv https://api-adresse.data.gouv.fr/search/csv/
Here is the code I wrote:
int main (int argc, char* argv[]){
QCoreApplication app(argc, argv);
QNetworkAccessManager man;
QUrl url("https://api-adresse.data.gouv.fr/search/csv/");
QNetworkRequest req(url);
QFile inputFile("<path_to_search.csv>");
inputFile.open(QIODevice::ReadOnly);
QByteArray data = inputFile.readAll();
QNetworkReply* reply = man.post(req, "data=" + data);
QObject::connect(reply, &QNetworkReply::finished, [&](){
QByteArray read = reply->readAll();
std::cout << "Reading Data:" << std::endl;
std::cout << read.toStdString() << std::endl;
reply->close();
reply->deleteLater();
app.quit();
});
return app.exec();
}
The server replies with
{"code":400,"message":"A CSV file must be provided in data field"}
So clearly I am forwarding the form incorrectly. How should I proceed?
To send information through the forms, I don't know the query section, but rather you want to use QHttpMultiPart as I show in this old post. Applying to your case the solution is:
#include <QCoreApplication>
#include <QFile>
#include <QHttpMultiPart>
#include <QNetworkAccessManager>
#include <QNetworkReply>
QHttpMultiPart *buildMultpart(const QVariantMap & data, const QMap<QString, QString> filenames){
QHttpMultiPart *multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QVariantMap::const_iterator i_data = data.constBegin();
while (i_data != data.constEnd()) {
QHttpPart postpart;
postpart.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"").arg(i_data.key()));
postpart.setBody(i_data.value().toByteArray());
multipart->append(postpart);
++i_data;
}
QMap<QString, QString>::const_iterator i_filenames = filenames.constBegin();
while (i_filenames != filenames.constEnd()) {
QFile *file = new QFile(i_filenames.value());
if(!file->open(QIODevice::ReadOnly)){
delete file;
continue;
}
QHttpPart postpart;
postpart.setHeader(QNetworkRequest::ContentDispositionHeader,
QString("form-data; name=\"%1\"; filename=\"%2\"")
.arg(i_filenames.key(), file->fileName()));
postpart.setBodyDevice(file);
multipart->append(postpart);
file->setParent(multipart);
++i_filenames;
}
return multipart;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QNetworkAccessManager manager;
QNetworkRequest request;
QUrl url("https://api-adresse.data.gouv.fr/search/csv/");
request.setUrl(url);
QMap<QString, QString> filenames;
filenames["data"] = "/path/of/file.csv";
QHttpMultiPart *multipart = buildMultpart({}, filenames);
QNetworkReply *reply = manager.post(request, multipart);
multipart->setParent(reply);
QObject::connect(reply, &QNetworkReply::finished, [reply](){
if(reply->error() == QNetworkReply::NoError){
qDebug().noquote() << reply->readAll();
}
else{
qDebug() << reply->error() << reply->errorString();
}
reply->deleteLater();
QCoreApplication::quit();
});
return a.exec();
}

QCompleter doesn't work properly with NetworkRequest finished

Qcompleter which is associated with a lineEdit doesn't work in the slot of a QNetworkRequest finished.The Qcompleter disappeared quite quickly.Each time the text in lineEdit changed a request was send.I tried a demo without other code,it also occured.
Every time the text in lineEdit was edit,a request contains the text will be send to my server.And then I want to show the content in reply in a Qcompleter.But the prompt disappears in a instant.
void MainWindow::onRequestFinished(QNetworkReply* reply){
QStringList stringList;
stringList << "test1" <<"test2"<<"test3";
QCompleter* completer = new QCompleter(stringList,this);
completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
ui->lineEdit->setCompleter(completer);
reply->deleteLater();
}
void MainWindow::on_lineEdit_textChanged(const QString &arg1)
{
QUrl url("http://www.google.com");
QNetworkRequest request;
request.setUrl(url);
manager->get(request);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow){
...
this->manager = new QNetworkAccessManager(this);
connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(onRequestFinished(QNetworkReply*)));
...
}
The logic is similar to an old answer of mine, in it a model is created that will store the information this prevents you from creating a QCompleter at every moment avoiding the problem the disappearance of the popup.
#include <QtWidgets>
#include <QtNetwork>
class SuggestModel: public QStandardItemModel
{
Q_OBJECT
public:
using QStandardItemModel::QStandardItemModel;
void search(const QString & text)
{
QNetworkRequest request = create_request(text);
if(m_reply)
m_reply->abort();
m_reply = manager.get(request);
connect(m_reply, &QNetworkReply::finished, this, &SuggestModel::onFinished);
QEventLoop loop;
connect(this, &SuggestModel::finished, &loop, &QEventLoop::quit);
loop.exec();
}
private Q_SLOTS:
void onFinished(){
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
QUrl url = reply->url();
if (reply->error() == QNetworkReply::NoError) {
QVector<QString> choices;
QByteArray response(reply->readAll());
QXmlStreamReader xml(response);
while (!xml.atEnd()) {
xml.readNext();
if (xml.tokenType() == QXmlStreamReader::StartElement)
if (xml.name() == "suggestion") {
QStringRef str = xml.attributes().value("data");
choices << str.toString();
}
}
clear();
for(const QString & choice: choices)
appendRow(new QStandardItem(choice));
}
reply->deleteLater();
Q_EMIT finished();
m_reply = nullptr;
}
Q_SIGNALS:
void finished();
private:
QNetworkRequest create_request(const QString & text){
const QString suggestUrl(QStringLiteral("http://google.com/complete/search?output=toolbar&q=%1"));
QString url = suggestUrl.arg(text);
return QNetworkRequest(url);
}
QNetworkAccessManager manager;
QNetworkReply *m_reply = nullptr;
};
class SuggestCompleter: public QCompleter{
public:
SuggestCompleter(QObject *parent=nullptr):
QCompleter(parent)
{
SuggestModel *m_model = new SuggestModel(this);
setModel(m_model);
setCompletionMode(QCompleter::UnfilteredPopupCompletion);
}
QStringList splitPath(const QString &path) const override{
if(SuggestModel * m = qobject_cast<SuggestModel *>(model()))
m->search(path);
return QCompleter::splitPath(path);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLineEdit le;
le.setCompleter(new SuggestCompleter(&le));
le.show();
return a.exec();
}
#include "main.moc"

How to make a post request to API Rest in Qt?

I wrote a piece of code that sends me, via a post request, a json to my API Rest; and works!
main.cpp
void replyFinished(QNetworkReply *reply)
{
reply->deleteLater();
qDebug() << "reply delete!";
qDebug() << "https post_request done!";
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QNetworkAccessManager *manager = new QNetworkAccessManager();
QUrl url("https://.../");
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QObject::connect(manager, &QNetworkAccessManager::finished, replyFinished);
quint8 speed = 0x12;
quint8 accelleration = 0x2b;
QString json = QString("{\"speed\":\"%1\",\"acceleration\":\"%2\"}").arg(speed).arg(accelleration);
manager->post(request, json.toUtf8());
return a.exec();
}
But when I want to integrate this piece of code in my program, it does not work. Briefly, my program gets through the SIGNAL and SLOT mechanism, a QByteArray, from which I take the data and I send them to my API Rest.
This is my Header.h
...
class Packet : public QObject
{
Q_OBJECT
public:
Packet();
public slots:
void receivePayload(QByteArray &bufferToJson);
void replyFinished(QNetworkReply *reply);
private:
QNetworkAccessManager *m_manager;
quint8 m_speed;
quint8 m_accelleration;
public:
QString json;
};
...
This is my class.cpp
Packet::Packet()
: m_manager { new QNetworkAccessManager }
{
QObject::connect(m_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
}
void Packet::replyFinished(QNetworkReply *reply)
{
reply->deleteLater();
qDebug() << "reply delete!";
qDebug() << "https post_request done!";
}
void Packet::receivePayload(QByteArray &bufferToJson){
m_speed = bufferToJson.at(0);
m_accelleration = bufferToJson.at(1);
QUrl url("https://.../");
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QString json = QString("{\"speed\":\"%1\",\"acceleration\":\"%2\"}").arg(m_speed).arg(m_accelleration);
m_manager->post(request, json.toUtf8());
}
What's the problem of my change?

Qt QNetworkAccessManager and Slot not working

i am a beginner in c++ and i am trying to retrieve data from a website using http request and to download the data in a file .
I am using the classes :
QMainWindow
QtNetwork/QNetworkAccessManager
QtNetwork/QNetworkRequest
QtNetwork/QNetworkReply
QUrl
The thing is that the file is created but there is no data in the file and i am getting an error that i don't understand . I searched through the forum found some similar kind of problems but did not understand as i am a beginner . Please help me its a school project and i am really stuck here.
Here is the httpWindow.h code
#ifndef HTTPWINDOW_H
#define HTTPWINDOW_H
#include <QMainWindow>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QUrl>
#include <QString>
class QFile;
namespace Ui {
class httpWindow;
}
class httpWindow : public QMainWindow
{
Q_OBJECT
public:
explicit httpWindow(QWidget *parent = 0);
~httpWindow();
void request(QUrl url);
private slots:
void downloadFile();
void httpFinished();
void httpReadyRead();
private:
Ui::httpWindow *ui;
QUrl url;
QNetworkAccessManager *manager;
QNetworkRequest requete;
QNetworkReply *reply;
QFile *file;
int httpGetId;
bool httpRequestAborted;
};
#endif // HTTPWINDOW_H
Here is the httpwindow.cpp
#include <QtWidgets>
#include <qnetwork.h>
#include <QString>
#include "httpwindow.h"
#include "ui_httpwindow.h"
httpWindow::httpWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::httpWindow)
{
ui->setupUi(this);
downloadFile();
}
httpWindow::~httpWindow()
{
delete ui;
}
void httpWindow::request(QUrl url)
{
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished()),
this, SLOT(httpFinished()));
//requete.setUrl(QUrl("http://fxrates.fr.forexprostools.com/index.php?force_lang=5&pairs_ids=1;3;2;4;7;5;8;6;&header-text-color=%23FFFFFF&curr-name-color=%230059b0&inner-text-color=%23000000&green-text-color=%232A8215&green-background=%23B7F4C2&red-text-color=%23DC0001&red-background=%23FFE2E2&inner-border-color=%23CBCBCB&border-color=%23cbcbcb&bg1=%23F6F6F6&bg2=%23ffffff&bid=show&ask=show&last=show&change=hide&last_update=hide"));
requete.setUrl(url);
reply = manager->get(requete);
connect(reply, SIGNAL(&reply::readyRead()), this, SLOT(httpReadyRead()));
}
void httpWindow::downloadFile()
{
QMessageBox msg ;
QUrl url("http://fxrates.fr.forexprostools.com/index.php?force_lang=5&pairs_ids=1;3;2;4;7;5;8;6;&header-text-color=%23FFFFFF&curr-name-color=%230059b0&inner-text-color=%23000000&green-text-color=%232A8215&green-background=%23B7F4C2&red-text-color=%23DC0001&red-background=%23FFE2E2&inner-border-color=%23CBCBCB&border-color=%23cbcbcb&bg1=%23F6F6F6&bg2=%23ffffff&bid=show&ask=show&last=show&change=hide&last_update=hide") ;
qDebug() << url.toString();
QFileInfo fileInfo(url.path());
//msg.setText("fileInfo = " + fileInfo);
QString fileName = "C:\\testQt\\" + fileInfo.fileName();
msg.setText("fileName = " + fileName);
if (fileName.isEmpty()){
fileName = "C:\testQt\fichier.html";
msg.setText(" création d'un nouveau fichier fichier.html ");
}
if (QFile::exists(fileName)) {
QFile::remove(fileName);
return;
}
file = new QFile(fileName);
msg.setText(" QFile::exists(fileName) == true , file : ");
if (!file->open(QIODevice::WriteOnly)) {
delete file;
file = 0;
return;
}
// schedule the request
httpRequestAborted = false;
request(url);
}
void httpWindow::httpFinished()
{
if (httpRequestAborted) {
if (file) {
file->close();
file->remove();
delete file;
file = 0;
}
reply->deleteLater();
return;
}
file->flush();
file->close();
QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (reply->error()) {
file->remove();
// QMessageBox::information(this, tr("HTTP"),
// tr("Download failed: %1.")
// .arg(reply->errorString()));
// downloadButton->setEnabled(true);
} else if (!redirectionTarget.isNull()) {
QUrl newUrl = url.resolved(redirectionTarget.toUrl());
// if (QMessageBox::question(this, tr("HTTP"),
// tr("Redirect to %1 ?").arg(newUrl.toString()),
// QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
url = newUrl;
reply->deleteLater();
file->open(QIODevice::WriteOnly);
file->resize(0);
request(url);
return;
}
reply->deleteLater();
reply = 0;
delete file;
file = 0;
}
void httpWindow::httpReadyRead()
{
// this slot gets called every time the QNetworkReply has new data.
// We read all of its new data and write it into the file.
// That way we use less RAM than when reading it at the finished()
// signal of the QNetworkReply
if (file)
file->write(reply->readAll());
}
Here is the main.cpp code
#include "httpwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
httpWindow w;
w.show();
return a.exec();
}
The errors :
can't find linker symbol for virtual table for `QMessageBox' value
found `RGB_MASK' instead
can't find linker symbol for virtual table for `QMessageBox' value
found `RGB_MASK' instead
"http://fxrates.fr.forexprostools.com/index.php?force_lang=5&pairs_ids=1;3;2;4;7;5;8;6;&header-text-color=%23FFFFFF&curr-name-color=%230059b0&inner-text-color=%23000000&green-text-color=%232A8215&green-background=%23B7F4C2&red-text-color=%23DC0001&red-background=%23FFE2E2&inner-border-color=%23CBCBCB&border-color=%23cbcbcb&bg1=%23F6F6F6&bg2=%23ffffff&bid=show&ask=show&last=show&change=hide&last_update=hide"
QObject::connect: No such signal QNetworkAccessManager::finished() in ..\ppe3_trading_test\httpwindow.cpp:24
QObject::connect: (receiver name: 'httpWindow')
QObject::connect: No such signal QNetworkReplyHttpImpl::&reply::readyRead() in ..\ppe3_trading_test\httpwindow.cpp:31
QObject::connect: (receiver name: 'httpWindow')
Please do help me its really important for my schooling .
connect(reply, SIGNAL(&reply::readyRead()), this, SLOT(httpReadyRead()));
You're mixing up old syntax and new syntax, it should be
connect(reply, SIGNAL(readyRead()), this, SLOT(httpReadyRead()));
or better yet using new syntax(Qt5 only):
connect(reply, &QNetworkReply::readyRead, this, &httpWindow::httpReadyRead);
QNetworkAccessManager doesn't have a finished() signal it has a finished(QNetworkReply*) signal, read the docs.

Web request with progress bar

This is my code (C++: Qt) for getting webpage source:
QString htmlString;
QEventLoop eventLoop;
QNetworkAccessManager mgr;
QObject::connect(&mgr, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));
QNetworkRequest req( QUrl( QString( "http://stackoverflow.com" ) ) );
QNetworkReply *reply = mgr.get(req);
eventLoop.exec();
htmlString = reply->readAll();
Is there any way to get webpage source with progress bar ?!
Write special class for this:
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QDebug>
#include <QProgressBar>
class Downloader : public QObject
{
Q_OBJECT
public:
explicit Downloader(QObject *parent = 0);
void doDownload();
public slots:
void replyFinished (QNetworkReply *reply);
void updateDownloadProgress(qint64, qint64);
private:
QNetworkAccessManager *manager;
QProgressBar *bar;
};
#endif
Cpp:
Downloader::Downloader(QObject *parent) :
QObject(parent)
{
}
void Downloader::doDownload()
{
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
QNetworkReply * rep = manager->get(QNetworkRequest(QUrl("http://qt-project.org/")));
connect(rep, SIGNAL(downloadProgress(qint64, qint64)),
this, SLOT(updateDownloadProgress(qint64, qint64)));
bar = new QProgressBar;
bar->show();
}
void Downloader::replyFinished (QNetworkReply *reply)
{
if(reply->error())
{
qDebug() << "ERROR!";
qDebug() << reply->errorString();
}
else
{
qDebug() << reply->readAll();
}
reply->deleteLater();
}
void Downloader::updateDownloadProgress(qint64 read, qint64 total)
{
qDebug() << read << total;
bar->setMaximum(total);
bar->setValue(read);
}
Usage:
Downloader down;
down.doDownload();
Main idea here is to use void QNetworkReply::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) [signal] to get progress and show this progress in QProgressBar.
And you can do this with your current code without class:
QString htmlString;
QEventLoop eventLoop;
QNetworkAccessManager mgr;
QObject::connect(&mgr, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));
QProgressBar *bar = new QProgressBar;
bar->show();
QNetworkRequest req( QUrl( QString( "http://stackoverflow.com" ) ) );
QNetworkReply *reply = mgr.get(req);
QObject::connect(reply,&QNetworkReply::downloadProgress,[=](qint64 bytesReceived, qint64 bytesTotal) {//with lambda
bar->setMaximum(bytesTotal);
bar->setValue(bytesReceived);
});
eventLoop.exec();
htmlString = reply->readAll();
qDebug() << htmlString;
I used here C++11 (CONFIG += c++11 to .pro file) and new syntax of signals and slots.