Qt-ohjelmointi
Qt HTTP

Kun Qt-sovelluksessa halutaan käyttää HTTP-protokollaa, on projektiin lisättävä QtNetwork-moduuli seuraavasti:
qmake:
pro-tiedostoon

QT +=network

CMake:
CMakeLists-tiedostoon
find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets Network)
PRIVATE
    Qt6::Network

QtNetwork on Qt-kirjaston moduuli, joka tarjoaa kehittäjille työkaluja verkko-ohjelmointiin ja verkkoyhteyksien hallintaan Qt-sovelluksissa. Moduuli sisältää muun muassa seuraavat luokat:

LuokkaSelite
QNetworkAccessManagerQNetworkAccessManager on QtNetwork-moduulin luokka, joka tarjoaa pääsyn verkkoresursseihin ja hallinnoi verkkopyyntöjä. Sen avulla voidaan helposti luoda ja käsitellä HTTP-pyyntöjä ja -vastauksia Qt-sovelluksissa.
QNetworkRequestQNetworkRequest on QtNetwork-moduulin luokka, joka edustaa HTTP- tai muuta verkko-pyyntöä.
QNetworkReplyQNetworkReply on QtNetwork-moduulin luokka, josta luodun olion avulla päästään käsiksi http-response dataan.
QJsonDocumentQJsonDocument on Qt:n luokka, jota käytetään JSON-objektien ja -taulukoiden (QJsonObject ja QJsonArray) lukemiseen ja kirjoittamiseen.
QJsonArrayQJsonArray-luokan avulla voidaan käsitellä JSON-array-tyyppistä dataa.
QJsonObjectQJsonObject luokan avulla voidaan käsitellä JSON-object tyyppistä dataa.

HTTP-responsen data luetaan tämän sivun esimerkeissä QByteArray-luokan olioon.

HTTP request
HTTP liikenne toimii asynkronisesti, joten käytetään Signal-Slot systeemiä. Alla lähetetään HTTP GET metodilla request.
Ei autentikointia
QString site_url="http://localhost:3000/book";
QNetworkRequest request(site_url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished, this, &CurrentClassName::getBookSlot);
reply = manager->get(request);
Kun HTTP response saapuu, QNetworkAccessManager emittoi finished signaalin, joka on edellä kytketty getBookSlot-slottiin.
Webtoken autentikointi
Edellinen esimerkki, jos API vaatii webtokenia
QString site_url="http://localhost:3000/book";
QNetworkRequest request(site_url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

//WEBTOKEN ALKU
    //Onnistuneen loginin seurauksena saadaan arvo muuttujalle webToken, jonka 
    //tietotyyppi on QByteArray ja sen eteen asetetaan merkkijono Bearer 
QByteArray myToken="Bearer "+webToken;
request.setRawHeader(QByteArray("Authorization"),(myToken));
//WEBTOKEN LOPPU

manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished, this, &CurrentClassName::getBookSlot);
reply = manager->get(request);
Huom! Varsinaisen tokenin (eli webToken) eteen on siis kirjoitettava sana Bearer.
Http responsen käsittely

Edellä siis tehtiin http-request ja finished-signaali kytkettiin slottiin getBookSlot. Nyt siis response käsitellään tuossa slotissa.

Responsena JSON-objekti
Mikäli edellä esitetty HTTP response sisältäisi JSON objektin voitaisiin se käsitellä seuraavalla koodilla.
void MainWindow::getBookSlot (QNetworkReply *reply)
{
    QByteArray response_data=reply->readAll();
    // Muunnetaan vastaus QByteArray-tyyppisestä JSON-dokumentiksi
    QJsonDocument json_doc = QJsonDocument::fromJson(response_data);
    // Muunnetaan JSON-dokumentti JSON-objektiksi
    QJsonObject json_obj = json_doc.object();
   // Käsitellään JSON-objektia
    
    reply->deleteLater();
    manager->deleteLater();
}
Responsena JSON-array
Mikäli edellä esitetty HTTP response sisältäisi JSON-arrayn voitaisiin se käsitellä seuraavalla koodilla.
void MainWindow::getBookSlot (QNetworkReply *reply)
{
    QByteArray response_data=reply->readAll();
     // Muunnetaan vastaus QByteArray-tyyppisestä JSON-dokumentiksi
    QJsonDocument json_doc = QJsonDocument::fromJson(response_data);
    // Muunnetaan JSON-dokumentti JSON-arrayksi
    QJsonArray json_array = json_doc.array();
    // Käsitellään JSON-arraytä

    reply->deleteLater();
    manager->deleteLater();
}    
deleteLater
deleteLater()-metodia käytetään yleensä Qt-sovelluksissa tilanteissa, joissa halutaan poistaa dynaamisesti luotu olio turvallisesti. Tämä metodi asettaa olion poistettavaksi myöhemmin Qt:n tapahtumakäsittelyjärjestelmän kautta, mikä varmistaa, että olio poistetaan oikeassa kohtaa ohjelman suoritusjärjestystä. Tämä on erityisen tärkeää, jos olio on sidottu muihin osiin ohjelmaa, kuten signaaleihin.
fromJson-metodi

fromJson metodia, voidaan kutsua myös antamalla QJsonParseError-viite seuraavasti:

QJsonParseError parseError;
QJsonDocument json_doc = QJsonDocument::fromJson(response_data, &parseError);
Silloin voidaan tarkistaa tapahtuiko virhe seuraavasti:
if (parseError.error != QJsonParseError::NoError) {
    qWarning() << "JSON parsing error:" << parseError.errorString();
    // Tässä vaiheessa json_doc ei ole kelvollinen
}

JSON-objektin kenttiin päästään käsiksi seuraavasti:

int book_id = json_obj["id_book"].toInt();
QString book_name = json_obj["name"].toString();

JSON-array:tä voidaan käsitellä seuraavalla foreach-loopilla:

foreach (const QJsonValue &value, json_array) {
    // Toimenpiteet
}

Jos haluat päästä käsiksi JSON-arrayn yksittäisen objektin kenttään, voit käyttää seuraavaa rakennetta

QString book_name = json_array.at(0)["name"].toString();
Edellä QStringiin nimeltään book_name sijoitetaan ensimmäisen objektin (at(0)) name kentän arvo.

JSON-datan käsittely C++-olioiden avulla

Käytännössä JSON-data kannattaa usein mäpätä C++-olioiksi, jolloin sitä on helpompi käsitellä. Esimerkiksi edellisten esimerkkien tapauksessa voisi luoda Book-luokan seuraavilla koodeilla:

#ifndef BOOK_H
#define BOOK_H

#include <qjsonobject.h>

class Book
{
public:
    int id;
    QString name;
    QString author;

    static Book mapJson(const QJsonObject &json);
};

#endif // BOOK_H
#include "book.h"

Book Book::mapJson(const QJsonObject &json) {
    Book book;
    book.id = json["id_book"].toInt();
    book.name = json["name"].toString();
    book.author = json["author"].toString();
    return book;
}

Jos http-responsena saadaan JSON-objekti voidaan luoda Book-luokan olio seuraavasti:

Book book = Book::mapJson(json_obj);

Jos http-responsena saadaan json array voidaan luoda Book-olioita sisältävä QVector seuraavasti:

QVector<Book> bookList;

    for (const QJsonValue &value : json_array) {
        if (value.isObject()) {
            Book book = Book::mapJson(value.toObject());
            bookList.append(book);
        }
    }

Edellä metodi mapJson määriteltiin staattiseksi, jotta:

  1. Se ei tarvitse olemassaolevaa oliota toimiakseen
  2. Sen on tarkoitus luoda uusi Book-olio annetusta json-objektista
Kyseessä on siis ns. factory-metodi.