📜 ⬆️ ⬇️

Silicon Framework - WebAPI on C ++

Note translator: in the C ++ syntax, the tools for constructing domain-specific languages ​​are completely lacking . As a result, few of them in C ++ try to use them, and attempts to do so are of interest, especially when you end up with something that looks slim and practically useful. One of such discoveries for me was the Silicon framework, which is trying to use the tools of modern C ++ to quickly and flexibly implement WebAPI in my project. Let's see how simple it looks.

Hello World at Silicon - a program that is an HTTP request to
  http: // host / hello / world 
will respond with code 200 with the text “hello world”:
auto my_api = http_api(GET / _hello / _world = [] () { return "hello world";}); mhd_json_serve(my_api, 80); 


Not bad, right? my_api here is the description of our API, and mhd_json_serve is a backend of the Silicon framework that implements this API using the built-in web server (a choice of microhttpd or LWAN ).
')
Let's see what else Silicon can do.

Return JSON
 GET / _hi = [] () { return D(_name = "John", _age = 42); } 


Handling parameters of all types
 POST / _hello / _id[int()] // URL- * get_parameters(_name) // GET- * post_parameters(_age = int()) // POST- = [] (auto p) // p    { std::ostringstream ss; ss << p.name << p.age << p.id; return ss.str(); } 


Optional Parameters
 GET / _hello * get_parameters(_id = optional(int(42))) 


Bonding layer
If you write WebAPI, then with high probability you may need access to the database. On Silicon, it looks like this:

 auto my_api = http_api( GET / _username / _id[int()] = [] (auto p, mysql_connection& db) { std::string name; db("SELECT name from User where id = ?")(id) >> name; return D(_name = name); } ); auto middlewares = std::make_tuple( mysql_connection_factory("localhost", "user", "password", "database_name") ); mhd_json_serve(my_api, middlewares, 8080); 


MySQL and Sqlite are supported.

Errors
To return HTTP error codes, exceptions are used:

 GET / _test / _id[int()] = [] (auto p) { if (p.id != 42) //   401 (Unauthorized) throw error::unauthorized("Wrong ID"); return "success"; } 


Sessions
We, of course, can remember user sessions (in a database or in memory):

 struct session { int id; }; auto api = http_api( GET / _set_id / _id[int()] = [] (auto p, session& s) { s.id = p.id; }, GET / _get_id = [] (session& s) { return D(_id = s.id); } ); auto middlewares = std::make_tuple( hashmap_session_factory<session>() ); mhd_json_serve(my_api, middlewares, 8080); 


Testing created webAPI
Not much use from WebAPI, if all its methods are not tested. Fortunately, Silicon allows, based on the described API, to get a client based on libcurl_json_client, with ready-made functions for calling methods of our API. It can be used both for testing and in a real client.

 //  API auto my_api = http_api( POST / _hello / _world / _id[int()] * get_parameters(_name, _city) = [] (auto p) { return D(_id = p.id, _name = p.name, _city = p.city); } ); //   auto server = sl::mhd_json_serve(hello_api, 8080, _non_blocking); //   auto c = libcurl_json_client(my_api, "127.0.0.1", 8080); // c.http_get  GET- // c.http_post  POST- // c.http_put  PUT- // c.http_delete  DELETE- //         auto r = c.http_post.hello.world(_id = 42, _name = "John", _city = "Paris"); assert(r.status == 200); assert(r.response.id == 42); assert(r.response.name == "John"); assert(r.response.city == "Paris"); 

Source: https://habr.com/ru/post/280214/


All Articles