Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ git_override(
# LLVM Setup
llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm", dev_dependency = True)
llvm.toolchain(
llvm_version = "17.0.6",
llvm_version = "21.1.6",
)
use_repo(llvm, "llvm_toolchain")
register_toolchains("@llvm_toolchain//:all", dev_dependency = True)
Expand All @@ -40,4 +40,4 @@ git_override(
module_name = "hedron_compile_commands",
remote = "https://github.com/mikael-s-persson/bazel-compile-commands-extractor.git",
commit = "f5fbd4cee671d8d908f37c83abaf70fba5928fc7",
)
)
95 changes: 94 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,95 @@
# rest-api-helper
A simple helper aimed at making creation of REST APIs a bit nicer

A simple helper library for C++ aimed at making the creation of REST APIs easier and cleaner. It is built on top of [cpp-httplib](https://github.com/yhirose/cpp-httplib) and [nlohmann/json](https://github.com/nlohmann/json).

## Features

- **Route Management**: Define routes and endpoints with a fluent API.
- **Auto-Documentation**: Automatically generates a JSON documentation endpoint for your API.
- **Parameter Descriptions**: Add descriptions for path parameters and request/response details.
- **Bazel Support**: Ready to be integrated into Bazel projects.

## Installation

This library is designed to be used with Bazel with Bzlmod enabled.

### 1. Add dependency to `MODULE.bazel`

Add the following to your `MODULE.bazel`:

```python
# Assuming you have this in a registry or local override
bazel_dep(name = "rest_api_helper", version = "0.0.1")
```
Comment thread
Yuki-cpp marked this conversation as resolved.

### 2. Add dependency to your `BUILD` file

In your `BUILD` or `BUILD.bazel` file, add the library to your target's `deps`:

```python
cc_binary(
name = "my_app",
srcs = ["main.cpp"],
deps = [
"@rest_api_helper//src:rest_api_helper",
],
)
```

## Usage

Here is a simple example of how to use the library:

```cpp
#include <httplib.h>
#include "src/rest_api.hpp"

int main()
{
httplib::Server server;
// Initialize the API helper with a base route "/api"
yuki::web::RestAPI api(server, "/api");

// Enable the documentation endpoint at "/api/docs"
api.add_docs_endpoint("docs");

// Add a route "/api/hello"
auto& hello_route = api.add_route("hello", "A simple hello route");

// Add a GET endpoint to the route
hello_route.add_endpoint(
yuki::web::HTTPMethod::HTTP_GET,
[](const httplib::Request&, httplib::Response& res) {
res.set_content("Hello, World!", "text/plain");
},
"Returns a hello message"
);

// Start the server
server.listen("0.0.0.0", 8080);

return 0;
}
```

See `examples/basic_usage.cpp` for a more complete example.

## Building and Testing

To build the library:

```bash
bazel build //src:rest_api_helper
```

To run the tests:

```bash
bazel test //tests:unit_tests
```

## Dependencies

- [cpp-httplib](https://github.com/yhirose/cpp-httplib)
- [nlohmann/json](https://github.com/nlohmann/json)
- [googletest](https://github.com/google/googletest) (for testing)
8 changes: 8 additions & 0 deletions examples/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
load("//build_utils:defs.bzl", "strict_cc_binary")

strict_cc_binary(
name = "basic_usage",
srcs = ["basic_usage.cpp"],
deps = ["//src:rest_api_helper"],
visibility = ["//visibility:private"],
)
2 changes: 1 addition & 1 deletion src/main.cpp → examples/basic_usage.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <httplib.h>

#include "src/hello.hpp"
#include "src/rest_api.hpp"

int main()
{
Expand Down
13 changes: 3 additions & 10 deletions src/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
load("//build_utils:defs.bzl", "strict_cc_binary", "strict_cc_library")
load("//build_utils:defs.bzl", "strict_cc_library")

strict_cc_library(
name = "rest_api_helper",
srcs = ["hello.cpp"],
hdrs = ["hello.hpp"],
srcs = ["rest_api.cpp"],
hdrs = ["rest_api.hpp"],
visibility = ["//visibility:public"],

deps = [
"@cpp-httplib",
"@nlohmann_json//:json",
],
)

strict_cc_binary(
name = "example_app",
srcs = ["main.cpp"],
deps = [":rest_api_helper"],
visibility = ["//visibility:private"],
)
5 changes: 4 additions & 1 deletion src/hello.cpp → src/rest_api.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#include "src/hello.hpp"
#include "src/rest_api.hpp"

#include <utility>

namespace yuki::web
{

namespace
{
std::string http_method_to_string(HTTPMethod method)
{
switch (method)
Expand All @@ -21,6 +23,7 @@ std::string http_method_to_string(HTTPMethod method)
return "UNKNOWN";
}
}
} // namespace

RestAPI::Route::Route(httplib::Server& server,
nlohmann::json& endpoints_documentation,
Expand Down
47 changes: 45 additions & 2 deletions src/hello.hpp → src/rest_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
namespace yuki::web
{

/**
Comment thread
Yuki-cpp marked this conversation as resolved.
* @brief Enum representing supported HTTP methods.
*/
enum class HTTPMethod
{
HTTP_GET,
Expand All @@ -18,11 +21,23 @@ enum class HTTPMethod
HTTP_PUT,
};

std::string http_method_to_string(HTTPMethod method);

/**
* @brief A helper class to manage REST API routes and documentation.
*
* This class wraps an httplib::Server and provides a structured way to add routes
* and endpoints, automatically generating documentation for them.
Comment thread
Yuki-cpp marked this conversation as resolved.
*
* @note The user is responsible for managing the lifecycle of the httplib::Server instance,
* including starting the server (e.g., server.listen()) and configuring SSL/TLS if required.
*/
class RestAPI
{
public:
/**
* @brief Represents a single route in the API (e.g., "/users").
*
* A Route can have multiple endpoints (e.g., GET /users, POST /users).
*/
class Route
{
public:
Expand All @@ -32,6 +47,14 @@ class RestAPI
Route& operator=(Route&&) = delete;
~Route() = default;

/**
* @brief Adds an endpoint to the route.
*
* @param method The HTTP method for the endpoint.
* @param handler The function to handle requests.
* @param description A description of what the endpoint does.
* @param parameters_descriptions A map of parameter names to their descriptions (optional).
*/
void add_endpoint(HTTPMethod method,
std::function<void(const httplib::Request&, httplib::Response&)> handler,
const std::string& description,
Expand All @@ -49,18 +72,38 @@ class RestAPI
friend class yuki::web::RestAPI;
};

/**
* @brief Construct a new RestAPI object.
*
* @param base_server The httplib::Server instance to attach routes to.
* @param base_api_route The base path for all routes (e.g., "/api/v1").
*/
RestAPI(httplib::Server& base_server, const std::string& base_api_route);
RestAPI(const RestAPI&) = delete;
RestAPI& operator=(const RestAPI&) = delete;
RestAPI(RestAPI&&) = delete;
RestAPI& operator=(RestAPI&&) = delete;
~RestAPI() = default;

/**
* @brief Adds a new route to the API.
*
* @param path The path for the route, relative to the base API route.
* @param description A description of the route resource.
* @param path_parameters_descriptions A map of path parameter names to their descriptions
* (optional).
* @return yuki::web::RestAPI::Route& A reference to the created Route object.
*/
yuki::web::RestAPI::Route&
add_route(const std::string& path,
const std::string& description,
const std::map<std::string, std::string>& path_parameters_descriptions = {});

/**
* @brief Adds a documentation endpoint that serves the generated API docs in JSON format.
*
* @param docs_path The path for the documentation endpoint, relative to the base API route.
*/
void add_docs_endpoint(const std::string& docs_path);

private:
Expand Down
2 changes: 1 addition & 1 deletion tests/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ load("//build_utils:defs.bzl", "strict_cc_test")

strict_cc_test(
name = "unit_tests",
srcs = ["hello_test.cpp"],
srcs = ["rest_api_test.cpp"],
deps = [
"//src:rest_api_helper",
"@googletest//:gtest",
Expand Down
3 changes: 0 additions & 3 deletions tests/hello_test.cpp

This file was deleted.

Loading