{"id":30265,"date":"2025-02-03T05:00:00","date_gmt":"2025-02-03T04:00:00","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=30265"},"modified":"2025-01-27T12:56:56","modified_gmt":"2025-01-27T11:56:56","slug":"qt-i-rest-api-tworzenie-aplikacji-sieciowych","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/qt-i-rest-api-tworzenie-aplikacji-sieciowych\/","title":{"rendered":"Qt i REST API \u2013 tworzenie aplikacji sieciowych"},"content":{"rendered":"\n<p>Framework Qt cz\u0119sto kojarzony jest g\u0142\u00f3wnie z tworzeniem graficznego interfejsu u\u017cytkownika. Jednak to pot\u0119\u017cne narz\u0119dzie ma znacznie wi\u0119cej do zaoferowania, co cz\u0119sto umyka uwadze wielu in\u017cynier\u00f3w.&nbsp;Qt wyposa\u017cony jest w szereg modu\u0142\u00f3w rozszerzaj\u0105cych jego funkcjonalno\u015b\u0107 poza GUI, takich jak:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>obs\u0142uga sieci,<\/li>\n\n\n\n<li>grafika 3D,<\/li>\n\n\n\n<li>manipulacja danymi w formacie JSON, lub XML.<\/li>\n<\/ul>\n\n\n\n<p>W dzisiejszym artykule skoncentrujemy si\u0119 na mniej oczywistym <strong>aspekcie Qt \u2013 jego zdolno\u015bciach do tworzenia aplikacji sieciowych<\/strong>. Przejdziemy przez proces tworzenia ma\u0142ego klienta REST API oraz mini serwera HTTP, pokazuj\u0105c, jak te zaawansowane funkcje mog\u0105 by\u0107 wykorzystane w praktycznych projektach programistycznych.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>REST API<\/strong><\/h2>\n\n\n\n<p>Na pocz\u0105tku przypomnijmy sobie, czym jest REST (czyli Representation State Transfer).<\/p>\n\n\n\n<p>REST to styl architektury&nbsp;oprogramowania zapewniaj\u0105cy skalowalno\u015b\u0107, prostot\u0119, niezale\u017cno\u015b\u0107 komponent\u00f3w, a tak\u017ce efektywno\u015b\u0107 w przesy\u0142aniu danych mi\u0119dzy klientem a serwerem.<\/p>\n\n\n\n<p>Cechuje si\u0119:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>bezstanowo\u015bci\u0105&nbsp;(statelessness),<\/li>\n\n\n\n<li>oddzieleniem klienta od serwera (client-server separation),<\/li>\n\n\n\n<li>jednolitym interfejsem (uniform interface),<\/li>\n\n\n\n<li>bezpiecznym po\u0142\u0105czeniem przez warstw\u0119,<\/li>\n\n\n\n<li>obs\u0142ug\u0105 pami\u0119ci podr\u0119cznej,<\/li>\n\n\n\n<li>systemem warstwowym.<\/li>\n<\/ul>\n\n\n\n<p>Z poj\u0119ciem REST API najcz\u0119\u015bciej \u0142\u0105czony jest protok\u00f3\u0142 HTTP (Hypertext Transfer Protocol) wykorzystywany w us\u0142ugach internetowych. Bazuj\u0105c na bezstanowo\u015bci architektury, ka\u017cde \u017c\u0105danie HTTP do serwera musi zawiera\u0107 wszystkie niezb\u0119dne informacje do jego zrozumienia i wykonania, bez potrzeby zachowywania wcze\u015bniejszego kontekstu sesji. REST API korzystaj\u0105ce z protoko\u0142u HTTP bazuje na metodach HTTP. <\/p>\n\n\n\n<p>W\u015br\u00f3d nich najcz\u0119\u015bciej u\u017cywanymi s\u0105:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>GET \u2013 wykorzystywana do pobierania danych o zasobach,<\/li>\n\n\n\n<li>POST \u2013 tworzy nowy zas\u00f3b, wykorzystywana r\u00f3wnie\u017c do innych operacji, gdy nie mieszcz\u0105 si\u0119 one w ramach pozosta\u0142ych metod,<\/li>\n\n\n\n<li>DELETE&nbsp;\u2013 usuwa okre\u015blony zas\u00f3b,<\/li>\n\n\n\n<li>PUT&nbsp;\u2013 modyfikuje\/aktualizuje dany zas\u00f3b na podstawie identyfikatora.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Qt a us\u0142ugi sieciowe<\/strong><\/h2>\n\n\n\n<p>W Qt dost\u0119p do us\u0142ug sieciowych jest realizowany przez bibliotek\u0119 <code>Network<\/code>. Dzi\u0119ki klasom zawartym w tym module, programowanie sieciowe oparte na takich protoko\u0142ach jak HTTP, TCP czy UDP staje si\u0119 prostsze i bardziej intuicyjne.<\/p>\n\n\n\n<p>Dodanie modu\u0142u do projektu jest bardzo \u0142atwe. Je\u015bli projekt jest budowany w oparciu o <code>qmake<\/code>, wystarczy doda\u0107 nast\u0119puj\u0105c\u0105 linie:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n QT += network\n<\/pre><\/div>\n\n\n<p>Natomiast w przypadku CMake realizuje si\u0119 to w nast\u0119puj\u0105cy spos\u00f3b:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nfind_package(Qt6 REQUIRED COMPONENTS Network)\ntarget_link_libraries(mytarget PRIVATE Qt6::Network)\n<\/pre><\/div>\n\n\n<p>Jednym z atut\u00f3w biblioteki Qt jest bogata dokumentacja, o ca\u0142ej zawarto\u015bci modu\u0142u sieciowego mo\u017cna przeczyta\u0107 w <a href=\"https:\/\/doc.qt.io\/qt-6\/network.html\" target=\"_blank\" rel=\"noopener\" title=\"\" rel=\"nofollow\" >Network Programming API<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Klient REST API<\/strong><\/h2>\n\n\n\n<p>W pierwszej kolejno\u015bci zaimplementujemy klienta REST API wysy\u0142aj\u0105cego \u017c\u0105dania: GET, POST i DELETE oraz wy\u015bwietlaj\u0105cego odpowiedzi od serwera. Do komunikacji sieciowej wykorzystamy klas\u0119 <code>QNetworkAccessManager<\/code> umo\u017cliwiaj\u0105c\u0105 wysy\u0142anie \u017c\u0105da\u0144 HTTP oraz odbieranie odpowiedzi z serwera w spos\u00f3b asynchroniczny, czyli nieblokuj\u0105cy interfejsu u\u017cytkownika oraz p\u0119tli g\u0142\u00f3wnej aplikacji. Ponadto przechowuje ona wsp\u00f3ln\u0105 konfiguracj\u0119 i ustawienia dla wysy\u0142anych \u017c\u0105da\u0144. Zaleca si\u0119, aby na ca\u0142\u0105 aplikacj\u0119 stworzona by\u0142a tylko jedna instancja <code>QNetworkAccessManager<\/code>.<\/p>\n\n\n\n<p>Przyk\u0142adowa implementacja klienta z wykorzystaniem klasy <code>QNetworkAccessManager<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n#include &amp;lt;QtNetwork\/QNetworkAccessManager&gt;\n#include &amp;lt;QtNetwork\/QNetworkReply&gt;\n#include &amp;lt;QJsonDocument&gt;\n\nconst QString JSONContentTypeHeader = &quot;application\/json&quot;;\n\nclass RESTClient : public QObject {\n    Q_OBJECT\npublic:\n    RESTClient(QObject * parent = nullptr) : QObject(parent) {\n        m_manager = new QNetworkAccessManager(this);\n        connect(m_manager, &amp;amp;QNetworkAccessManager::finished, this, &amp;amp;RESTClient::onFinished);\n    }\n\n    void sendGetRequest(const QUrl &amp;amp;url) {\n        QNetworkRequest request(url);\n        m_manager-&gt;get(request);\n    }\n\n    void sendPostRequest(const QUrl &amp;amp;url, const QByteArray &amp;amp;data) {\n        QNetworkRequest request(url);\n        request.setHeader(QNetworkRequest::ContentTypeHeader, JSONContentTypeHeader);\n        m_manager-&gt;post(request, data);\n    }\n\n    void sendDeleteRequest(const QUrl &amp;amp;url) {\n        QNetworkRequest request(url);\n        m_manager-&gt;deleteResource(request);\n    }\n\nprivate slots:\n    void onFinished(QNetworkReply *reply) {\n        if (reply-&gt;error() == QNetworkReply::NoError) {\n            qDebug() &amp;lt;&amp;lt; &quot;Response received:&quot; &amp;lt;&amp;lt; reply-&gt;readAll();\n        } else {\n            qDebug() &amp;lt;&amp;lt; &quot;Error:&quot; &amp;lt;&amp;lt; reply-&gt;errorString();\n        }\n        reply-&gt;deleteLater();\n    }\n\nprivate:\n    QNetworkAccessManager *m_manager;\n};\n<\/pre><\/div>\n\n\n<p>W powy\u017cszym przyk\u0142adzie klasa <code>RESTClient<\/code> odpowiedzialna jest za wysy\u0142anie \u017c\u0105da\u0144 przez zaimplementowane metody:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>sendGetRequest \u2013 wysy\u0142a \u017c\u0105danie typu GET,<\/li>\n\n\n\n<li>sendPostRequest \u2013 wysy\u0142a \u017c\u0105danie typu POST,<\/li>\n\n\n\n<li>sendDeleteRequest \u2013 wysy\u0142a \u017c\u0105danie typu DELETE.<\/li>\n<\/ul>\n\n\n\n<p>Jak mo\u017cna \u0142atwo zauwa\u017cy\u0107, stworzenie i wys\u0142anie \u017c\u0105dania do serwera jest bardzo proste. Do ka\u017cdego z typ\u00f3w zapytania klasa <code>QNetworkAccessManager<\/code>&nbsp;posiada odpowiednie metody. Programista odpowiedzialny jest wy\u0142\u0105cznie za przygotowanie poprawnego \u017c\u0105dania oraz obs\u0142ug\u0119 wyniku otrzymanego z serwera.<\/p>\n\n\n\n<p>Gdy klasa <code>QNetworkAccessManager<\/code>&nbsp;otrzymuje odpowied\u017a z serwera, emituje sygna\u0142 <code>finished(QNetworkReply *reply)<\/code>, przekazuj\u0105c wska\u017anik do tej odpowiedzi jako argument. W slocie <code>onFinished(QNetworkReply *reply)<\/code> sprawdzane s\u0105 szczeg\u00f3\u0142y odpowiedzi, w tym zawarto\u015b\u0107 oraz ewentualne b\u0142\u0119dy serwera, co umo\u017cliwia odpowiednie reagowanie na otrzymane dane. W tym przypadku programista jest zobowi\u0105zany do zarz\u0105dzania pami\u0119ci\u0105 i usuni\u0119cia wska\u017anika <code>reply<\/code>.<\/p>\n\n\n\n<p>Do tego wykorzystana zosta\u0142a metoda <code>QObject::deleteLater()<\/code>, kt\u00f3ra sprawia, \u017ce obiekt jest niszczony przy nast\u0119pnej iteracji p\u0119tli g\u0142\u00f3wnej. Jest to zalecany spos\u00f3b usuwania obiekt\u00f3w pochodz\u0105cych od klasy <code>QObject<\/code>. Stosuj\u0105c <code>deleteLater<\/code>&nbsp; zamiast <code>delete<\/code>, unikamy sytuacji, w kt\u00f3rej usuni\u0119to obiekt, natomiast zdarzenia z nim zwi\u0105zane pozosta\u0142y do obs\u0142u\u017cenia w aktualnej iteracji p\u0119tli. <\/p>\n\n\n\n<p>W obecnej implementacji klasy <code>RESTClien<\/code><em><code>t<\/code><\/em> ca\u0142a odpowiedzialno\u015b\u0107 za odbi\u00f3r i przetwarzanie danych z serwera spoczywa na niej samej, co mo\u017ce nie by\u0107 optymalne. Z tego powodu planujemy zmodyfikowa\u0107 implementacj\u0119 tak, aby to klasa wykorzystuj\u0105ca <code>RESTClient<\/code> zarz\u0105dza\u0142a przetwarzaniem otrzymanych informacji. To pozwoli na wi\u0119ksz\u0105 elastyczno\u015b\u0107 i lepsze zarz\u0105dzanie odpowiedziami z serwera.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n#include &amp;lt;QtNetwork\/QNetworkAccessManager&gt;\n\nconst QString JSONContentTypeHeader = &quot;application\/json&quot;;\n\nclass RESTClient : public QObject {\n    Q_OBJECT\npublic:\n    RESTClient(QObject * parent = nullptr) : QObject(parent) {\n        m_manager = new QNetworkAccessManager(this);\n    }\n\n    QNetworkReply* sendGetRequest(const QUrl &amp;amp;url) {\n        QNetworkRequest request(url);\n        return m_manager-&gt;get(request);\n    }\n\n    QNetworkReply* sendPostRequest(const QUrl &amp;amp;url, const QByteArray &amp;amp;data) {\n        QNetworkRequest request(url);\n        request.setHeader(QNetworkRequest::ContentTypeHeader, JSONContentTypeHeader);\n        return m_manager-&gt;post(request, data);\n    }\n\n    QNetworkReply* sendDeleteRequest(const QUrl &amp;amp;url) {\n        QNetworkRequest request(url);\n        return m_manager-&gt;deleteResource(request);\n    }\n\nprivate:\n    QNetworkAccessManager *m_manager;\n};\n<\/pre><\/div>\n\n\n<p>Po wprowadzonych zmianach klasa <code>RESTClient<\/code> pe\u0142ni jedynie funkcj\u0119 wysy\u0142ania \u017c\u0105da\u0144, a obiekt zawieraj\u0105cy odpowied\u017a jest bezpo\u015brednio zwracany do warstwy wy\u017cszej, kt\u00f3ra korzysta z klienta.<\/p>\n\n\n\n<p>Przyk\u0142ad u\u017cycia:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n#include &amp;lt;QCoreApplication&gt;\n\n#include &quot;RESTClient.h&quot;\n#include &amp;lt;QNetworkReply&gt;\n\nint main(int argc, char *argv&#x5B;])\n{\n    QCoreApplication a(argc, argv);\n\n    RESTClient client;\n    auto reply = client.sendGetRequest(QUrl(&quot;http:\/\/httpbin.org\/get&quot;));   \n    QObject::connect(reply, &amp;amp;QNetworkReply::finished, &#x5B;reply](){\n        qDebug() &amp;lt;&amp;lt; reply-&gt;readAll();\n        reply-&gt;deleteLater();   \n        qApp-&gt;exit();\n    });\n\n    return a.exec();\n}\n\n#include &quot;main.moc&quot;\n<\/pre><\/div>\n\n\n<p>G\u0142\u00f3wn\u0105 zalet\u0105 tej implementacji jest u\u017cycie sygna\u0142u <code>QNetworkReply::finished() <\/code>zamiast <code>QNetworkAccessManager::finished(QNetworkReply *)<\/code>. Bezpo\u015brednie dzia\u0142anie na obiektach klasy <code>QNetworkReply<\/code>&nbsp;pozwala na rozdzielenie logiki aplikacji. Jednocze\u015bnie sprawiaj\u0105c, \u017ce mo\u017cliwa jest obs\u0142uga odpowiedzi przez bardziej rozbudowanie obiekty, co powoduje, \u017ce kod staje si\u0119 bardziej elastyczny i czytelny.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>QNetworkRequest<\/strong><\/h2>\n\n\n\n<p>W powy\u017cszych&nbsp; przyk\u0142adach podczas wysy\u0142ania zapyta\u0144 do serwera wykorzystywali\u015bmy klas\u0119 <code>QNetworkRequest<\/code>. Reprezentuje ona \u017c\u0105danie sieciowe w&nbsp;komunikacji&nbsp;po HTTP&nbsp;w Qt.<\/p>\n\n\n\n<p>Do tej pory u\u017cywali\u015bmy jej w do\u015b\u0107 prosty spos\u00f3b poprzez utworzenie obiektu i przekazywanie URL&nbsp;do konstruktora, tak jak poni\u017cej:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nQUrl url(&quot;http:\/\/httpbin.org\/get&quot;);\nQNetworkRequest request(url);\n<\/pre><\/div>\n\n\n<p>Klasa <code>QNetworkRequest<\/code> umo\u017cliwia ustawianie nag\u0142\u00f3wk\u00f3w HTTP, kt\u00f3re mog\u0105 zawiera\u0107 dodatkowe informacje takie jak typ danych, dane autoryzacji, wersj\u0119 API oraz wiele innych. W aplikacjach wykorzystuj\u0105cych REST API do\u015b\u0107 cz\u0119sto dodatkowe nag\u0142\u00f3wki s\u0105 wymagane do prawid\u0142owego przetworzenia zapytania przez system.<\/p>\n\n\n\n<p>Nag\u0142\u00f3wki dodaje si\u0119 do \u017c\u0105dania poprzez u\u017cycie metody <code>setHeader<\/code>, kt\u00f3ra jako pierwszy argument przyjmuje typ wyliczeniowy&nbsp;<code>QNetworkRequest::KnownHeaders<\/code>, natomiast drugim argumentem jest przesy\u0142ana warto\u015b\u0107. <code>QNetworkRequest::KnownHeaders<\/code> zawiera najbardziej popularne i najcz\u0119\u015bciej wykorzystywane nag\u0142\u00f3wki HTTP. Do dodawania nietypowych nag\u0142\u00f3wk\u00f3w, kt\u00f3re nie s\u0105 zawarte w typie wyliczeniowym, u\u017cywamy metody <code>setRawHeader<\/code>, gdzie pierwszym argumentem jest nazwa przesy\u0142anego nag\u0142\u00f3wka.<\/p>\n\n\n\n<p>Przyk\u0142ad ustawiania nag\u0142\u00f3wk\u00f3w:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nQNetworkRequest request(QUrl(&quot;http:\/\/httpbin.org\/get&quot;));\nrequest.setHeader(QNetworkRequest::ContentTypeHeader, &quot;application\/json&quot;);\nrequest.setRawHeader(&quot;Authorization&quot;, &quot;BearerAccessToken&quot;);\n<\/pre><\/div>\n\n\n<p>Ponadto mo\u017cliwe jest ustawianie dodatkowych atrybut\u00f3w w zapytaniach. Atrybuty odpowiedzialne s\u0105 za wiele przydatnych funkcji takich jak:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>ustawienie priorytetu \u017c\u0105dania,<\/li>\n\n\n\n<li>kontrola nad polityk\u0105 przekierowa\u0144,<\/li>\n\n\n\n<li>obs\u0142uga cache,<\/li>\n\n\n\n<li>korzystanie z atrybut\u00f3w specyficznych dla protoko\u0142u.<\/li>\n<\/ul>\n\n\n\n<p>Wszystkie reprezentowane s\u0105&nbsp;przez typ wyliczeniowy <code>QNetworkRequest::Attribute<\/code>, a ich warto\u015bci przechowywane s\u0105 w klasie <code>QVariant<\/code>, <a href=\"https:\/\/doc.qt.io\/qt-6\/qnetworkrequest.html#Attribute-enum\" target=\"_blank\" rel=\"noopener\" title=\"\" rel=\"nofollow\" >szczeg\u00f3\u0142y opisane s\u0105 w dokumentacji<\/a>.<\/p>\n\n\n\n<p>Ustawianie atrybut\u00f3w \u017c\u0105dania jest tak samo proste jak dodawanie nag\u0142\u00f3wk\u00f3w. U\u017cywamy do tego metody <code>setAttribute<\/code>, przyk\u0142ad:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nQNetworkRequest request(QUrl(&quot;http:\/\/httpbin.org\/get&quot;));\nrequest.setAttribute(QNetworkRequest::Http2DirectAttribute, true);\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Serwer HTTP<\/strong><\/h2>\n\n\n\n<p>Do napisania w\u0142asnego serwera obs\u0142uguj\u0105cego \u017c\u0105dania HTTP skorzystamy z klasy <code>QHttpServer<\/code> nale\u017c\u0105cej do modu\u0142u <code>HttpServer<\/code>.<\/p>\n\n\n\n<p><code>QHttpServer<\/code> posiada w swojej funkcjonalno\u015bci:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Routing \u017c\u0105da\u0144 \u2013 pozwala zdefiniowa\u0107, jak serwer powinien reagowa\u0107 na r\u00f3\u017cnego rodzaju \u017c\u0105dania, takie jak GET, POST, DELETE itp. Wykorzystuje si\u0119 do tego metod\u0119 <code>route()<\/code>, kt\u00f3ra przyjmuje \u015bcie\u017ck\u0119, metod\u0119 HTTP i funkcj\u0119 obs\u0142ugi, co umo\u017cliwia elastyczne zarz\u0105dzanie logik\u0105 biznesow\u0105.<\/li>\n\n\n\n<li>Obs\u0142ug\u0119 odpowiedzi \u2013 dla ka\u017cdego typu \u017c\u0105dania mo\u017cna zdefiniowa\u0107 odpowied\u017a, kt\u00f3ra b\u0119dzie zwracana. Mo\u017ce to by\u0107 tekst, JSON, lub inny format danych. Serwer mo\u017ce r\u00f3wnie\u017c obs\u0142ugiwa\u0107 b\u0142\u0119dy i inne typowe scenariusze HTTP.<\/li>\n\n\n\n<li>Integracj\u0119 z <code>Qt Core<\/code> \u2013 dzi\u0119ki integracji z p\u0119tl\u0105 zdarze\u0144 Qt, <code>QHttpServer<\/code> dzia\u0142a asynchronicznie i efektywnie, zarz\u0105dzaj\u0105c wieloma po\u0142\u0105czeniami bez blokowania g\u0142\u00f3wnego w\u0105tku aplikacji.<\/li>\n<\/ul>\n\n\n\n<p>Ten mechanizm sprawia, \u017ce <code>QHttpServer<\/code> jest idealny do tworzenia lekkich serwer\u00f3w HTTP w aplikacjach, kt\u00f3re potrzebuj\u0105 lokalnego backendu.<\/p>\n\n\n\n<p>Przyk\u0142ad u\u017cycia:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n#include &amp;lt;QCoreApplication&gt;\n#include &amp;lt;QHttpServer&gt;\n#include &amp;lt;QJsonArray&gt;\n#include &amp;lt;QJsonObject&gt;\n#include &amp;lt;QJsonDocument&gt;\n\nint main(int argc, char *argv&#x5B;])\n{\n    QCoreApplication a(argc, argv);\n\n    QStringList users = {&quot;testUserName&quot;};\n\n    QHttpServer server;\n    server.route(&quot;\/users&quot;, QHttpServerRequest::Method::Get, &#x5B;&amp;amp;users] () {\n        return QHttpServerResponse(QJsonArray::fromStringList(users), QHttpServerResponse::StatusCode::Ok);\n    });\n\n    server.route(&quot;\/users&quot;, QHttpServerRequest::Method::Post, &#x5B;&amp;amp;users](const QHttpServerRequest &amp;amp;request) {\n        QJsonDocument doc = QJsonDocument::fromJson(request.body());\n        const QJsonObject obj = doc.object();\n        const QString name = obj&#x5B;&quot;name&quot;].toString();\n        if (name.isEmpty()) {\n            return QHttpServerResponse(&quot;Invalid data&quot;, QHttpServerResponse::StatusCode::BadRequest);\n        }\n        if (users.contains(name)) {\n            return QHttpServerResponse(&quot;User exists&quot;, QHttpServerResponse::StatusCode::BadRequest);\n        }\n        users.append(name);\n        return QHttpServerResponse(&quot;User added&quot;, QHttpServerResponse::StatusCode::Ok);\n    });\n\n    server.route(&quot;\/users\/&amp;lt;arg&gt;&quot;, QHttpServerRequest::Method::Delete, &#x5B;&amp;amp;users] (const QString&amp;amp; name) {\n        if (name.isEmpty() || !users.contains(name)) {\n            return QHttpServerResponse(&quot;Invalid data&quot;, QHttpServerResponse::StatusCode::BadRequest);\n        }\n        users.removeAll(name);\n        return QHttpServerResponse(QHttpServerResponse::StatusCode::Ok);\n    });\n\n    const int port = 8080;\n    if (server.listen(QHostAddress::Any, port)) {\n        qDebug() &amp;lt;&amp;lt; &quot;Start listening on port:&quot; &amp;lt;&amp;lt; port;\n    } else {\n        qDebug() &amp;lt;&amp;lt; &quot;Cannot start listening on port:&quot; &amp;lt;&amp;lt; port;\n        exit(1);\n    }\n    return a.exec();\n}\n<\/pre><\/div>\n\n\n<p>W powy\u017cszym przyk\u0142adzie zaimplementowane s\u0105 trzy metody HTTP:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>GET \/users \u2013 zwracaj\u0105ca u\u017cytkownik\u00f3w w postaci listy JSON,<\/li>\n\n\n\n<li>POST \/users \u2013 dodawanie u\u017cytkownika do listy; nazwa u\u017cytkownika jest odczytywana z cia\u0142a \u017c\u0105dania poprzez metod\u0119 <code>request.body()<\/code>,<\/li>\n\n\n\n<li>DELETE \/users\/&lt;arg&gt; \u2013 usuwanie u\u017cytkownika z listy, gdzie <code>&lt;arg&gt;<\/code> to nazwa u\u017cytkownika do usuni\u0119cia. W przypadku, gdy ma by\u0107 usuni\u0119ty u\u017cytkownik o nazwie <code>testUser<\/code>, \u017c\u0105danie powinno wygl\u0105da\u0107 nast\u0119puj\u0105co: <code>DELETE \/users\/testUser <\/code>.<\/li>\n<\/ul>\n\n\n\n<p>Serwer uruchamiany jest poprzez wywo\u0142anie metody <code>QHttpServer::listen()<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/oferty-pracy\/\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"737\" height=\"170\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/02\/praca-m.jpg\" alt=\"oferty pracy\" class=\"wp-image-30274\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/02\/praca-m.jpg 737w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/02\/praca-m-300x69.jpg 300w\" sizes=\"(max-width: 737px) 100vw, 737px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Wnioski<\/strong><\/h2>\n\n\n\n<p>W dzisiejszym artykule przedstawi\u0142em Wam, jak w \u0142atwy spos\u00f3b napisa\u0107 dwie aplikacje komunikuj\u0105ce si\u0119 po HTTP, zar\u00f3wno cz\u0119\u015b\u0107 klienck\u0105 jak i serwerow\u0105.<\/p>\n\n\n\n<p><strong>Qt<\/strong> oferuje bogaty zestaw narz\u0119dzi, kt\u00f3re pozwalaj\u0105 nie tylko na tworzenie atrakcyjnych interfejs\u00f3w graficznych, ale r\u00f3wnie\u017c na efektywne i elastyczne tworzenie aplikacji sieciowych. Dzi\u0119ki bogatej zawarto\u015bci frameworka, tworzenie zaawansowanych aplikacji jest \u0142atwe i przyjemne, zachowuj\u0105c du\u017c\u0105 wydajno\u015b\u0107.&nbsp;Bez&nbsp;nak\u0142adu znacznych ilo\u015bci czasu i pracy mo\u017cliwe jest utworzenie dzia\u0142aj\u0105cej aplikacji, dzi\u0119ki czemu <strong>staje si\u0119 ono narz\u0119dziem do szybkiego prototypowania oraz tworzenia gotowych rozwi\u0105za\u0144<\/strong>.<\/p>\n\n\n\n<p>Zach\u0119cam do eksploracji mo\u017cliwo\u015bci, jakie otwiera Qt, zw\u0142aszcza w kontek\u015bcie rozwoju oprogramowania sieciowego, gdzie jego <strong>zaawansowane modu\u0142y sieciowe mog\u0105 znacz\u0105co przyspieszy\u0107 i u\u0142atwi\u0107 rozw\u00f3j z\u0142o\u017conych aplikacji.<\/strong> Niech inspiracje i przyk\u0142ady przedstawione w tym wpisie b\u0119d\u0105 punktem wyj\u015bcia do w\u0142asnych eksperyment\u00f3w i projekt\u00f3w z wykorzystaniem Qt \ud83d\ude0a<\/p>\n\n\n\n<p>***<\/p>\n\n\n\n<p>Je\u017celi interesuje Ci\u0119 obszar frameworka Qt, zajrzyj koniecznie r\u00f3wnie\u017c do <a href=\"https:\/\/sii.pl\/blog\/wyszukiwarka\/Qt\/\" target=\"_blank\" rel=\"noopener\" title=\"\">innych artyku\u0142\u00f3w naszych specjalist\u00f3w<\/a>. <\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;30265&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;9&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5 ( votes: 9)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;Qt i REST API \u2013 tworzenie aplikacji sieciowych&quot;,&quot;width&quot;:&quot;139.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 139.5px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            5\/5 ( votes: 9)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Framework Qt cz\u0119sto kojarzony jest g\u0142\u00f3wnie z tworzeniem graficznego interfejsu u\u017cytkownika. Jednak to pot\u0119\u017cne narz\u0119dzie ma znacznie wi\u0119cej do zaoferowania, &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/qt-i-rest-api-tworzenie-aplikacji-sieciowych\/\">Continued<\/a><\/p>\n","protected":false},"author":697,"featured_media":30266,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[2783,1512,563,955,956],"class_list":["post-30265","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-qt","tag-poradnik","tag-embedded","tag-http","tag-rest-api"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/01\/Qt-i-REST-API-\u2013-tworzenie-aplikacji-sieciowych.jpg","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/30265"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/697"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=30265"}],"version-history":[{"count":3,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/30265\/revisions"}],"predecessor-version":[{"id":30276,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/30265\/revisions\/30276"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/30266"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=30265"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=30265"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=30265"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}