Http
FuzeHttp[github] is a web framework written in C++23, designed for modern REST API-based services. It is gradually being developed in an ad-hoc way, to meet the growing needs of Fuze Mediaboard.
Building the example project
The easiest way to get started is to set up the example project, and then work from there. If you have deployed Fuze Mediaboard before, these steps will be very familiar.Compiling from source
Prerequisites: Git, CMake (>= 3.28), Boost (>= 1.88), SQLite OR PostgreSQL.
First ensure that submodules are downloaded. Use this command:
git submodule update --init --recursive
Now, to compile the server:
cmake -B build -G Ninja -D WITH_EXAMPLE=ON
cmake --build build
Compiling is known to work with clang-19, but not GCC 14.
Running the example project
This is the same procedure to create the owner account, as in Fuze Mediaboard.
If compiled from source, execute ./build/bin/example --create_owner
The --create_owner flag is required on first boot. When the server starts, an invitation link will appear in the command-line output.
If you ever forget the password, you can simply run the create_owner command again. Note that it will not be the same account.
Program options
Options can be defined in config.ini or passed in at runtime. Run the server with --help to see all available options. Some options are built-in, such as threads and environment_variable_for_secret.
Additional options can be defined. The container for additional options is instantiated in this way:
FuzeHttp::ProgramOptions options;
We can see the three option types inherited from FuzeHttp::ProgramOptionBase in the example project's addProgramOptions function:
options->addOptions()
(new ProgramOption<std::string>("favicon_url", "https://fuze.page/favicon.ico"))
(new ProgramConstant("test_program_constant", 73))
(new ProgramOptionPtr("site_name", &state_config->server_name, {.default_value=std::string("FuzeHttp Example")}));
These classes accept a template argument OptionType, which can be any type with an operator>> overload. Here is a description of the three option types:
| class | description |
|---|---|
template<typename OptionType> | The default_value is stored within this object and can be overridden by config.ini or command-line arguments. |
template<typename OptionType> | Same as ProgramOption except the value is absolute - it cannot be overriden. It also does not appear in the --help command. |
template<typename OptionType>struct Args { std::optional<OptionType> default_value; const char* description = ""; bool include_in_frontend = true; } | Same as ProgramOption except the value is stored elsewhere, and this object holds a raw pointer to that value. |
Frontend
Unlike MVC frameworks, FuzeHttp does not provide live SSR.
File inclusion
Relative paths to files should be prepended with FILE_, so that cache control will work properly. Otherwise, the client can load files from different versions, leading to unreproducible errors. For example:
<link rel="stylesheet" href=FILE_"static/styles.css">
This should not be done for external resources, only internal assets contained in the frontend folder.
Using program options
ProgramOption, ProgramOptionPtr, and ProgramConstant entries can be included in the frontend, by prepending CONFIG_ to the key. On startup, the server will fill in the values.
Given the example project has this option entry:
In the frontend,
(new ProgramConstant("test_program_constant", 73))
CONFIG_test_program_constant is replaced with 73.
Controller
All HTTP requests are routed through the controller. A pattern can be added to the controller, which matches a request URL to a view.
Pattern
URLs can be added to the controller with the following function:
template<typename... Types>
void addPattern(http::verb req_method, typename MakeFuncPtr<StateType, typename GetHandlerArgs<TypeList<Types...>, ToHandlerArg>::type>::type view, Types... args)
A pattern consists of a method, a callback, an optional Client parameter, and a set of path segments. Path segments can be const char*, int{}, std::string{}, or an overload of ResolverBase.
View
This is a callback function which is called when its corresponding pattern in the controller matches the request URL. Every view contains arguments for the state and the request, plus variable path segments.
Response
Every view must return a FuzeHttp::Response. The status is required. Designated initializer syntax is recommended.
struct Response {
beast::http::status status;
std::unordered_map<std::string, std::string> headers;
std::optional<std::string> error_message;
std::optional<boost::json::value> json;
std::optional<std::filesystem::path> file;
std::optional<std::string> body;
};