Refine the REST examples; refine the http message parsing.

This commit is contained in:
Adam Gu
2018-04-13 17:52:40 +08:00
parent 803ae3eb5f
commit 4e35648b29
9 changed files with 264 additions and 101 deletions
+1 -1
View File
@@ -6,5 +6,5 @@ file(GLOB SRCS *.cc *.h)
add_executable(rest_book_client ${SRCS})
target_link_libraries(rest_book_client webcc ${Boost_LIBRARIES})
target_link_libraries(rest_book_client webcc jsoncpp ${Boost_LIBRARIES})
target_link_libraries(rest_book_client "${CMAKE_THREAD_LIBS_INIT}")
+172 -50
View File
@@ -1,87 +1,209 @@
#include <iostream>
#include "boost/algorithm/string.hpp"
#include "json/json.h" // jsoncpp
#include "webcc/http_client.h"
#include "webcc/http_request.h"
#include "webcc/http_response.h"
class BookListClient {
////////////////////////////////////////////////////////////////////////////////
class BookClientBase {
public:
BookListClient() {
host_ = "localhost";
port_ = "8080";
BookClientBase(const std::string& host, const std::string& port)
: host_(host), port_(port) {
}
bool Request(const std::string& method,
const std::string& url,
const std::string& content,
webcc::HttpResponse* http_response) {
webcc::HttpRequest http_request;
http_request.set_method(method);
http_request.set_url(url);
http_request.SetHost(host_, port_);
if (!content.empty()) { // TODO
http_request.SetContent(content);
}
http_request.Build();
webcc::HttpClient http_client;
webcc::Error error = http_client.SendRequest(http_request, http_response);
return error == webcc::kNoError;
}
protected:
std::string host_;
std::string port_;
};
////////////////////////////////////////////////////////////////////////////////
class BookListClient : public BookClientBase {
public:
BookListClient(const std::string& host, const std::string& port)
: BookClientBase(host, port) {
}
bool ListBooks() {
webcc::HttpRequest http_request;
http_request.set_method(webcc::kHttpGet);
http_request.set_url("/books");
http_request.SetHost(host_, port_);
http_request.Build();
webcc::HttpResponse http_response;
webcc::HttpClient http_client;
webcc::Error error = http_client.SendRequest(http_request, &http_response);
if (error != webcc::kNoError) {
if (!Request(webcc::kHttpGet, "/books", "", &http_response)) {
return false;
}
std::cout << "Book list: " << std::endl
<< http_response.content() << std::endl;
std::cout << http_response.content() << std::endl;
return true;
}
private:
std::string host_;
std::string port_;
bool CreateBook(const std::string& id,
const std::string& title,
double price) {
Json::Value root(Json::objectValue);
root["id"] = id;
root["title"] = title;
root["price"] = price;
Json::StreamWriterBuilder builder;
std::string book_json = Json::writeString(builder, root);
webcc::HttpResponse http_response;
if (!Request(webcc::kHttpPost, "/books", book_json, &http_response)) {
return false;
}
std::cout << http_response.status() << std::endl;
return true;
}
};
class BookDetailClient {
////////////////////////////////////////////////////////////////////////////////
class BookDetailClient : public BookClientBase {
public:
BookDetailClient() {
host_ = "localhost";
port_ = "8080";
BookDetailClient(const std::string& host, const std::string& port)
: BookClientBase(host, port) {
}
bool GetBook(const std::string& id) {
webcc::HttpRequest http_request;
http_request.set_method(webcc::kHttpGet);
http_request.set_url("/books/" + id);
http_request.SetHost(host_, port_);
http_request.Build();
webcc::HttpResponse http_response;
webcc::HttpClient http_client;
webcc::Error error = http_client.SendRequest(http_request, &http_response);
if (error != webcc::kNoError) {
if (!Request(webcc::kHttpGet, "/books/" + id, "", &http_response)) {
return false;
}
std::cout << "Book: " << id << std::endl
<< http_response.content() << std::endl;
std::cout << http_response.content() << std::endl;
return true;
}
private:
std::string host_;
std::string port_;
};
int main() {
BookListClient book_list_client;
book_list_client.ListBooks();
////////////////////////////////////////////////////////////////////////////////
BookDetailClient book_detail_client;
book_detail_client.GetBook("1");
std::string g_host;
std::string g_port;
void ListBooks() {
std::cout << "List books" << std::endl;
BookListClient client(g_host, g_port);
client.ListBooks();
}
void CreateBook(const std::string& id,
const std::string& title,
double price) {
std::cout << "Create book: " << id << " " << title << " " << price << std::endl;
BookListClient client(g_host, g_port);
client.CreateBook(id, title, price);
}
void Help(const char* argv0) {
std::cout << "Usage: " << argv0 << " <host> <port>" << std::endl;
std::cout << " E.g.," << std::endl;
std::cout << " " << argv0 << " localhost 8080" << std::endl;
}
std::string GetUserInput() {
char input[256];
std::size_t length = 0;
do {
std::cout << ">> ";
std::cin.getline(input, 256);
length = strlen(input);
} while (length == 0);
return input;
}
int main(int argc, char* argv[]) {
if (argc != 3) {
Help(argv[0]);
return 1;
}
g_host = argv[1];
g_port = argv[2];
// Type commands to execute actions.
// Commands: list, create, update, remove
// Examples:
// >> list
// >> create 1 { "title": "1984", "price": 12.3 }
// >> detail 1
// >> update 1 { "price": 32 }
// >> delete 1
while (true) {
std::string input = GetUserInput();
boost::trim(input);
std::string command;
std::size_t i = input.find(' ');
if (i == std::string::npos) {
command = input;
} else {
command = input.substr(0, i);
}
if (command == "exit") {
break;
}
if (command == "list") {
ListBooks();
continue;
}
++i;
std::size_t j = input.find(' ', i);
std::string id = input.substr(i, j - i);
i = j + 1;
if (command == "create") {
std::string json = input.substr(i);
std::cout << "json:" << json << std::endl;
Json::Value root;
Json::CharReaderBuilder builder;
std::string errs;
if (Json::parseFromStream(builder, std::stringstream(json), &root, &errs)) {
CreateBook(id, root["title"].asString(), root["price"].asDouble());
} else {
std::cerr << errs << std::endl;
}
}
}
//BookDetailClient book_detail_client(host, port);
//book_detail_client.GetBook("1");
return 0;
}
+34 -10
View File
@@ -1,6 +1,7 @@
#include "book_services.h"
#include <list>
#include <iostream>
#include "boost/lexical_cast.hpp"
#include "json/json.h" // jsoncpp
@@ -28,16 +29,16 @@ public:
}
};
std::ostream& operator<<(std::ostream& os, const Book& book) {
os << "{ " << book.id << ", " << book.title << ", " << book.price << " }";
return os;
}
static const Book kNullBook{};
class BookStore {
public:
BookStore() {
// Prepare test data.
books_.push_back({ "1", "Title1", 11.1 });
books_.push_back({ "2", "Title2", 22.2 });
books_.push_back({ "3", "Title3", 33.3 });
}
BookStore() = default;
const std::list<Book>& books() const {
return books_;
@@ -87,16 +88,39 @@ bool BookListService::Handle(const std::string& http_method,
const std::string& request_content,
std::string* response_content) {
if (http_method == webcc::kHttpGet) {
// Return all books as a JSON array.
Json::Value root(Json::arrayValue);
for (const Book& book : g_book_store.books()) {
root.append(book.ToJson());
}
Json::StreamWriterBuilder wbuilder;
*response_content = Json::writeString(wbuilder, root);
Json::StreamWriterBuilder builder;
*response_content = Json::writeString(builder, root);
return true;
}
if (http_method == webcc::kHttpPost) {
// Add a new book.
Json::Value root;
Json::CharReaderBuilder builder;
std::stringstream stream(request_content);
std::string errs;
if (!Json::parseFromStream(builder, stream, &root, &errs)) {
std::cerr << errs << std::endl;
return false;
}
Book book;
book.id = root["id"].asString();
book.title = root["title"].asString();
book.price = root["price"].asDouble();
return g_book_store.AddBook(book);
}
return false;
}
@@ -119,8 +143,8 @@ bool BookDetailService::Handle(const std::string& http_method,
return false;
}
Json::StreamWriterBuilder wbuilder;
*response_content = Json::writeString(wbuilder, book.ToJson());
Json::StreamWriterBuilder builder;
*response_content = Json::writeString(builder, book.ToJson());
return true;