{"id":270,"date":"2018-07-26T14:59:19","date_gmt":"2018-07-26T12:59:19","guid":{"rendered":"http:\/\/www.kompikownia.pl\/?p=270"},"modified":"2019-03-08T00:08:23","modified_gmt":"2019-03-07T23:08:23","slug":"rest-api-w-c-biblioteka-casablanca-cpprest","status":"publish","type":"post","link":"https:\/\/www.kompikownia.pl\/index.php\/2018\/07\/26\/rest-api-w-c-biblioteka-casablanca-cpprest\/","title":{"rendered":"REST API w C++ &#8211; biblioteka Casablanca cpprest"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Czas czytania:<\/span> <span class=\"rt-time\">5<\/span> <span class=\"rt-label rt-postfix\">minut<\/span><\/span>\n<p><strong>Przed lektur\u0105<\/strong><br>Aby\u015b zrozumia\u0142 tre\u015b\u0107 tego wpisu by\u0142oby dobrze, aby\u015b wiedzia\u0142 co to jest REST API oraz do czego ono s\u0142u\u017cy. W tre\u015bci tego wpisu nie b\u0119d\u0119 si\u0119 rozwodzi\u0142 nad tym co to dok\u0142adnie jest REST API oraz do czego ono s\u0142u\u017cy. Skupi\u0119 si\u0119 jedynie nad tym, jak wykona\u0107 prost\u0105 implementacj\u0119.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>Ostatnimi czasy tworz\u0119 do\u015b\u0107 du\u017cy projekt. Jego wielko\u015b\u0107 wymaga\u0142a podzia\u0142u na dwie cz\u0119\u015bci: backend i frontend. Backend to wszystko, co dzieje si\u0119 pod spodem (komunikacja z baz\u0105 danych, wykonywanie oblicze\u0144 itp.) Natomiast Frontend zajmuje si\u0119 g\u0142\u00f3wnie interfejsem aplikacji, czyli sposobem \u201ekomunikacji\u201d z u\u017cytkownikiem. Aplikacja powstawa\u0142a w C++ i mia\u0142em spory problem z&nbsp;wyprowadzeniem przetwarzanych danych do aplikacji tworzonej w React\u2019ie. Pr\u00f3bowa\u0142em r\u00f3\u017cnych sposob\u00f3w \u2013 np.: komunikacji za pomoc\u0105 socket\u00f3w. Pewnego razu na uczelni us\u0142ysza\u0142em o czym\u015b takim jak REST API \u2013 kt\u00f3re wykorzystuje m.in. format JSON oraz r\u00f3\u017cne typy zapyta\u0144 HTTP do udost\u0119pnienia frontendowi r\u00f3\u017cnych informacji. W wykonaniu REST API w j\u0119zyku C++ mo\u017ce nam pom\u00f3c biblioteka firmy Microsoft o nazwie Casablanca (cpprest). Za chwil\u0119 zobaczymy, jak j\u0105 zainstalowa\u0107 oraz jak zrobi\u0107 proste API.<\/p>\n\n\n\n<h1 class=\"western wp-block-heading\">Instalacja Cablanca cpprest<\/h1>\n\n\n\n<p>Instalacja biblioteki cpprest zosta\u0142a dobrze opisana na jej stronie w <a href=\"https:\/\/github.com\/Microsoft\/cpprestsdk\">Githubie<\/a>. W&nbsp;Linuksie mo\u017cemy j\u0105 bezproblemowo zainstalowa\u0107 za pomoc\u0105 polecenia:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo apt-get install libcpprest-dev\n<\/pre>\n\n\n\n<p>Nasz projekt nie b\u0119dzie mia\u0142 jakiego\u015b ogromnego rozmiaru. Tote\u017c u\u017cyjemy prostego \u015brodowiska Code::Blocks. Utw\u00f3rz nowy projekt konsolowy w j\u0119zyku C++. Gdy to zrobisz, kliknij PPM na nazwie projektu\u2192Build Options\u2192na li\u015bcie po lewej stronie zaznacz nazw\u0119 swojego projektu. Po prawej stronie przejd\u017a na zak\u0142adk\u0119 Linker Settings. Musimy doda\u0107 nast\u0119puj\u0105ce opcje:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">-lcpprest\n-lpthread\n-lboost_system\n-lssl\n-lcrypto\n<\/pre>\n\n\n\n<p>Poni\u017cej znajduje si\u0119 screen prezentuj\u0105cy jak to powinno wygl\u0105da\u0107:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"764\" height=\"765\" src=\"https:\/\/www.kompikownia.pl\/wp-content\/uploads\/2018\/07\/Screenshot_20180726_134541.png\" alt=\"\" class=\"wp-image-274\"\/><\/figure><\/div>\n\n\n\n<p><br>To tyle. Biblioteka zosta\u0142a do\u0142\u0105czona a projekt zosta\u0142 skonfigurowany. Pora na napisanie prostego kodu.<\/p>\n\n\n\n<h1 class=\"western wp-block-heading\">Piszemy proste Rest API w C++<\/h1>\n\n\n\n<p>Nasz projekt b\u0119dzie sk\u0142ada\u0142 si\u0119 z kilku klas. Utworzymy sobie klas\u0119 BasicController, kt\u00f3ra b\u0119dzie ustawia\u0142a wszystkie podstawowe parametry serwera. Nast\u0119pnie utworzymy sobie klas\u0119 us\u0142ugi, kt\u00f3ra b\u0119dzie implementowa\u0142a metody GET\/PUT\/POST i inne.<\/p>\n\n\n\n<h2 class=\"western wp-block-heading\">BasicController<\/h2>\n\n\n\n<p>Zaczynamy od klasy BasicController. Dodajemy do projektu nowy plik o nazwie BasicController.h. Wewn\u0105trz znajduje si\u0119 nast\u0119puj\u0105cy kod:<\/p>\n\n\n\n<p>Om\u00f3wimy go linijka po linijce.<\/p>\n\n\n\n\n<div class=\"codecolorer-container cpp default\" style=\"overflow:auto;white-space:nowrap;width:90%;height:600px;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/>17<br \/>18<br \/>19<br \/>20<br \/>21<br \/>22<br \/>23<br \/>24<br \/>25<br \/>26<br \/>27<br \/>28<br \/>29<br \/><\/div><\/td><td><div class=\"cpp codecolorer\"><span class=\"co2\">#ifndef BASICCONTROLLER_H_INCLUDED<\/span><br \/>\n<span class=\"co2\">#define BASICCONTROLLER_H_INCLUDED<\/span><br \/>\n<span class=\"co2\">#include &lt;cpprest\/http_listener.h&gt;<\/span><br \/>\n<span class=\"co2\">#include &lt;pplx\/pplxtasks.h&gt;<\/span><br \/>\n<span class=\"co2\">#include &lt;string&gt;<\/span><br \/>\n<span class=\"co2\">#include &lt;cpprest\/http_msg.h&gt;<\/span><br \/>\n<span class=\"kw2\">using<\/span> <span class=\"kw2\">namespace<\/span> web<span class=\"sy4\">;<\/span><br \/>\n<span class=\"kw2\">using<\/span> <span class=\"kw2\">namespace<\/span> http<span class=\"sy4\">;<\/span><br \/>\n<span class=\"kw2\">using<\/span> <span class=\"kw2\">namespace<\/span> http<span class=\"sy4\">::<\/span><span class=\"me2\">experimental<\/span><span class=\"sy4\">::<\/span><span class=\"me2\">listener<\/span><span class=\"sy4\">;<\/span><br \/>\n<br \/>\n<span class=\"kw2\">class<\/span> BasicController <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw2\">public<\/span><span class=\"sy4\">:<\/span><br \/>\n&nbsp; &nbsp; BasicController<span class=\"br0\">&#40;<\/span><span class=\"kw4\">const<\/span> std<span class=\"sy4\">::<\/span><span class=\"me2\">string<\/span><span class=\"sy3\">&amp;<\/span> address,<span class=\"kw4\">const<\/span> std<span class=\"sy4\">::<\/span><span class=\"me2\">string<\/span><span class=\"sy3\">&amp;<\/span> port<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; ~BasicController<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw4\">void<\/span> setEndpoint<span class=\"br0\">&#40;<\/span><span class=\"kw4\">const<\/span> std<span class=\"sy4\">::<\/span><span class=\"me2\">string<\/span><span class=\"sy3\">&amp;<\/span> mount_point<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; std<span class=\"sy4\">::<\/span><span class=\"me2\">string<\/span> endpoint<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"kw4\">const<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; pplx<span class=\"sy4\">::<\/span><span class=\"me2\">task<\/span><span class=\"sy1\">&lt;<\/span><span class=\"kw4\">void<\/span><span class=\"sy1\">&gt;<\/span> accept<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; pplx<span class=\"sy4\">::<\/span><span class=\"me2\">task<\/span><span class=\"sy1\">&lt;<\/span><span class=\"kw4\">void<\/span><span class=\"sy1\">&gt;<\/span> shutdown<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw2\">virtual<\/span> <span class=\"kw4\">void<\/span> initRestOpHandlers<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy1\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy4\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; std<span class=\"sy4\">::<\/span><span class=\"me2\">vector<\/span><span class=\"sy1\">&lt;<\/span>utility<span class=\"sy4\">::<\/span><span class=\"me2\">string_t<\/span><span class=\"sy1\">&gt;<\/span> requestPath<span class=\"br0\">&#40;<\/span><span class=\"kw4\">const<\/span> http_request <span class=\"sy3\">&amp;<\/span> message<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw2\">protected<\/span><span class=\"sy4\">:<\/span><br \/>\n&nbsp; &nbsp; http_listener _listener<span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw2\">private<\/span><span class=\"sy4\">:<\/span><br \/>\n&nbsp; &nbsp; uri_builder endpointBuilder<span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"sy4\">;<\/span><br \/>\n<br \/>\n<span class=\"co2\">#endif \/\/ BASICCONTROLLER_H_INCLUDED<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n\n\n\n<p>#include\u2019y \u2013 to jest to, co musi si\u0119 pojawi\u0107. Aby program prawid\u0142owo si\u0119 skompilowa\u0142, musimy do\u0142\u0105czy\u0107 pliki nag\u0142\u00f3wkowe zawieraj\u0105ce funkcje z nowo dodanej biblioteki, z kt\u00f3rej b\u0119dziemy korzystali.<\/p>\n\n\n\n<p>Konstruktor naszej klasy przyjmuje dwa parametry: adres oraz port pod kt\u00f3rym nasz serwer b\u0119dzie nas\u0142uchiwa\u0142. Jako adres przeka\u017cemy adres IP naszej karty sieciowej. W przysz\u0142o\u015bci mo\u017cemy sami odczytywa\u0107 ten adres, ale pomin\u0105\u0142em ten fragment dla uproszczenia przyk\u0142adu.<\/p>\n\n\n\n<p>Destruktor jest, ale nic nie robi.<\/p>\n\n\n\n<p><strong>setEndpoint<\/strong> \u2013 funkcja ta przyjmuje tylko jeden argument. mount_point, czyli \u201efragment adresu\u201d pod jakim b\u0119dzie widoczna nasza us\u0142uga. np.: Skonstruujmy kontroler, przekazuj\u0105c mu jako adres IP i port 192.168.1.1 i port 8080. setEndpoint uruchommy z argumentem \u201e\/api\/calculator\u201d. Wtedy nasze API b\u0119dzie widoczne pod adresem <a href=\"http:\/\/192.168.1.1:8080\/api\/calculator\">http:\/\/192.168.1.1:8080\/api\/calculator<\/a>. Proste, nie?<\/p>\n\n\n\n<p>Kolejne dwie funkcje \u2013 <strong>accept<\/strong> i <strong>shutdown<\/strong> \u2013 s\u0142u\u017c\u0105 do rozpocz\u0119cia i zako\u0144czenia pracy serwera. Czysto wirtualn\u0105 metod\u0105 <strong>initRestOpHandlers<\/strong> zajmiemy si\u0119 p\u00f3\u017aniej.<\/p>\n\n\n\n<p><strong>requestPath<\/strong> wyci\u0105ga nam z zapytania cz\u0119\u015b\u0107 adresu, kt\u00f3r\u0105 dopisa\u0142 u\u017cytkownik. Wr\u00f3\u0107my do poprzedniego przyk\u0142adu. Za\u0142\u00f3\u017cmy, \u017ce u\u017cytkownik wys\u0142a\u0142 zapytanie pod adres:<\/p>\n\n\n\n<p><a href=\"http:\/\/192.168.1.1:8080\/api\/calculator\/adder\">http:\/\/192.168.1.1:8080\/api\/calculator\/adder<\/a>. Wtedy requestPath zwr\u00f3ci tablic\u0119, kt\u00f3rej pierwszym elementem b\u0119dzie s\u0142owo \u201eadder\u201d.<\/p>\n\n\n\n<p><strong>http_listener _listener<\/strong> \u2013 jest to zmienna, kt\u00f3ra s\u0142u\u017cy\u0107 nam b\u0119dzie po pod\u0142\u0105czenia odpowiednich funkcji do danych zapyta\u0144. Szczeg\u00f3\u0142owo zajmiemy si\u0119 ni\u0105 p\u00f3\u017aniej.<\/p>\n\n\n\n<p><strong>uri_builder endpointBuilder<\/strong> \u2013 s\u0142u\u017cy do zbudowania adresu, pod kt\u00f3rym b\u0119dzie widoczna nasza us\u0142uga. Zauwa\u017cysz i zrozumiesz jej zastosowanie, kiedy b\u0119dziemy patrzyli na implementacj\u0119 powy\u017cszych metod.<\/p>\n\n\n\n<p>No dobra. Pierwsze koty za p\u0142oty. Przechodzimy do implementacji klasy BasicController.<\/p>\n\n\n<div class=\"codecolorer-container cpp default\" style=\"overflow:auto;white-space:nowrap;width:90%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/><\/div><\/td><td><div class=\"cpp codecolorer\"><span class=\"co2\">#include &quot;BasicController.h&quot;<\/span><br \/>\n<br \/>\nBasicController<span class=\"sy4\">::<\/span><span class=\"me2\">BasicController<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw4\">const<\/span> std<span class=\"sy4\">::<\/span><span class=\"me2\">string<\/span><span class=\"sy3\">&amp;<\/span> naddress,<span class=\"kw4\">const<\/span> std<span class=\"sy4\">::<\/span><span class=\"me2\">string<\/span><span class=\"sy3\">&amp;<\/span> nport<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp;this<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>endpointBuilder.<span class=\"me1\">set_host<\/span><span class=\"br0\">&#40;<\/span>naddress<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp;this<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>endpointBuilder.<span class=\"me1\">set_port<\/span><span class=\"br0\">&#40;<\/span>nport<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp;this<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>endpointBuilder.<span class=\"me1\">set_scheme<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;http&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\nBasicController<span class=\"sy4\">::<\/span>~BasicController<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"kw4\">void<\/span> BasicController<span class=\"sy4\">::<\/span><span class=\"me2\">setEndpoint<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw4\">const<\/span> std<span class=\"sy4\">::<\/span><span class=\"me2\">string<\/span><span class=\"sy3\">&amp;<\/span> mount_point<span class=\"br0\">&#41;<\/span><br \/>\n<span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; endpointBuilder.<span class=\"me1\">set_path<\/span><span class=\"br0\">&#40;<\/span>mount_point<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; _listener <span class=\"sy1\">=<\/span> http_listener<span class=\"br0\">&#40;<\/span>endpointBuilder.<span class=\"me1\">to_uri<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n\n\n<p>W konstruktorze za pomoc\u0105 endpointBuildera ustawiamy adres, port oraz protok\u00f3\u0142, pod kt\u00f3rym b\u0119dziemy nas\u0142uchiwa\u0107. W setEndpoint do endPointBuildera dodajemy \u015bcie\u017ck\u0119 i to wszystko przekazujemy jako wynik do _listenera, kt\u00f3ry od tego momentu wie, pod jakim adresem ma nas\u0142uchiwa\u0107 przychodz\u0105cych zapyta\u0144.<\/p>\n\n\n\n\n<div class=\"codecolorer-container cpp default\" style=\"overflow:auto;white-space:nowrap;width:90%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>20<br \/>21<br \/>22<br \/>23<br \/>24<br \/>25<br \/>26<br \/><\/div><\/td><td><div class=\"cpp codecolorer\">pplx<span class=\"sy4\">::<\/span><span class=\"me2\">task<\/span><span class=\"sy1\">&lt;<\/span><span class=\"kw4\">void<\/span><span class=\"sy1\">&gt;<\/span> BasicController<span class=\"sy4\">::<\/span><span class=\"me2\">accept<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; initRestOpHandlers<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> _listener.<span class=\"me1\">open<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\npplx<span class=\"sy4\">::<\/span><span class=\"me2\">task<\/span><span class=\"sy1\">&lt;<\/span><span class=\"kw4\">void<\/span><span class=\"sy1\">&gt;<\/span> BasicController<span class=\"sy4\">::<\/span><span class=\"me2\">shutdown<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> _listener.<span class=\"me1\">close<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n\n\n\n<p>W metodzie accept wywo\u0142ujemy metod\u0119 initRestOpHandlers(), kt\u00f3r\u0105 nied\u0142ugo nadpiszemy w klasie pochodnej. Poza tym, otwieramy _listenera. Od momentu wywo\u0142ania tej funkcji nasz serwer zaczyna pracowa\u0107. Implementacja metody shutdown jest analogiczna.<\/p>\n\n\n\n\n<div class=\"codecolorer-container cpp default\" style=\"overflow:auto;white-space:nowrap;width:90%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>27<br \/>28<br \/>29<br \/>30<br \/>31<br \/><\/div><\/td><td><div class=\"cpp codecolorer\">std<span class=\"sy4\">::<\/span><span class=\"me2\">vector<\/span><span class=\"sy1\">&lt;<\/span>utility<span class=\"sy4\">::<\/span><span class=\"me2\">string_t<\/span><span class=\"sy1\">&gt;<\/span> BasicController<span class=\"sy4\">::<\/span><span class=\"me2\">requestPath<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw4\">const<\/span> http_request<span class=\"sy3\">&amp;<\/span> message<span class=\"br0\">&#41;<\/span><br \/>\n<span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw4\">auto<\/span> relativePath <span class=\"sy1\">=<\/span> uri<span class=\"sy4\">::<\/span><span class=\"me2\">decode<\/span><span class=\"br0\">&#40;<\/span>message.<span class=\"me1\">relative_uri<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">path<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> uri<span class=\"sy4\">::<\/span><span class=\"me2\">split_path<\/span><span class=\"br0\">&#40;<\/span>relativePath<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n\n\n\n<p>Jak dzia\u0142a metoda requestPath? Jako argument przyjmujemy zapytanie http. Dekodujemy je za pomoc\u0105 specjalnej metody uri::decode. Korzystamy ze specjalnego typu zmiennej auto, kt\u00f3rej typ, wzorem Javascriptu i innych nowoczesnych j\u0119zyk\u00f3w, automatycznie dopasowuje si\u0119 do danej sytuacji. Metoda split_path dzieli \u015bcie\u017ck\u0119 na kawa\u0142ki i ka\u017cdy z&nbsp;tych kawa\u0142k\u00f3w wk\u0142ada do oddzielnego elementu klasy vector. To wszystko zwracamy za pomoc\u0105 s\u0142owa kluczowego return.<\/p>\n\n\n\n<h2 class=\"western wp-block-heading\">Service<\/h2>\n\n\n\n<p>Klasa Service dziedziczy po BasicController. Umie\u015b\u0107 j\u0105 w oddzielnych plikach: Service.cpp oraz Service.h.<\/p>\n\n\n\n<p>Nasza us\u0142uga b\u0119dzie pe\u0142ni\u0142a bardzo prost\u0105 rol\u0119. Zapytanie GET b\u0119dzie zwraca\u0142o nam zawarto\u015b\u0107 kontenera vector przechowuj\u0105cego liczby int. Je\u015bli przy zapytaniu GET adres URI b\u0119dzie ko\u0144czy\u0142 si\u0119 s\u0142\u00f3wkiem sum, to dostaniemy sum\u0119 liczb, a je\u015bli s\u0142\u00f3wkiem avg to \u015bredni\u0105. Zapytanie PUT b\u0119dzie natomiast dodawa\u0142o kolejne liczby do tego kontenera. To wystarczy, aby pokaza\u0107 ci og\u00f3ln\u0105 wizj\u0119 pos\u0142ugiwania si\u0119 bibliotek\u0105 cpprest. Pozosta\u0142e zapytania dasz rad\u0119 zaimplementowa\u0107 we w\u0142asnym zakresie.<\/p>\n\n\n\n<p><strong>Service.h<\/strong><\/p>\n\n\n\n\n<div class=\"codecolorer-container cpp default\" style=\"overflow:auto;white-space:nowrap;width:90%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/>17<br \/>18<br \/><\/div><\/td><td><div class=\"cpp codecolorer\"><span class=\"co2\">#ifndef SERVICE_H_INCLUDED<\/span><br \/>\n<span class=\"co2\">#define SERVICE_H_INCLUDED<\/span><br \/>\n<span class=\"co2\">#include &quot;BasicController.h&quot;<\/span><br \/>\n<span class=\"co2\">#include &lt;vector&gt;<\/span><br \/>\n<span class=\"kw2\">using<\/span> std<span class=\"sy4\">::<\/span><span class=\"me2\">vector<\/span><span class=\"sy4\">;<\/span><br \/>\n<br \/>\n<span class=\"kw2\">class<\/span> Service <span class=\"sy4\">:<\/span> <span class=\"kw2\">public<\/span> BasicController <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw2\">public<\/span><span class=\"sy4\">:<\/span><br \/>\n&nbsp; &nbsp; Service<span class=\"br0\">&#40;<\/span><span class=\"kw4\">const<\/span> std<span class=\"sy4\">::<\/span><span class=\"me2\">string<\/span><span class=\"sy3\">&amp;<\/span> address,<span class=\"kw4\">const<\/span> std<span class=\"sy4\">::<\/span><span class=\"me2\">string<\/span><span class=\"sy3\">&amp;<\/span> port<span class=\"br0\">&#41;<\/span> <span class=\"sy4\">:<\/span> BasicController<span class=\"br0\">&#40;<\/span>address,port<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; ~Service<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw4\">void<\/span> handleGet<span class=\"br0\">&#40;<\/span>http_request message<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw4\">void<\/span> handlePut<span class=\"br0\">&#40;<\/span>http_request message<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw4\">void<\/span> initRestOpHandlers<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"kw2\">override<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw2\">private<\/span><span class=\"sy4\">:<\/span><br \/>\n&nbsp; &nbsp; vector<span class=\"sy1\">&lt;<\/span><span class=\"kw4\">int<\/span><span class=\"sy1\">&gt;<\/span> numbers<span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw4\">float<\/span> calculateSum<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"co2\">#endif \/\/ SERVICE_H_INCLUDED<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n\n\n\n<p>Oto nasz plik Service.h. Zdefiniowali\u015bmy w nim klas\u0119 Service. To ona b\u0119dzie zajmowa\u0142a si\u0119 analiz\u0105 zapyta\u0144 i wys\u0142aniem odpowiedniej odpowiedzi do u\u017cytkownika. Prywatnie zdefiniowali\u015bmy sobie vector liczb typu int. To tam b\u0119dziemy przechowywali liczby dodane przez u\u017cytkownika za pomoc\u0105 zapytania PUT. Zdefiniowali\u015bmy sobie tak\u017ce pomocnicz\u0105 funkcj\u0119 calculateSum() (w linijce 16). Funkcja calculateSum b\u0119dzie liczy\u0142a sum\u0119 wszystkich element\u00f3w znajduj\u0105cej si\u0119 w kontenerze numbers.<\/p>\n\n\n\n<p>A co zdefiniowali\u015bmy jako publiczne elementy? Konstruktor, kt\u00f3ry przyjmuje takie same parametry jak konstruktor klasy, po kt\u00f3rej dziedziczymy (BasicController). Poza tym konstruktor nic nie musi robi\u0107. Dalej mamy definicj\u0119 metod, z kt\u00f3rych b\u0119dziemy korzystali: handleGet i handlePut. Obydwie jako argument przyjmuj\u0105 zmienn\u0105 typu http_request. <strong>http_request<\/strong> zawiera wszystkie informacje o zapytaniu HTTP, jakie zosta\u0142o wys\u0142ane przez u\u017cytkownika. InitrRestOpHandlers() jest metod\u0105 odziedziczon\u0105 po BasicController, kt\u00f3r\u0105 w tym miejscu zaimplementujemy.<\/p>\n\n\n\n<p><strong>Service.cpp<\/strong><br>Plik Service.cpp jest dosy\u0107 d\u0142ugi. Aby\u015b wszystko dobrze zrozumia\u0142, b\u0119d\u0119 omawia\u0142 po kolei poszczeg\u00f3lne metody tego pliku.<\/p>\n\n\n\n\n<div class=\"codecolorer-container cpp default\" style=\"overflow:auto;white-space:nowrap;width:90%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/><\/div><\/td><td><div class=\"cpp codecolorer\"><span class=\"co2\">#include &quot;Service.h&quot;<\/span><br \/>\n<span class=\"co2\">#include &lt;string&gt;<\/span><br \/>\n<span class=\"kw2\">using<\/span> std<span class=\"sy4\">::<\/span><span class=\"me2\">string<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"kw4\">void<\/span> Service<span class=\"sy4\">::<\/span><span class=\"me2\">initRestOpHandlers<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; _listener.<span class=\"me1\">support<\/span><span class=\"br0\">&#40;<\/span>methods<span class=\"sy4\">::<\/span><span class=\"me2\">GET<\/span>,std<span class=\"sy4\">::<\/span><span class=\"me2\">bind<\/span><span class=\"br0\">&#40;<\/span><span class=\"sy3\">&amp;<\/span>Service<span class=\"sy4\">::<\/span><span class=\"me2\">handleGet<\/span>,<span class=\"kw3\">this<\/span>,std<span class=\"sy4\">::<\/span><span class=\"me2\">placeholders<\/span><span class=\"sy4\">::<\/span>_1<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; _listener.<span class=\"me1\">support<\/span><span class=\"br0\">&#40;<\/span>methods<span class=\"sy4\">::<\/span><span class=\"me2\">PUT<\/span>,std<span class=\"sy4\">::<\/span><span class=\"me2\">bind<\/span><span class=\"br0\">&#40;<\/span><span class=\"sy3\">&amp;<\/span>Service<span class=\"sy4\">::<\/span><span class=\"me2\">handlePut<\/span>,<span class=\"kw3\">this<\/span>,std<span class=\"sy4\">::<\/span><span class=\"me2\">placeholders<\/span><span class=\"sy4\">::<\/span>_1<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n\n\n\n<p>Zaczynamy od funkcji initRestOpHandlers. Domy\u015blasz si\u0119 pewnie, jakie ona ma zadanie :). M\u00f3wimy serwerowi, jakie metody obs\u0142uguje nasze API. Pierwszy argument to odpowiednia metoda. Drugi argument wygl\u0105da nieco bardziej tajemniczo. Za pomoc\u0105 std::bind \u201em\u00f3wimy\u201d listenerowi, \u017ceby u\u017cy\u0142 danej metody obs\u0142ugi je\u015bli serwer otrzyma dane zapytanie. Np.: w linijce pi\u0105tej m\u00f3wimy, \u017ce do obs\u0142ugi zapytania GET powinna zosta\u0107 u\u017cyta metoda handleGet. Natomiast w kolejnej linijce u\u015bwiadamiamy serwerowi, \u017ceby u\u017cy\u0142 metody handlePut do obs\u0142ugi zapytania PUT. Analogicznie post\u0119powaliby\u015bmy z innymi zapytaniami HTTP, kt\u00f3re chcieliby\u015bmy obs\u0142u\u017cy\u0107 a nie ma ich w tym przyk\u0142adzie.<\/p>\n\n\n\n\n<div class=\"codecolorer-container cpp default\" style=\"overflow:auto;white-space:nowrap;width:90%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/><\/div><\/td><td><div class=\"cpp codecolorer\"><span class=\"kw4\">float<\/span> Service<span class=\"sy4\">::<\/span><span class=\"me2\">calculateSum<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw4\">float<\/span> sum <span class=\"sy1\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">for<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw4\">unsigned<\/span> <span class=\"kw4\">int<\/span> i <span class=\"sy1\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy4\">;<\/span>i<span class=\"sy1\">&lt;<\/span>numbers.<span class=\"me1\">size<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span>i<span class=\"sy2\">++<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; sum<span class=\"sy2\">+<\/span><span class=\"sy1\">=<\/span>numbers<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> sum<span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n\n\n\n<p>Implementacja metody CalculateSum nie pozostawia \u017cadnych w\u0105tpliwo\u015bci. Po prostu w p\u0119tli for sumujemy wszystkie elementy kontenera numbers i sum\u0119 t\u0119 przechowujemy w zmiennej typu float o nazwie sum. Na samym ko\u0144cu, gdy p\u0119tla sko\u0144czy swoj\u0105 prac\u0119, zwracamy zmienn\u0105 sum jako rezultat wykonania tej metody. Nie ma tu nic niezwyk\u0142ego, nad czym warto by\u0142oby d\u0142u\u017cej si\u0119 rozwodzi\u0107.<\/p>\n\n\n\n\n<div class=\"codecolorer-container cpp default\" style=\"overflow:auto;white-space:nowrap;width:90%;height:300px;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>16<br \/>17<br \/>18<br \/>19<br \/>20<br \/>21<br \/>22<br \/>23<br \/>24<br \/>25<br \/>26<br \/>27<br \/>28<br \/>29<br \/>30<br \/>31<br \/>32<br \/>33<br \/>34<br \/>35<br \/>36<br \/>37<br \/>38<br \/>39<br \/>40<br \/>41<br \/>42<br \/>43<br \/>44<br \/>45<br \/>46<br \/><\/div><\/td><td><div class=\"cpp codecolorer\"><span class=\"kw4\">void<\/span> Service<span class=\"sy4\">::<\/span><span class=\"me2\">handleGet<\/span><span class=\"br0\">&#40;<\/span>http_request message<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; vector<span class=\"sy1\">&lt;<\/span>string<span class=\"sy1\">&gt;<\/span> path <span class=\"sy1\">=<\/span> requestPath<span class=\"br0\">&#40;<\/span>message<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>path.<span class=\"me1\">empty<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; vector <span class=\"sy1\">&lt;<\/span>json<span class=\"sy4\">::<\/span><span class=\"me2\">value<\/span><span class=\"sy1\">&gt;<\/span> jsonNumbers<span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">for<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw4\">unsigned<\/span> <span class=\"kw4\">int<\/span> i <span class=\"sy1\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy4\">;<\/span>i<span class=\"sy1\">&lt;<\/span>numbers.<span class=\"me1\">size<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span>i<span class=\"sy2\">++<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; json<span class=\"sy4\">::<\/span><span class=\"me2\">value<\/span> number<span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; number<span class=\"br0\">&#91;<\/span><span class=\"st0\">&quot;number&quot;<\/span><span class=\"br0\">&#93;<\/span> <span class=\"sy1\">=<\/span> json<span class=\"sy4\">::<\/span><span class=\"me2\">value<\/span><span class=\"sy4\">::<\/span><span class=\"me2\">number<\/span><span class=\"br0\">&#40;<\/span>numbers<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jsonNumbers.<span class=\"me1\">push_back<\/span><span class=\"br0\">&#40;<\/span>number<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; json<span class=\"sy4\">::<\/span><span class=\"me2\">value<\/span> generatedNumberList<span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; generatedNumberList<span class=\"br0\">&#91;<\/span><span class=\"st0\">&quot;numbers&quot;<\/span><span class=\"br0\">&#93;<\/span> <span class=\"sy1\">=<\/span> json<span class=\"sy4\">::<\/span><span class=\"me2\">value<\/span><span class=\"sy4\">::<\/span><span class=\"me2\">array<\/span><span class=\"br0\">&#40;<\/span>jsonNumbers<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; message.<span class=\"me1\">reply<\/span><span class=\"br0\">&#40;<\/span>status_codes<span class=\"sy4\">::<\/span><span class=\"me2\">OK<\/span>,generatedNumberList<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">else<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>path<span class=\"br0\">&#91;<\/span><span class=\"nu0\">0<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy1\">==<\/span><span class=\"st0\">&quot;avg&quot;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw4\">float<\/span> avg <span class=\"sy1\">=<\/span> calculateSum<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy2\">\/<\/span>numbers.<span class=\"me1\">size<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; json<span class=\"sy4\">::<\/span><span class=\"me2\">value<\/span> number<span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; number<span class=\"br0\">&#91;<\/span><span class=\"st0\">&quot;avg&quot;<\/span><span class=\"br0\">&#93;<\/span> <span class=\"sy1\">=<\/span> json<span class=\"sy4\">::<\/span><span class=\"me2\">value<\/span><span class=\"sy4\">::<\/span><span class=\"me2\">number<\/span><span class=\"br0\">&#40;<\/span>avg<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; message.<span class=\"me1\">reply<\/span><span class=\"br0\">&#40;<\/span>status_codes<span class=\"sy4\">::<\/span><span class=\"me2\">OK<\/span>,number<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">else<\/span> <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>path<span class=\"br0\">&#91;<\/span><span class=\"nu0\">0<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy1\">==<\/span><span class=\"st0\">&quot;sum&quot;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw4\">float<\/span> sum <span class=\"sy1\">=<\/span> calculateSum<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; json<span class=\"sy4\">::<\/span><span class=\"me2\">value<\/span> number<span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; number<span class=\"br0\">&#91;<\/span><span class=\"st0\">&quot;sum&quot;<\/span><span class=\"br0\">&#93;<\/span> <span class=\"sy1\">=<\/span> json<span class=\"sy4\">::<\/span><span class=\"me2\">value<\/span><span class=\"sy4\">::<\/span><span class=\"me2\">number<\/span><span class=\"br0\">&#40;<\/span>sum<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; message.<span class=\"me1\">reply<\/span><span class=\"br0\">&#40;<\/span>status_codes<span class=\"sy4\">::<\/span><span class=\"me2\">OK<\/span>,number<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">else<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; message.<span class=\"me1\">reply<\/span><span class=\"br0\">&#40;<\/span>status_codes<span class=\"sy4\">::<\/span><span class=\"me2\">BadRequest<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n\n\n\n<p>Ciekawe rzeczy zaczynaj\u0105 si\u0119 od metody handleGet, kt\u00f3ra ma obs\u0142u\u017cy\u0107 \u017c\u0105danie GET do naszego API. Przyj\u0119li\u015bmy, \u017ce wys\u0142anie zapytania GET pod adres bez \u017cadnych argument\u00f3w zwr\u00f3ci nam list\u0119 liczb zapisanych w kontenerze numbers. Je\u015bli dodamy do adresu avg, to zostanie zwr\u00f3cona \u015brednia, a je\u015bli sum \u2013 to suma. Aby rozpozna\u0107 ka\u017cd\u0105 z tych sytuacji, wykorzystujemy metod\u0119 requestPath, kt\u00f3rej implementacj\u0119 omawia\u0142em wcze\u015bniej. W kolejnej linijce sprawdzamy, jak\u0105 wersj\u0119 zapytania wybra\u0142 u\u017cytkownik. Je\u015bli nic nie dopisa\u0142 do adresu naszego API, to znaczy \u017ce powinni\u015bmy mu zwr\u00f3ci\u0107 liczby zapisane w kontenerze.<\/p>\n\n\n\n<p>REST API zwykle zwraca wyniki swojej pracy w formie JSON. Musimy takiego JSON\u2019a stworzy\u0107. Kreujemy sobie kontener przechowuj\u0105cy jakie\u015b warto\u015bci (json::value) o nazwie jsonNumbers. Potem w p\u0119tli przechodzimy przez wszystkie elementy kontenera przechowuj\u0105cego nasze liczby, konstruujemy zawarto\u015b\u0107 \u201ewn\u0119trza\u201d tablicy, w kt\u00f3rej znajduje si\u0119 tylko liczba z danego obiegu p\u0119tli. Powsta\u0142y obiekt json::value dopisujemy do wcze\u015bniej utworzonej kolekcji number.<\/p>\n\n\n\n<p>Gdy p\u0119tla sko\u0144czy swoj\u0105 prac\u0119, musimy jeszcze konwertowa\u0107 kontener vector na tablic\u0119 JSON. Robi\u0105 to linijki 26 i 27. W linijce 28 wysy\u0142amy odpowied\u017a do u\u017cytkownika.<\/p>\n\n\n\n<p>A co, je\u015bli u\u017cytkownik chcia\u0142by pozna\u0107 \u015bredni\u0105 przechowywanych przez serwer liczb? Ten przypadek jest o wiele prostszy. Zwracamy tylko jedn\u0105 warto\u015b\u0107, wi\u0119c nie musimy bawi\u0107 si\u0119 w \u017cadne p\u0119tle czy tablice. Po prostu obliczamy \u015bredni\u0105. Tworzymy obiekt json::value number, kt\u00f3ry b\u0119dzie przechowywa\u0142 liczb\u0119, kt\u00f3r\u0105 zwr\u00f3cimy. Pod nazw\u0105 avg zapisujemy w nim obliczon\u0105 \u015bredni\u0105. Ostatecznie zwracamy wynik naszych dzia\u0142a\u0144 za pomoc\u0105 message.reply. Analogicznie wygl\u0105da obs\u0142uga sumy.<\/p>\n\n\n\n<p>Co, je\u015bli u\u017cytkownik rozszerzy zapytanie o co\u015b innego ni\u017c avg czy sum? Odpowiadamy mu, \u017ce zrobi\u0142 co\u015b \u017ale \u2013 linijka 43.<\/p>\n\n\n\n\n<div class=\"codecolorer-container cpp default\" style=\"overflow:auto;white-space:nowrap;width:90%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>47<br \/>48<br \/>49<br \/>50<br \/>51<br \/>52<br \/>53<br \/>54<br \/>55<br \/>56<br \/>57<br \/>58<br \/>59<br \/>60<br \/>61<br \/><\/div><\/td><td><div class=\"cpp codecolorer\"><span class=\"kw4\">void<\/span> Service<span class=\"sy4\">::<\/span><span class=\"me2\">handlePut<\/span><span class=\"br0\">&#40;<\/span>http_request message<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; message.<span class=\"me1\">extract_json<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">then<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#91;<\/span><span class=\"sy1\">=<\/span><span class=\"br0\">&#93;<\/span><span class=\"br0\">&#40;<\/span>pplx<span class=\"sy4\">::<\/span><span class=\"me2\">task<\/span><span class=\"sy1\">&lt;<\/span>json<span class=\"sy4\">::<\/span><span class=\"me2\">value<\/span><span class=\"sy1\">&gt;<\/span> task<span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw2\">try<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; json<span class=\"sy4\">::<\/span><span class=\"me2\">value<\/span> val <span class=\"sy1\">=<\/span> task.<span class=\"me1\">get<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw4\">int<\/span> number <span class=\"sy1\">=<\/span> val<span class=\"br0\">&#91;<\/span>U<span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;number&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#93;<\/span>.<span class=\"me1\">as_number<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">to_int32<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; numbers.<span class=\"me1\">push_back<\/span><span class=\"br0\">&#40;<\/span>number<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; message.<span class=\"me1\">reply<\/span><span class=\"br0\">&#40;<\/span>status_codes<span class=\"sy4\">::<\/span><span class=\"me2\">OK<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw2\">catch<\/span><span class=\"br0\">&#40;<\/span>std<span class=\"sy4\">::<\/span><span class=\"me2\">exception<\/span><span class=\"sy3\">&amp;<\/span> e<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; message.<span class=\"me1\">reply<\/span><span class=\"br0\">&#40;<\/span>status_codes<span class=\"sy4\">::<\/span><span class=\"me2\">BadRequest<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n\n\n\n<p>Zajmijmy si\u0119 teraz dodawaniem nowych liczb \u2013 metoda handlePut. W linijce 45 widzimy tajemniczy zapis: <strong>message.extract_json().then([=](pplx::task&lt;json::value&gt; task)<\/strong>. Korzystamy tu z mechanizmu \u201easynchroniczno\u015bci\u201d wprowadzonego w jednym z najnowszych standard\u00f3w C++. To, co znajduje si\u0119 poni\u017cej w nawiasach klamrowych jest wykonywane \u201etak jakby\u201d w oddzielnym w\u0105tku.<\/p>\n\n\n\n<p>Widzisz blok try,catch. Do czego on mo\u017ce s\u0142u\u017cy\u0107? Oczywi\u015bcie, do obs\u0142ugi sytuacji wyj\u0105tkowych. Nie mogli\u015bmy go pomin\u0105\u0107, gdy\u017c u\u017cytkownik mo\u017ce w ciele zapytania wpisa\u0107 jakie\u015b nieprawid\u0142owe dane. Mo\u017ce si\u0119 te\u017c zwyczajnie pomyli\u0107. Mimo przyj\u0119cia nieprawid\u0142owego zapytania, nasz serwer powinien kontynuowa\u0107 prac\u0119. W\u0142a\u015bnie dlatego zastosowali\u015bmy obs\u0142ug\u0119 wyj\u0105tk\u00f3w. Je\u015bli cia\u0142o zapytania b\u0119dzie posiada\u0142o b\u0142\u0119dy, rzucimy u\u017cytkownikowi BadRequestem. Z pewno\u015bci\u0105 to mu u\u015bwiadomi, \u017ce zrobi\u0142 co\u015b \u017ale.<\/p>\n\n\n\n<p>Je\u015bli wszystkie dane zosta\u0142y prawid\u0142owo wprowadzone, obs\u0142ugujemy zapytanie. Nie mamy wiele roboty. Odczytujemy zmienn\u0105 number z otrzymanego \u201ecia\u0142a\u201d JSON i zapisujemy j\u0105 do zmiennej number w naszym programie. T\u0119 liczb\u0119 dodajemy do kontenera i odpowiadamy u\u017cytkownikowi, \u017ce operacja si\u0119 powiod\u0142a.<\/p>\n\n\n\n<h2 class=\"western wp-block-heading\">Main.cpp<\/h2>\n\n\n\n<p>Om\u00f3wili\u015bmy ju\u017c budow\u0119 ca\u0142ego serwera, a jeszcze nie powiedzieli\u015bmy nic o najwa\u017cniejszej rzeczy &#8211; jak go uruchomi\u0107. No c\u00f3\u017c, zostawi\u0142em ten element na sam koniec gdy\u017c nie ma tu specjalnej filozofii. Sp\u00f3jrz na poni\u017cszy kawa\u0142ek kodu.<\/p>\n\n\n\n\n<div class=\"codecolorer-container cpp default\" style=\"overflow:auto;white-space:nowrap;width:90%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/><\/div><\/td><td><div class=\"cpp codecolorer\"><span class=\"co2\">#include &lt;iostream&gt;<\/span><br \/>\n<span class=\"co2\">#include &quot;Service.h&quot;<\/span><br \/>\n<span class=\"kw2\">using<\/span> <span class=\"kw2\">namespace<\/span> std<span class=\"sy4\">;<\/span><br \/>\n<br \/>\n<span class=\"kw4\">int<\/span> main<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; Service serv<span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;127.0.0.1&quot;<\/span>,<span class=\"st0\">&quot;8080&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; serv.<span class=\"me1\">setEndpoint<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;\/api&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; serv.<span class=\"me1\">accept<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">wait<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">while<\/span><span class=\"br0\">&#40;<\/span><span class=\"nu0\">1<\/span><span class=\"sy1\">==<\/span><span class=\"nu0\">1<\/span><span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; sleep<span class=\"br0\">&#40;<\/span><span class=\"nu0\">1000<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> <span class=\"nu0\">0<\/span><span class=\"sy4\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n\n\n\n<p>Dos\u0142ownie kilka linijek. Includujemy sobie plik &#8222;Service.h&#8221; kt\u00f3ry zawiera kod naszej us\u0142ugi. Tworzymy sobie obiekt tej klasy, podaj\u0105c mu jako argument adres i port. Ustawiamy nast\u0119pnie za pomoc\u0105 omawianej wcze\u015bniej funkcji setEndpoint pod jakim adresem ma by\u0107 widoczna ta us\u0142uga. W ko\u0144cu uruchamiamy serwer za pomoc\u0105 metody accept().<br>Jedynym elementem, kt\u00f3ry m\u00f3g\u0142by wzbudzi\u0107 w\u0105tpliwo\u015bci jest ta p\u0119tla, kt\u00f3ra znajduje si\u0119 na samym ko\u0144cu. Po co ona? serv.accept().wait() jest wywo\u0142aniem nieblokuj\u0105cym. Oznacza to, \u017ce program dalej kontynuowa\u0142by swoje dzia\u0142anie, gdy\u017c serwer uruchamia si\u0119 w oddzielnym w\u0105tku. Gdyby p\u0119tli nie by\u0142o, program natychmiast zako\u0144czy\u0142by swoje dzia\u0142anie. Aby nie marnowa\u0107 czasu procesora, umie\u015bci\u0142em w p\u0119tli wywo\u0142anie funkcji sleep na dosy\u0107 d\u0142ugi okres czasu.<\/p>\n\n\n\n<h1 class=\"western wp-block-heading\">Nasze API dzia\u0142a!<\/h1>\n\n\n\n<p>To tyle. Nasze API jest funkcjonalne i prawid\u0142owo reaguje na pro\u015bby u\u017cytkownika. Nie zawiesi si\u0119 te\u017c, gdy wprowadzone zostan\u0105 nieprawid\u0142owe dane.<\/p>\n\n\n\n<div class=\"wp-block-image size-full wp-image-296\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"806\" height=\"592\" src=\"https:\/\/www.kompikownia.pl\/wp-content\/uploads\/2018\/07\/Screenshot_20180726_143038.png\" alt=\"\" class=\"wp-image-296\"\/><figcaption>Dodawanie nowych liczb<\/figcaption><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image size-full wp-image-298\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"806\" height=\"592\" src=\"https:\/\/www.kompikownia.pl\/wp-content\/uploads\/2018\/07\/Screenshot_20180726_143532.png\" alt=\"\" class=\"wp-image-298\"\/><figcaption>Pobieranie sumy<\/figcaption><\/figure><\/div>\n\n\n\n<p>Z pewno\u015bci\u0105 chcia\u0142by\u015b przetestowa\u0107, jak ono pracuje. S\u0142u\u017cy do tego specjalna aplikacja Postman, kt\u00f3r\u0105 mo\u017cesz pobra\u0107 ze sklepu z aplikacjami dla Google Chrome. Obs\u0142uga jest intuicyjna. Niemniej, w niedalekiej przysz\u0142o\u015bci zajm\u0119 si\u0119 dok\u0142adniejszym opisaniem tego wspania\u0142ego programu.<\/p>\n\n\n\n<p>W swoim zakresie spr\u00f3buj rozszerzy\u0107 powy\u017cszy program o obs\u0142ug\u0119 usuwania liczb. Mo\u017cesz to zrobi\u0107 na dwa sposoby: albo odczytywa\u0107 z liczb\u0119\/indeks liczby do usuni\u0119cia z cia\u0142a metody JSON, albo przekazywa\u0107 \u017c\u0105danie przez URL.<\/p>\n\n\n\n<p>Kod omawiany w tym artykule znajduje si\u0119 w moim repozytorium na Githubie.<a href=\"https:\/\/github.com\/karol221-10\/blog_apps\/tree\/master\/cpprestapi\"> (o w\u0142a\u015bnie tutaj!) <\/a><\/p>\n\n\n\n<p>Na dzisiaj to tyle. Do zobaczenia \ud83d\ude42 Zapraszam do czytania moich kolejnych artyku\u0142\u00f3w.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Czas czytania:<\/span> <span class=\"rt-time\">5<\/span> <span class=\"rt-label rt-postfix\">minut<\/span><\/span> Przed lektur\u0105Aby\u015b zrozumia\u0142 tre\u015b\u0107 tego wpisu by\u0142oby dobrze, aby\u015b wiedzia\u0142 co to jest REST API oraz do czego ono s\u0142u\u017cy. W tre\u015bci tego wpisu nie b\u0119d\u0119 si\u0119 rozwodzi\u0142 nad tym &#8230;<\/p>\n","protected":false},"author":1,"featured_media":298,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[31],"tags":[],"_links":{"self":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts\/270"}],"collection":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/comments?post=270"}],"version-history":[{"count":37,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts\/270\/revisions"}],"predecessor-version":[{"id":1205,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts\/270\/revisions\/1205"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/media\/298"}],"wp:attachment":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/media?parent=270"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/categories?post=270"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/tags?post=270"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}