Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RESTful API requests using Qt

I'm trying to get example found from this link to work.

GET and DELETE methods are working but I have some issue with PUT and POST. I get server replied: Bad Request. With qDebug() I get this error:

QNetworkReply::NetworkError(ProtocolInvalidOperationError)

To httprequestworker.cpp, I have changed request type to:

request_content.append("Content-Type: application/fhir+json");

Here is my function for getting contents of JSON file from computer and executing the whole input of request for the server:

void MainWindow::on_pushButton_clicked()
{
    QString url_str = "http://hapi.fhir.org/baseDstu3/Patient/4705560";

    HttpRequestInput input(url_str, "PUT");

    QString settings;
    QFile file;

    file.setFileName("C:/Users/Lauri/Desktop/FHIR/Omia testeja/themostsimplepatientJSON.json");
    file.open(QIODevice::ReadOnly | QIODevice::Text);
    settings = file.readAll();
    file.close();

    settings.remove(QRegExp("[\\n]"));
    qDebug() << settings;
    settings.toUtf8();
    input.add_var("key1", settings);


    HttpRequestWorker *worker = new HttpRequestWorker(this);
    connect(worker, SIGNAL(on_execution_finished(HttpRequestWorker*)), this, SLOT(handle_result(HttpRequestWorker*)));
    worker->execute(&input);
}

Here is the simple JSON I want to upload:

{
  "resourceType": "Patient",
  "text": {
    "status": "generated",
    "div": "<div xmlns='http://www.w3.org/1999/xhtml'>This is a test patient<a name='mm'/></div>"
  },
  "name": [
    {
      "use": "usual",
      "prefix": [
        "Mr"
      ],
      "given": [
        "Teppo",
        "Testi"
      ],
      "family": "Testinen"
    }
  ],
  "telecom": [
    {
      "value": "123456789",
      "system": "phone",
      "use": "home"
    }
  ],
  "gender": "male",
  "birthDate": "2018-08-21"
}

JSON file should be right because I have been able to POST and PUT with postman and other tools. Is there something obvious that I'm missing?

Captures from postman:

PUT Headers

PUT Body

POST Headers

POST Body

With qDebug() I can see that reading JSON is successful. I have been trying to find solution for ProtocolInvalidOperationError with no success.

like image 700
Lauri Avatar asked Aug 13 '18 06:08

Lauri


1 Answers

the class HttpRequestWorker does not support the sending of json, so I will not use it in the example. For this case I will use QNetworkAccessManager directly:

In the case of PUT you must add the id in the .json, so you can modify the file or do it by code, in this case use the second case:

PUT:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QNetworkAccessManager>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();
    void onManagerFinished(QNetworkReply *reply);

private:
    Ui::MainWindow *ui;
    QNetworkAccessManager manager;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageBox>
#include <QNetworkReply>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(&manager, &QNetworkAccessManager::finished, this, &MainWindow::onManagerFinished);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    QNetworkRequest request(QUrl("http://hapi.fhir.org/baseDstu3/Patient/4705560"));
    request.setRawHeader("Content-Type", "application/fhir+json");
    QFile file("/path/of/themostsimplepatientJSON.json");
    if(file.open(QIODevice::ReadOnly)){
        QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
        QJsonObject obj = doc.object();
        obj["id"] = "4705560"; // add ID
        doc.setObject(obj);
        manager.put(request, doc.toJson());
    }
}

void MainWindow::onManagerFinished(QNetworkReply *reply)
{
    qDebug()<< reply->readAll();
}

output:

"{\n  \"resourceType\": \"OperationOutcome\",\n  \"text\": {\n    \"status\": \"generated\",\n    \"div\": \"<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\"><h1>Operation Outcome</h1><table border=\\\"0\\\"><tr><td style=\\\"font-weight: bold;\\\">INFORMATION</td><td>[]</td><td><pre>Successfully created resource \\\"Patient/4705560/_history/7\\\" in 5ms</pre></td>\\n\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\n\\t\\t\\t</tr>\\n\\t\\t\\t<tr>\\n\\t\\t\\t\\t<td style=\\\"font-weight: bold;\\\">INFORMATION</td>\\n\\t\\t\\t\\t<td>[]</td>\\n\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\t<td><pre>No issues detected during validation</pre></td>\\n\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\n\\t\\t\\t</tr>\\n\\t\\t</table>\\n\\t</div>\"\n  },\n  \"issue\": [\n    {\n      \"severity\": \"information\",\n      \"code\": \"informational\",\n      \"diagnostics\": \"Successfully created resource \\\"Patient/4705560/_history/7\\\" in 5ms\"\n    },\n    {\n      \"severity\": \"information\",\n      \"code\": \"informational\",\n      \"diagnostics\": \"No issues detected during validation\"\n    }\n  ]\n}"

POST:

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFile>
#include <QMessageBox>
#include <QNetworkReply>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(&manager, &QNetworkAccessManager::finished, this, &MainWindow::onManagerFinished);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    QNetworkRequest request(QUrl("http://hapi.fhir.org/baseDstu3/Patient")); // without ID
    request.setRawHeader("Content-Type", "application/fhir+json");
    QFile file("/path/of/themostsimplepatientJSON.json");
    if(file.open(QIODevice::ReadOnly)){
        QByteArray ba = file.readAll();
        manager.post(request, ba);
    }
}

void MainWindow::onManagerFinished(QNetworkReply *reply)
{
    qDebug()<< reply->readAll();
}

output:

"{\n  \"resourceType\": \"OperationOutcome\",\n  \"text\": {\n    \"status\": \"generated\",\n    \"div\": \"<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\"><h1>Operation Outcome</h1><table border=\\\"0\\\"><tr><td style=\\\"font-weight: bold;\\\">INFORMATION</td><td>[]</td><td><pre>Successfully created resource \\\"Patient/4728838/_history/1\\\" in 3ms</pre></td>\\n\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\n\\t\\t\\t</tr>\\n\\t\\t\\t<tr>\\n\\t\\t\\t\\t<td style=\\\"font-weight: bold;\\\">INFORMATION</td>\\n\\t\\t\\t\\t<td>[]</td>\\n\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\t<td><pre>No issues detected during validation</pre></td>\\n\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\n\\t\\t\\t</tr>\\n\\t\\t</table>\\n\\t</div>\"\n  },\n  \"issue\": [\n    {\n      \"severity\": \"information\",\n      \"code\": \"informational\",\n      \"diagnostics\": \"Successfully created resource \\\"Patient/4728838/_history/1\\\" in 3ms\"\n    },\n    {\n      \"severity\": \"information\",\n      \"code\": \"informational\",\n      \"diagnostics\": \"No issues detected during validation\"\n    }\n  ]\n}"

The complete example can be found in the following link

like image 159
eyllanesc Avatar answered Oct 12 '22 12:10

eyllanesc