From 20f909c1478cbb176f623f0af5b75dfa2d328709 Mon Sep 17 00:00:00 2001 From: James Yab Date: Sun, 28 Dec 2025 23:44:35 -0500 Subject: [PATCH 1/5] Use CONFIG keyword to search for GTest package-provided config files --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f5089ed..6107877 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(TEST_TARGET "server_tests_bin") set(TARGET "server_impl_bin") set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -find_package(GTest REQUIRED) +find_package(GTest CONFIG REQUIRED) find_package(Threads REQUIRED) From 376a52117ca173df1afeca007ce2458d285bf3df Mon Sep 17 00:00:00 2001 From: James Yab Date: Sun, 28 Dec 2025 23:46:41 -0500 Subject: [PATCH 2/5] Add Nix flake configuration for reproducible C/C++ development environment --- flake.lock | 27 +++++++++++++++++++++++++++ flake.nix | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..aca9ee5 --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1766736597, + "narHash": "sha256-BASnpCLodmgiVn0M1MU2Pqyoz0aHwar/0qLkp7CjvSQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "f560ccec6b1116b22e6ed15f4c510997d99d5852", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..eabe14e --- /dev/null +++ b/flake.nix @@ -0,0 +1,32 @@ +{ + description = "A C/C++ development environment"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; + }; + + outputs = {nixpkgs, ...}: let + system = "x86_64-linux"; + pkgs = import nixpkgs { inherit system; }; + in { + devShells.${system}.default = pkgs.mkShell { + packages = with pkgs; [ + git + + gcc + lcov + gdb + + # If you want to use clang and llvm-cov instead of gcc, uncomment + # clang + # llvmPackages.llvm + + gnumake + cmake + conan + + python312 + ]; + }; + }; +} From 1e06282c3a2c25b8ec4e48fa70f67ae6fd287386 Mon Sep 17 00:00:00 2001 From: James Yab Date: Sun, 28 Dec 2025 23:47:04 -0500 Subject: [PATCH 3/5] Add Dockerfile for reproducible build environment with Conan --- Dockerfile | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..104534a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,38 @@ +FROM ubuntu:24.04 +LABEL authors="james" + + +RUN apt-get update && apt-get install -y \ + build-essential \ + gcc \ + g++ \ + cmake \ + git \ + python3 \ + python3-pip \ + python3-venv \ + lcov \ + pkg-config \ + && rm -rf /var/lib/apt/lists/* + +# Create a venv for Conan +RUN python3 -m venv /opt/venv +# Activate venv +ENV PATH="/opt/venv/bin:$PATH" + +# Install Conan inside the venv +RUN pip install --upgrade pip \ + && pip install conan + +# Configure Conan default profile +RUN conan profile detect --force + +# Set working dir and copy project files +WORKDIR /app +COPY --exclude=build/ . . + +# Build with Conan +RUN conan build . --build=missing + + +CMD ["/bin/bash"] \ No newline at end of file From 0d1fa1cfebe426f0f5ee273f10c3f3518f3adc93 Mon Sep 17 00:00:00 2001 From: James Yab Date: Sun, 28 Dec 2025 23:50:35 -0500 Subject: [PATCH 4/5] Update README to include Docker and Nix usage instructions --- README.md | 52 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 54a5bf9..3dc70e8 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,9 @@ A modern C++ HTTP server implementation with routing, testing, and CI-driven qua * [Features](#features) * [Usage](#usage) * [Project Structure](#project-structure) +* [Using Docker](#using-docker) +* [Using Nix](#using-nix) * [Building the Source Code](#building-the-source-code) - * [Building for Release Mode](#building-for-release-mode) * [Running the Server](#running-the-server) * [Running the Tests](#running-the-tests) @@ -33,6 +34,8 @@ A modern C++ HTTP server implementation with routing, testing, and CI-driven qua * Build verification * Automated test execution * Coverage report generation +* **Docker** for reproducible builds and containerization +* **Nix flake** for reproducible development environments * **Project tracking** using GitHub Projects (Kanban board) --- @@ -45,20 +48,24 @@ A modern C++ HTTP server implementation with routing, testing, and CI-driven qua HttpServer server{}; server.get_mapping( - "/test", [](const HttpServer::Request &, HttpServer::Response &res) { + "/test", [](HttpServer::Request &req, HttpServer::Response &res) { res.body = "testing new api route"; }); -server.post_mapping( - "/test2/{id}", [](const HttpServer::Request &, HttpServer::Response &res) { - std::stringstream ss; - try { - ss << req.path_params.get_path_param("id").value() << "\n"; - res.body = ss.str(); - } catch (const std::bad_optional_access &e) { - res.body = "could not get path parameter foo"; - } - }); + server.post_mapping( + "/test2/{id}/foo/{user}", + [](HttpServer::Request &req, HttpServer::Response &res) { + std::stringstream ss; + try { + ss << "{\"id\":" << "\"" << req.path_params.get_path_param("id").value() << "\"," + << "\"user\":" << "\"" << req.path_params.get_path_param("user").value() << "\"" + << "}"; + res.body = ss.str(); + } catch (const std::bad_optional_access &e) { + res.body = "could not get path parameter"; + } + }); + try { server.listen(3490); // use any port you like @@ -82,6 +89,27 @@ try { --- +## Using Docker + +```bash +# build the docker image +docker build -t cpp_http_server . + +# run a container in interactive mode +# discards after use +docker run --rm -it cpp_http_server +``` + +--- + +## Using Nix + +The `flake.nix` can only be used if your system has the Nix package manager with flakes enabled. + +```bash +nix develop +``` + ## Building the Source Code This project uses **Conan** for dependency management and **CMake** for builds. From 5150716b4ed248eaef5d43ceb239cf7523b97e59 Mon Sep 17 00:00:00 2001 From: James Yab Date: Sun, 28 Dec 2025 23:51:31 -0500 Subject: [PATCH 5/5] Add an example of utilizing multiple path parameters --- src/main.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 7f23215..7ea4948 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,13 +6,22 @@ int main() { HttpServer server{}; server.get_mapping( - "/test", [](const HttpServer::Request &, HttpServer::Response &res) { + "/test", [](HttpServer::Request &req, HttpServer::Response &res) { res.body = "testing new api route"; }); - server.get_mapping( - "/test2", [](const HttpServer::Request &, HttpServer::Response &res) { - res.body = "this is the other route"; + server.post_mapping( + "/test2/{id}/foo/{user}", + [](HttpServer::Request &req, HttpServer::Response &res) { + std::stringstream ss; + try { + ss << "{\"id\":" << "\"" << req.path_params.get_path_param("id").value() << "\"," + << "\"user\":" << "\"" << req.path_params.get_path_param("user").value() << "\"" + << "}"; + res.body = ss.str(); + } catch (const std::bad_optional_access &e) { + res.body = "could not get path parameter"; + } }); try { @@ -21,4 +30,4 @@ int main() { std::cerr << err.what() << '\n'; return EXIT_FAILURE; } -} +} \ No newline at end of file