matt-42 / silicon

A high performance, middleware oriented C++14 http web framework please use matt-42/lithium instead
http://siliconframework.org
MIT License
1.73k stars 138 forks source link

a convenient HTTP client for calling other APIs #56

Open tedli opened 7 years ago

tedli commented 7 years ago

silicon is really an awesome framework, thanks for the great work.

When writting APIs using silicon, I need to call other RESTful APIs what are served as http service.

I wrote dummy sl::http_api, and use libcurl_json_client to make requests.

However the libcurl_json_client seemed designed for testing. Found no way to specify something like a auth header nor ways to retrieve headers from the response.

It will be really convenient if I can write some code like this:

auto client = https("127.0.0.1") | port(8080) | opt(_insecure_skip_verify = true) | prefix(_api / _v1);

auto create_pod = client.post(_namespaces / _namespace[std::string()] / pods) | body<yaml_encoder>(
    D(_name = "a_name", _image = optional(std::string("alpine")))) | headers("Authorization", _auth[std::string()])
    | headers("a_header_key", "a_header_value") | content_type("application/x-yaml"); // content type could be set by the encoder.

auto response = create_pod(_namespace = "kube-system", _auth = "Basic c2lsaWNvbjphd2Vzb21lCg==");
auto a_sturct = create_pod<json_decoder>(_namespace = "kube-system", _auth = "Basic c2lsaWNvbjphd2Vzb21lCg==", _image = "busybox"); // decoder could access the response body and headers.

istream& raw_body = create_pod<raw>(_namespace = "kube-system", _auth = "Basic c2lsaWNvbjphd2Vzb21lCg==");

std::unordered_map<std::string, std::string> some_headers = {
    {"Authorization", "Basic c2lsaWNvbjphd2Vzb21lCg=="},
    {"key", "value"}
};

auto response = request<post>("http://127.0.0.1:8080/api/v1/namespaces/kube-system/pods", _body = D(_name = "a_name"), _headers = some_headers);

int status = response.status_code;

istream& raw_body = response.body<raw>();

auto struct_body = response.body<some_decoder>();

std::unordered_map<std::string, std::string> response_headers = response.headers();
auto struct_header = response.headers<some_parser>();

auto ws_client = http("127.0.0.1");
auto events = ws_client.watch(_apis / _batch / _v1 / _watch / _namespaces / _namespace[std::string()] / jobs / _name[std::string()]);

events = events | on_message([] (some_struct& message) {
    // do some thing.
});

events = events | _on_close = [] (some_struct& message) {
    // do some thing.
};

auto sync = events(_namespace = "kube-system", _name = "busybox");
sync.wait();

I write some c++, but lack of experience and advanced skills to write such elegant code like silicon. But I can still try to give a hand.

matt-42 commented 7 years ago

Thanks @tedli for you feedback. Yes, libcurl_json_client is mainly designed for testing, and it is true that silicon lack of a good http client to call others APIs. For now, I suggest you to use the libcurl C library: https://curl.haxx.se/libcurl/c/ . I think that it's better wait for coroutines (soon available in Clang) to write a C++ http client since they will enable async requests implementation.