|
1 | | -## Building the source code |
| 1 | +# C++ HTTP Server |
| 2 | + |
| 3 | +A modern C++ HTTP server implementation with routing, testing, and CI-driven quality checks. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Table of Contents |
| 8 | + |
| 9 | +* [Features](#features) |
| 10 | +* [Usage](#usage) |
| 11 | +* [Project Structure](#project-structure) |
| 12 | +* [Building the Source Code](#building-the-source-code) |
| 13 | + |
| 14 | + * [Building for Release Mode](#building-for-release-mode) |
| 15 | +* [Running the Server](#running-the-server) |
| 16 | +* [Running the Tests](#running-the-tests) |
| 17 | +* [Code Coverage](#code-coverage) |
| 18 | +* [CI / GitHub Actions](#ci--github-actions) |
| 19 | +* [Project Management](#project-management) |
| 20 | +* [Key Skills/Lessons Learned](#key-skillslessons-learned) |
| 21 | +* [Challenges](#challenges) |
| 22 | + |
| 23 | +--- |
| 24 | + |
| 25 | +## Features |
| 26 | + |
| 27 | +* **Route compilation and matching** with support for path parameters |
| 28 | + * Easily map functions to a new route |
| 29 | +* **Automated test suite** using GoogleTest (gtest) with CI/CD pipeline |
| 30 | +* **Code coverage reporting** using `lcov` |
| 31 | + * Automated code coverage with CI/CD pipeline |
| 32 | +* **GitHub Actions CI pipeline** |
| 33 | + * Build verification |
| 34 | + * Automated test execution |
| 35 | + * Coverage report generation |
| 36 | +* **Project tracking** using GitHub Projects (Kanban board) |
| 37 | + |
| 38 | +--- |
| 39 | + |
| 40 | +## Usage |
| 41 | + |
| 42 | +```cpp |
| 43 | +#include "HttpServer.h" |
| 44 | + |
| 45 | +HttpServer server{}; |
| 46 | + |
| 47 | +server.get_mapping( |
| 48 | + "/test", [](const HttpServer::Request &, HttpServer::Response &res) { |
| 49 | + res.body = "testing new api route"; |
| 50 | + }); |
| 51 | + |
| 52 | +server.post_mapping( |
| 53 | + "/test2/{id}", [](const HttpServer::Request &, HttpServer::Response &res) { |
| 54 | + std::stringstream ss; |
| 55 | + try { |
| 56 | + ss << req.path_params.get_path_param("id").value() << "\n"; |
| 57 | + res.body = ss.str(); |
| 58 | + } catch (const std::bad_optional_access &e) { |
| 59 | + res.body = "could not get path parameter foo"; |
| 60 | + } |
| 61 | + }); |
| 62 | + |
| 63 | +try { |
| 64 | + server.listen(3490); // use any port you like |
| 65 | +} catch (const std::exception &err) { |
| 66 | + std::cerr << err.what() << '\n'; |
| 67 | + return EXIT_FAILURE; |
| 68 | +} |
| 69 | +``` |
| 70 | + |
| 71 | +## Project Structure |
| 72 | + |
| 73 | +``` |
| 74 | +. |
| 75 | +├── src/ # Server implementation |
| 76 | +├── include/ # Public headers |
| 77 | +├── tests/ # gtest-based test suite |
| 78 | +├── cmake/ # CMake helpers |
| 79 | +├── .github/ # GitHub Actions workflows |
| 80 | +└── README.md |
| 81 | +``` |
| 82 | + |
| 83 | +--- |
| 84 | + |
| 85 | +## Building the Source Code |
| 86 | + |
| 87 | +This project uses **Conan** for dependency management and **CMake** for builds. |
| 88 | + |
| 89 | +### Building for Release Mode |
2 | 90 |
|
3 | | -## Building for Release mode |
4 | 91 | ```bash |
5 | 92 | conan build . --build=missing |
6 | 93 | ``` |
7 | 94 |
|
8 | | -## Command to run the HttpServer impl example |
| 95 | +--- |
| 96 | + |
| 97 | +## Running the Server |
| 98 | + |
| 99 | +Command to run the HTTP server implementation example: |
| 100 | + |
9 | 101 | ```bash |
10 | 102 | # in release mode |
11 | 103 | ./build/Release/server_impl_bin |
12 | 104 | ``` |
13 | 105 |
|
14 | | -## Command to run the Tests |
| 106 | +--- |
| 107 | + |
| 108 | +## Running the Tests |
| 109 | + |
| 110 | +Command to execute the automated test suite: |
| 111 | + |
15 | 112 | ```bash |
16 | 113 | # run tests |
17 | 114 | ./build/Release/server_tests_bin |
18 | 115 | ``` |
19 | 116 |
|
20 | | -## Generation of coverage reports |
| 117 | +--- |
| 118 | + |
| 119 | +## Code Coverage |
| 120 | + |
| 121 | +Coverage reports are generated using **lcov**. |
| 122 | + |
| 123 | +### Generate Coverage Reports |
21 | 124 |
|
22 | 125 | ```bash |
23 | 126 | make -C build/Release coverage |
24 | 127 | ``` |
25 | 128 |
|
26 | | -### Open the coverage report |
| 129 | +### Open the Coverage Report |
| 130 | + |
27 | 131 | ```bash |
28 | 132 | # specific to Linux |
29 | 133 | xdg-open build/Release/CMakeFiles/server_library.dir/src/out/index.html |
30 | 134 | ``` |
| 135 | + |
| 136 | +--- |
| 137 | + |
| 138 | +## CI / GitHub Actions |
| 139 | + |
| 140 | +The project includes a GitHub Actions workflow that automatically: |
| 141 | + |
| 142 | +* Builds the project |
| 143 | +* Runs the gtest suite |
| 144 | +* Generates an lcov coverage report |
| 145 | + |
| 146 | +### Coverage Report (GitHub Actions) |
| 147 | + |
| 148 | +<img src="doc_images/coverage.png" alt="lcov coverage report" height="400"> |
| 149 | + |
| 150 | +### Automated gtest Execution (GitHub Actions) |
| 151 | + |
| 152 | +<img src="doc_images/gtest.png" alt="gtest CI Run" height="400"> |
| 153 | + |
| 154 | +--- |
| 155 | + |
| 156 | +## Project Management |
| 157 | + |
| 158 | +Development tasks and progress are tracked using a **GitHub Projects Kanban board**. |
| 159 | + |
| 160 | +<img src="doc_images/kanban.png" alt="github projects kanban board" height="400"> |
| 161 | + |
| 162 | +--- |
| 163 | + |
| 164 | +## Key Skills/Lessons Learned |
| 165 | + |
| 166 | +* **Designing extensible routing systems** in C++ requires careful separation between route compilation and request |
| 167 | + matching |
| 168 | +* **Understanding of TCP and port implementation on Linux** |
| 169 | +* **Parsing of strings** (client requests) to get individual strings (HTTP method, route, request body) |
| 170 | +* **Implementing Test driven development (TDD)** to improve confidence in changes and reduce regressions when refactoring |
| 171 | +* **Setting up code coverage tools** (lcov) provide insight on what portions of the codebase are covered by testing |
| 172 | +* **Setting up CI automation with GitHub Actions** to automate testing, code coverage reports, and enforce consistent quality for PRs |
| 173 | +* **Better understanding of HTTP REST standards**, such as knowing which HTTP methods should have request bodies ignored |
| 174 | + |
| 175 | + |
| 176 | +C++ specific lessons learned: |
| 177 | +* **Using Conan** to simplify dependency management across environments |
| 178 | +* **Learning CMake** |
| 179 | + * Creating functions in CMake to automatically generate code coverage reports |
| 180 | +* **Implementing RAII** to improve memory safety and ensure automatic cleanup |
| 181 | +* **Implementing more modern C++** practices: |
| 182 | + * std::threads, lambdas for route handlers, RAII-style object lifetime, ... |
| 183 | + * exception usage instead of C-style exits, thread sleeping (std::this_thread::sleep_for) |
| 184 | +* Use `string_view` to avoid copying an entire `string` object |
| 185 | + |
| 186 | +--- |
| 187 | + |
| 188 | +## Challenges: |
| 189 | +* Implementing C++ practices while utilizing the Linux port library written in C |
| 190 | + * I had to encapsulate many parts of the C-specific library functions and employ RAII-style C++ objects (ex: closing ports before deconstruction) |
| 191 | +* Designing a routing system that allows a programmer to easily map a function pointer to a route |
| 192 | +* Refactoring the routing system to allow for path parameters |
0 commit comments