An ultra-fast light-weight REST-WS server based on features of C++17 intended to quickly and easily implement microservices.
The usage model of this framework is inspired by frameworks in other languages, such as Express.js and SparkJava.
Here is a small Hello World example
#include <iostream>
#include "just_resting.hxx"
using namespace std;
using namespace std::literals;
using namespace just_resting;
int main() {
auto app = Application{};
app.port(4200, true); //true --> find an available port if the primary is busy
app.debug(true);
app.route("GET"s, "/"s, [&](Request& req, Response& res) {
res.body("Hi there"s);
});
cout << app << endl;
app.launch([](auto port) {
cout << "Hello server started. URL = http://localhost:" << port << endl;
});
return 0;
}
Given that the build output is in ../dist
the program can be compiled with
c++ --std=c++17 -I../dist/include hello.cxx -o hello ../dist/lib/just_resting.a
Then, launch the program
> ./hello
JustRESTing/1.0 [(C) Ribomation AB, 2018.]
-- Routes --
GET /
Hello server started. URL = http://localhost:4200
Using a HTTP client such as HTTPie it might look like this from the client side
> http :4200
HTTP/1.1 200 OK
Content-Length: 8
Content-Type: text/plain
Date: Thu, 21 Jan 2021 13:07:51 GMT
Server: JustRESTing/0.1
Hi there
and, like this from the server side (debug printouts was enabled)
client connected: IP=127.0.0.1
>>> REQ payload-size=135
GET / HTTP/1.1<CR><NL>
Host: localhost:4200<CR><NL>
User-Agent: HTTPie/1.0.3<CR><NL>
Accept-Encoding: gzip, deflate<CR><NL>
Accept: */*<CR><NL>
Connection: keep-alive<CR><NL>
<CR><NL>
**END**
Although your can download and build the library yourself, and then build your own
app from the dist/
artifacts as shown above. However, it's much more easier to use
CMake and let it download and configure the library for you, using
FetchContent
First create a CMakeLists.txt
file:
cmake_minimum_required(VERSION 3.16)
project(app LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
include(FetchContent)
FetchContent_Declare(just_resting
GIT_REPOSITORY https://github.com/ribomation/just_resting.git
GIT_SHALLOW true
GIT_TAG main
)
FetchContent_MakeAvailable(just_resting)
add_executable(app app.cxx)
target_link_libraries(app PRIVATE ribomation::just_resting)
Second, create the C++ file app.cxx
(simplified version of the hello app above):
#include <iostream>
#include "just_resting.hxx"
using namespace std;
using namespace std::literals;
using namespace just_resting;
int main() {
Application srv;
srv.port(3500, true);
srv.route("GET"s, "/"s, [](Request& req, Response& res) {
res.body("Hi there, from a justRESTing microservice"s);
});
srv.launch([](auto port){
cout << "server started. http://localhost:" << port << endl;
});
return 0;
}
Third, build the server app. During the configuration phase of CMake, it will perform a shallow (just the files, no history) clone of the justRESTing GIT repo.
mkdir bld && cd bld
cmake ..
cmake --build .
Finally, launch the server, still within the build directory
./app
Here is an example of using HTTPie CLI
http :3500
Which provides the following output:
HTTP/1.1 200 OK
Content-Length: 41
Content-Type: text/plain
Date: Sat, 23 Jan 2021 13:51:34 GMT
Server: JustRESTing/0.1
Hi there, from a justRESTing microservice
The build system is based on CMake. Create a build directory, generate the build files and then build the library. During the build, it will also run the unit test suite.
cd path/to/the/just_resting/project/dir
mkdir bld && cd bld
cmake ..
cmake --build .
You can generate a tar file which can be used elsewhere. Run the following command
cmake --build . --target dist
It will generate GZIP:ed TAR file in the build directory, containing the library archive
(lib/just_resting.a
) file and the public include files (include/**.hxx
).
You can run the unit tests (based on Catch2) with the following command
cmake --build . --target test
There is a small show-case application inside ./demo/
which can be run with the command
cmake --build . --target demo
Then open a browser to http://localhost:4200/
A HTTP transaction can be intercepted by one or more filters. Just write a
class/struct that inherits from just_resting::Filter
and implement the
invoke()
method.
Here is a simple CORS filter
struct CorsFilter : just_resting::Filter {
void invoke(just_resting::Request& req, just_resting::Response& res, just_resting::Route& route) override {
auto const method = req.method();
if (method == "GET"sv || method == "HEAD"sv) {
next()->invoke(req, res, route);
res.header("Access-Control-Allow-Origin"s, "*"s);
} else if (method == "OPTIONS"sv) {
res.status(204, "No content"s);
res.header("Content-Length"s, "0"s);
res.header("Access-Control-Allow-Origin"s, "*"s);
auto headers = req.header("Access-Control-Request-Headers");
if (headers) {
res.header("Access-Control-Allow-Headers"s, std::string{headers->cbegin(), headers->cend()});
}
auto methods = req.header("Access-Control-Request-Methods");
if (methods) {
res.header("Access-Control-Allow-Methods"s, std::string{methods->cbegin(), methods->cend()});
}
} else {
next()->invoke(req, res, route);
res.header("Access-Control-Allow-Origin"s, "*"s);
}
}
};
Instantiate the filter and add it. In addition, you need to provide an (empty) OPTIONS route.
auto API = "/api"s;
srv.route("GET"s, API, [](Request& req, Response& res) {
res.body("Hi there, from a justRESTing microservice"s);
});
srv.route("OPTIONS"s, API, [](Request& req, Response& res) { /*empty*/ });
srv.route("POST"s, API, [](Request& req, Response& res) {
auto txt = string{req.body().cbegin(), req.body().cend()};
transform(txt.begin(), txt.end(), txt.begin(), [](auto ch) { return ::toupper(ch); });
res.body(txt);
});
When it comes to JSON for C++, my favorite is JSON for Modern C++ by Niels Lohmann
Using CMake, you can easily download and configure the library using FetchContent.
First add this snippet to CMakeLists.txt
FetchContent_Declare(json
GIT_REPOSITORY https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent
GIT_TAG v3.9.1
GIT_SHALLOW true
)
FetchContent_MakeAvailable(json)
Second, add the library to your application
add_executable(app)
target_sources(app PRIVATE app.cxx ... )
target_link_libraries(tools_srv PRIVATE
ribomation::just_resting
nlohmann_json::nlohmann_json
)
Third, import the header and set the namespace
#include "nlohmann/json.hpp"
namespace js = nlohmann;
Finally, use it
srv.route("GET"s, uri, [min, max, name](ws::Request& req, ws::Response& res) {
auto result = js::json{
{"name"s, name},
{"min"s, min},
{"max"s, max},
};
res.body(result.dump());
});
Here is a sample output (using HTTPie)
http :5000/api/tools/temperature
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 42
Content-Type: text/plain
Date: Sun, 24 Jan 2021 16:04:42 GMT
Server: JustRESTing/0.1
{
"max": 120,
"min": -40,
"name": "temperature"
}
This software is provided as is, without any implied warranties etc.