Rest sdk

18
www.italiancpp.org Italian C++ Conference 2016 14 Maggio, Milano REST e Websocket in C++ diventano semplici e produttivi con il REST SDK Raffaele Rialdi Twitter: @raffaeler Email: [email protected] Website: http://iamraf.net

Transcript of Rest sdk

Page 1: Rest sdk

www.italiancpp.org

Italian C++ Conference 201614 Maggio, Milano

REST e Websocket in C++ diventano semplici e produttivi con il REST SDKRaffaele Rialdi

Twitter: @raffaelerEmail: [email protected]: http://iamraf.net

Page 2: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

Chi sono …• Lavoro nella programmazione software dal 1987•Senior Software Architect in Vevy Europe•Consulente in diversi ambiti (finanziario, automotive, racing, manufacturing, healthcare)

• Specializzato sul mondo Microsoft•Ho iniziato con il DOS 1.0 … e ho seguito tutto ciò che è venuto dopo•Linguaggi preferiti: C++ e C#•Prediligo le tecnologie di "basso" livello e la «application security»•Microsoft MVP dall'anno 2003

• Trainer e speaker•Ho insegnato informatica per anni (e salutariamente continuo)•Partecipo a varie conferenze italiane e internazionali

Page 3: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

Cos'è Casablanca REST SDK?•Una libreria che semplifica l'accesso a servizi REST e comunicazioni

Websocket•Provvede anche servizi base (in beta) per creare semplici HTTP Server

• Si basa su alcuni «pillars» fondamentali:1. Gestione asincrona basata sui Task

2. Utilizzo di C++ "moderno" (è nata al momento dello standard C++11)

3. Cross-platform (Windows Desktop/Store/Phone, Linux, Android, Mac, iOS)

4. Cerca di offrire tutti i «building blocks» indispensabili (Json, Uri, conversioni Unicode, OAuth, etc.)

Page 4: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

I problemi del cross-platform• In Windows, le stringhe sono wide (16 bit)•wchar_t, wstring, …

• In Posix (Linux, Unix) le stringhe sono narrow (8 bit)•char, string, …• Il REST SDK definisce un tipo neutrale

•Conversioni disponibili• to_string_t, to_utf8string, to_utf16string

utility::string_t

#ifdef _UTF16_STRINGStypedef wchar_t char_t ;typedef std::wstring string_t;#define _XPLATSTR(x) L ## xtypedef std::wostringstream ostringstream_t;typedef std::wofstream ofstream_t;typedef std::wostream ostream_t;typedef std::wistream istream_t;typedef std::wifstream ifstream_t;typedef std::wistringstream istringstream_t;typedef std::wstringstream stringstream_t;#define ucout std::wcout#define ucin std::wcin#define ucerr std::wcerr#else...

basic_types.h

U("Hello, world")

std::string ansiRaf("raffaele");string_t raf_t(to_string_t(ansiRaf));std::string(begin(raf_t), end(raf_t));

Page 5: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

PPL in una slide• Dimenticate i thread, pensate a task

• Motivazioni: cross-platform, scalabilità, migliore schedulazione, codice più pulito, richiesto nelle applicazioni mobile

• Ok, da domani li uso … ma che problemi ci sono?• Le STL sono sincrone, co-routines non fanno parte dello standard, i «futures» hanno diverse lacune

• Arrivano le «Parallel Pattern Library» in soccorso• creare un task• scrivere una continuation

• continuation con co_await

• usare i task_completion

• Un task setta il risultato

• L'altro task è un attesa del risultato

#include <ppl.h>using namespace concurrency;

return create_task([] () {});SumAsync(10, 20).then([=](int sum) { Process(sum); };int result = co_await SumAsync(10, 20);Process(result);

task_completion_event<bool> quit;

quit->set(true);

bool result = co_await pplx::task<bool>(quit);

Page 6: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

concurrency::stream cheat sheet

basic_istream<>

stdio_istream<> async_iostream<>

basic_iostream<>

std

concurrency::streams

namespaces

concurrency::streams::details

streambuf<>

basic_streambuf<>

container_buffer<>

producer_consumer_buffer<>

rawptr_buffer<>

basic_ostream<>

stdio_ostream<> async_ostream<>

basic_ostream<>

async_istream<>

basic_istream<>

astreambuf.h

interopstream.h

streams.h

containerstream.h

bytestream(factory)

containerstream.h

container_stream<>(factory)

containerstream.h

producerconsumerstream.h

rawptrstream.h

rawptr_stream(factory)

rawptrstream.h

interopstream.h

interopstream.h

astreambuf.h

streams.h

interopstream.h

interopstream.h

Page 7: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

typedefs definiti dal REST SDK typedef container_stream<std::basic_string<char>>stringstream;typedef stringstream::buffer_type stringstreambuf;

typedef container_stream<utility::string_t> wstringstream;typedef wstringstream::buffer_type wstringstreambuf;

typedef file_stream<uint8_t> fstream;

typedef basic_ostream<uint8_t> ostream;typedef basic_istream<uint8_t> istream;

typedef basic_ostream<utf16char> wostream;typedef basic_istream<utf16char> wistream;

Page 8: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

File streams – leggere un file di testo

file_buffer<>

file_stream<>(factory)

filestream.h

std

concurrency::streams

namespaces

concurrency::streams::details

std::string Test1(const string_t& filename){ auto istr = slx::fstream::open_istream(filename, std::ios::in).get(); slx::stringstreambuf strbuf; auto size = istr.read_to_end(strbuf).get(); istr.close(); string content = strbuf.collection(); cout << content.c_str(); return content;}

task<std::string> Test1Async2(const string_t& filename){ auto istr = co_await slx::fstream::open_istream(filename, std::ios::in); slx::stringstreambuf strbuf; auto size = co_await istr.read_to_end(strbuf); istr.close(); string content = strbuf.collection(); cout << content.c_str(); return content;}Nota: Al momento co_await funziona solo se viene aggiunto /await alla riga di comando del compilatore

Page 9: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

File streams – copiare un file

file_buffer<>

file_stream<>(factory)

filestream.h

std

concurrency::streams

namespaces

concurrency::streams::details

void Test3(const string_t& source, const string_t& target){

auto istr = slx::fstream::open_istream(source, std::ios::in).get();

auto ostr = slx::fstream::open_ostream(target, std::ios::out).get();

slx::producer_consumer_buffer<char> buffer; int size = 110; // dimensione del blocco da copiare

while (auto ilen = istr.read(buffer, size).get()) {

auto olen = ostr.write(buffer, ilen).get(); }

istr.close(); ostr.close();}

co_await

co_await

co_await

co_await

Nota: Al momento co_await funziona solo se viene aggiunto /await alla riga di comando del compilatore

Page 10: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

I building block di rete• Le tre classi principali sono:•http_client: astrazione su tre librerie• boost::asio per il mondo *nix• WinHttp per Windows Desktop• WinRT per il Windows Store

•http_listener (beta): astrazione su:• boost::asio per il mondo *nix• Http.sys per il mondo Windows Desktop• WinRT vieta l'uso di listener nelle App (security!)

•websocket_client: astrazione su:• Websocket++ per tutti gli OS tranne …• WinRT offre il suo supporto nativo

Boost::Asio WinHttp WinRT

http_client

Boost::Asio Http.Sys

http_listener

WebsocketPP WinRT

websocket_client

Page 11: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

Features vs Sistema Operativo  Windows 

DesktopWindows Store WP 8 WP 8.1 WP 8.1

SilverlightWindows XP

Linux (Ubuntu)

Mac OS X iOS  Android

 

Programming with Tasks

JSONAsynchronous StreamsURIs

HTTP Client

HTTP Listener (Beta) (Beta) (Beta) (Beta) (Beta)

WebSocket Client

OAuth Client (Beta) (Beta)(Beta,

OAuth2 only)

(Beta, OAuth2

only)

(Beta, OAuth2

only)

(Beta, OAuth2

only)(Beta) (Beta) (Beta) (Beta)

Page 12: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

Leggere/scrivere JSON#include "cpprest\json.h"

json::value root2(100);

auto root6 = json::value::string(U("hello, world"));

vector<pair<string_t, json::value>> props...auto root2 = json::value::object(props);

Creare un intero:

Creare una stringa:

Creare un oggetto:

using namespace web;using namespace utility;using namespace utility::conversions;

auto jsonText = U("[ \"Book\", \"Pencil\" ]");auto json = json::value::parse(jsonText);

Deserializzazione:

void print(const json::value& val){ string_t text = val.serialize(); std::string utf8 = to_utf8string(text); cout << utf8.c_str() << endl;}

Serializzazione:

Page 13: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

tip: deserializzare in un boost::variant

1. 2. definire un tipo "metamorfico"

3. ciclare le proprietà del json::object e deserializzare ogni valore in un "universal"

4. boost::variant è "iostream" friendly

typedef boost::variant<bool, double, int, std::string> universal;

#include "boost\variant\variant.hpp"

if (val.is_string()){ auto stringt = val.as_string(); return universal(string(begin(stringt), end(stringt)));}

if (val.is_boolean()) return universal(val.as_bool());if (val.is_double()) return universal(val.as_double());...

Page 14: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

http_client in action1. Costruire del client2. Costruire una request3. Aggiungere gli header

4. Aggiungere il body (POST)5. Eseguire la chiamata6. Controllare http status7. Leggere il contenuto

http_client client(_address);

http_request request(methods::POST);

request.headers().add(header_names::user_agent,U("IAmRaf agent"));

request.set_body(body);

auto resp = co_await client.request(request);

http_response

if (response.status_code() == status_codes::OK)

auto json = co_await resp.extract_json();

Page 15: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

http_listener (beta)1. Dichiarare uno smart ptr2. Creare il listener3. Binding per ogni verb

4. Iniziare la Listen sulla rete

unique_ptr<http_listener> _listener;

_listener = make_unique<http_listener>(address);_listener->support(methods::GET, std::bind(&Listener::handle_get, this, std::placeholders::_1));

co_await _listener->open();

#include "cpprest\http_listener.h"

Page 16: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

websocket_client1. Creare il client2. Aprire la connessione3. Creare un messaggio (out)4. Impostare il contenuto5. Spedire il messaggio6. Ricevere la risposta7. Leggere il body8. Leggere il body type9. Leggere il contenuto

co_await client->connect(U("ws://server/...");

client = std::make_unique<websocket_client>();

websocket_outgoing_message message;

message.set_utf8_message("hello, world");

websocket_incoming_message message =co_await client->receive();

client->send(message);

istream body = message.body();websocket_message_type messageType =

message.message_type();

auto text = co_await message.extract_string();

RFC 6455

Page 17: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

tip: subprotocollo e headers Websockets• Il protocollo Websocket inizia con un handshake HTTP• Segue una notifica « 101 – Upgrade »• E una negoziazione di un "subprotocol" definito a livello applicativo

Ecco i passi per poter aggiungere headers e subprotocollo

• Create the options•Add the sub-protocol•Add headers

websocket_client_config config;

config.add_subprotocol(U("subprotocol-raf"));config.headers().add(U("X-Raf"),

to_string_t("C++ Native Client"));

RFC 6455

Page 18: Rest sdk

Italian C++ Conference 2016 – Un evento dell’Italian C++ Community

Domande? #include <iostream>

#include <sstream>

#include <vector>

#include <cpprest\json.h>

#include <cpprest\

http_client.h>

#include <cpprest\ws_client.

h>

Raffaele RialdiTwitter: @raffaelerEmail: [email protected]