19.3.2015

foto Petr Bravenec

Petr Bravenec
Twitter: @BravenecPetr
+420 777 566 384
petr.bravenec@hobrasoft.cz

Před pár týdny jsem představil jednoduchý http server pro Qt. Jak takový server používáme v praxi?

Odkazy

HTTP server pro C++ a Qt
Koukněte se, jak to běhá
Dokumentace
Download

Server používáme mimo jiné i pro embedded aplikace postavené na Beaglebone black. Protože se nám samozřejmě nechce generovat HTML kód v C++, snažíme si to ulehčit, takže stránky mají bez vyjímky stejnou strukturu.

Souhrnné informace o hobrasoft http serveru naleznete na stránce: Naše práce - Http Server pro C++ a Qt

Struktura HTTP stránek

  • Statická html část, společné části (hlavička, patička a podobně) jsou vkládané na straně serveru. Prázdné jsou například všechny formuláře, tabulky obsahují pouze hlavičky a podobně - veškerá proměnná data jsou označená pouze identifikátorem a jinak jsou nevyplněná.
  • Každá stránka má vlastní skript, který tahá ze serveru data v JSON a vkládá je do html. Pokud chci doplnit například řádky do tabulky, musím si Javascriptem sáhnout do API na serveru pro data a vygenerovat celou html tabulku až v prohlížeči.
  • Aplikace, které vyvíjíme, často ve svém webovém rozhraní zobrazují aktuální vnitřní stav aplikace - pokud někde někdo stiskne tlačítko, webové rozhraní musí takovou informaci okamžitě zobrazit. Pokud oželíme MSIE, dá se k tomu dobře použít mechanismus EventStream z HTML5.
  • Data je nutné občas modifikovat a předat aplikaci změny. Webové formuláře předávají aplikaci data opět v podobě JSON, o přeformátování dat z formuláře do JSON se opět postará Javascript.
  • U některých aplikací je požadavek na přístup z různých jiných informačních systémů, univerzální a jednotné API je proto výhodou.

API není přímo součástí serveru, je přibaleno v příkladu spolu se serverem. Stručný popis najdete v dokumentaci ke třídě AbstractController.

Velká většina datových struktur a přístup k datům v aplikacích vypadá podobně - aplikace zobrazí zjednodušený seznam jednotlivých prvků, kliknutím na konkrétní prvek se otevře formulář pro úpravu, kliknutím na tlačítko "Uložit" se změny zapíší do aplikace, tlačítkem "Smazat" se konkrétní prvek smaže.

Jak API vypadá?

Požadavky implementované třídou AbstractController vypadají vždy podobně. Při přístupu k datům metodou GET vypadají požadavky takto:

GET     http://localhost:8086/room                  // Vrací seznam pokojů
GET     http://localhost:8086/room/events           // Proud událostí, všechny pokoje
GET     http://localhost:8086/room/e40f2a           // Vrací pokoj s id e40f2a 
GET     http://localhost:8086/room/e40f2a/events    // Proud událostí, jen jeden pokoj

Pro přístup k datům lze použít i další metody HTTP protokolu: GET, PUT, POST i DELETE. Metodu PUT a POST je možné využít pro uložení prvku, metodu DELETE pak pro smazání prvku:

PUT     http://localhost:8086/room/e40f2a           // Uloží předaná data
DELETE  http://localhost:8086/room/e40f2a           // Smaže pokoj s id e402f2a

Implementace odvozené třídy

Ve třídě AbstractController jsou pro obsluhu jednotlivých typů požadavků vytvořené metody:

  • serviceList()
  • serviceEvents()
  • serviceIdEvents()
  • serviceIdGet()
  • serviceIdDelete()
  • serviceIdPut()
  • serviceIdPost()

V odvozených třídách stačí odvodit pouze ty metody, které chcete využívat. Implementace může být velmi jednoduchá:

void ControllerRoom::serviceIdGet(
            HobrasoftHttp::HttpRequest *request, 
            HobrasoftHttp::HttpResponse *response, 
            const QString& id
            ) {
    // Kontroly není třeba provádět, stará se o to abstraktní třída
    // ROOMSLIST je objekt se seznamem pokojů
    // Metoda room(id) vrací datovou strukturu pokoje
    serviceOK(request, response, ROOMSLIST->room(id))
}

Metoda serviceOK() říká abstraktní třídě, aby vrátila na HTTP požadavek odpověď "200 OK" s předanými daty. Struktura předávaných dat je popsaná níže. Před odesláním protokolem HTTP se data překovertují do JSON formátu.

Pokud byste potřebovali místo odpovědi "200 OK" poslat chybovou zprávu, využijte metodu serviceError().

Ale s kontrolami se nemusíte příliš zabývat. Abstraktní třída se stará i o základní kontroly - může být proto potřeba implementovat metodu exists() - metoda vrací true, pokud zadané ID existuje:

bool ControllerRoom::exists(const QString& id) {
    return ROOMSLIST->contains(id);
}

Metody, které nepotřebujete, nemusíte implementovat. Defaultní implementace vrací chybu 501.

Struktura předávaných dat

Data jsou předávaná ve strukturovaném kontejneru QVariantMap. Data můžete vytvořit například takto:

QVariantMap data;
data["ID"] = "e40f2a";
data["Description"] = "Jméno pokoje";
QVariantList list;
list << "abc" << "xyz";
data["List"] = list;

Odpovídající JSON struktura pak vypadá takto:

{ "ID" : "e40f2a", "Description" : "Jméno pokoje", "List" : [ "abc", "xyz" ] }

Závěr

Zajímají vás podivuhodná dobrodružství HTTP C++ serveru? Zůstaňte naladěni, sledujte twitter, sledujte naše stránky. Připravujeme článek o tom, jak vytvořit a používat HTML5 proud událostí (event stream).

Hobrasoft s.r.o. | Kontakt