- Very simple expressjs-like API, albeit with way fewer features
- Support for GET, POST, PUT, DELETE methods (should be trivial to add more if needed)
- Psuedo-asynchronous with the help of
select
, which also helps keep the resources used low - Easily serve static directories (examples below)
- Easy to include in project
Note This library works only on Linux and macOS!
C++ 17
cmake
3.23.2 (for integrating this library into your project)
This project should be used through its CMake integration.
Simply add the following lines to your project CMakeLists.txt
file:
include(FetchContent)
cmake_minimum_required(VERSION 3.23.2)
project(<Your Project Name> CXX)
FetchContent_Declare(
HttpServer
GIT_REPOSITORY https://github.com/WilsonOh/CPP_HTTP_Server.git
GIT_TAG main
)
FetchContent_MakeAvailable(HttpServer)
add_executable(${PROJECT_NAME} <Your Source Files>...)
target_link_libraries(${PROJECT_NAME} PRIVATE HttpServer)
The documentation for the API is in the fully commented HttpServer.hpp
header file.
In the Usage
section below I will go through some example usages.
First off, a simple "hello world" example.
Install the library into your project using CMake
as shown above, and then run the following code:
// main.cpp
#include <HttpServer.hpp>
int main(void) {
auto svr = HttpServer();
svr.get("/", [](const HttpRequest &req, HttpResponse &res) {
res.text("Hello, World!");
});
svr.run();
}
We first create an instance of HttpServer
which initializes its fields to the default values.
- Number of listeners: 3
- Text displayed when the requested page is not found: "Wilson's Server: page request is not found"
After that, we define a GET route at the root path /
by passing in "/" as the first argument.
We then pass in a lambda which takes in a const HttpRequest &
and HttpResponse &
and has no return value.
NOTE: It is important to use the correct const qualifier and specify the parameters as references.
Within the lambda, we have access the the HttpRequest
and HttpResponse
structs and all their methods, but for
this example we simply call res.text()
with the message we want to send.
This sets the Content-Type
of the response header to text/plain
and sends the message as the reponse body.
Suppose we have a static directory with the following structure
static
├── 404.html
├── favicon.ico
├── index.html
├── script.js
└── styles.css
We can serve the static
directory and set the 404 page to static/404.html
with 20 listeners with the following snippet:
#include <HttpServer.hpp>
int main(void) {
auto svr = HttpServer()
.setNumListeners(20)
.set404Page("./static/404.html")
.mount_static_directory("static");
svr.run();
}
setNumListeners
and set404Page
are self explanatory.
mount_static_directory
mounts the static directory on /
by default if there is only one argument, but a second argument for the mount point can be passed in.
run
sets the socket to listen at port 3000 by default with no arguments, but a port number can be passed in if needed.
Note static directory hosting works with nested directories too!
#include <HttpServer.hpp>
int main(void) {
HttpResponse res;
res.set_header("Foo", "Bar");
res.html_string("<h1>PAGE NOT FOUND</h1>");
auto svr = HttpServer()
.setNumListeners(20)
.set404Response(res)
.mount_static_directory("build", "/www");
svr.post("/users", [](const HttpRequest &req, HttpResponse &res) {
res.json(R"({ "foo": "bar" })");
});
svr.run(8080);
}
Here, instead of setting the path to the 404 page, we can make our own HttpResponse
object and fully define its behaviour and set it as the response for 404 requests.
The static directory is mounted at /www
instead of /
here, and a POST route is defined for the /users
route which returns a json in the response body.
Lastly, the server is set to run at port 8000.
There are a lot of "convenience methods" for the HttpResponse
object, such as res.image
to send an image from the host directory or res.downloadable
which sends a file as an attachment to the client.
res.redirect
can redirect the browser to a relative route or another URL, and
res.set_header
can be used to add to the HTTP response headers or override any existing ones.
Feel free to look through the header file for the full list of methods available!
- Get a basic server to start up
- Create a class to enclose the server creation
- Make setting headers easy
- Create HTTP method functions, which takes in a route and lambda
- Support (single) static file hosting
- Support static directory hosting (for js and css files)
- Support http methods other than go (using separate route maps for each method)
- Support file hosting (for downloading)
- Provide verbose debugging information
- Multithreading (maybe maybe not???)
- Support paramerized URLs