2025-06-22 14:40:33 -05:00
2025-06-22 14:40:33 -05:00
2025-06-22 14:40:33 -05:00
2025-06-22 14:40:33 -05:00

Goldfish HTTP Router

A fast radix tree-based HTTP router for C++.

Quick Start

#include "goldfish.hpp"
using namespace goldfish;

Router router;

// Basic route
router.get("/hello", [](IRequest& req, IResponse& res, Params params) {
	res.set_body("Hello, World!");
});

// Route with parameters
router.get("/users/:id", [](IRequest& req, IResponse& res, Params params) {
	string user_id = string(params[0]);
	res.set_body("User ID: " + user_id);
});

// Multiple parameters
router.get("/users/:userId/posts/:postId", [](IRequest& req, IResponse& res, Params params) {
	string user_id = string(params[0]);
	string post_id = string(params[1]);
	res.set_json("{\"user\":\"" + user_id + "\",\"post\":\"" + post_id + "\"}");
});

API Reference

Router Methods

void get(string_view path, Handler handler);
void post(string_view path, Handler handler);
void put(string_view path, Handler handler);
void del(string_view path, Handler handler);  // DELETE
void patch(string_view path, Handler handler);

bool handle(IRequest& request, IResponse& response);

Handler Signature

using Params = const std::vector<string_view>&;
using Handler = std::function<void(IRequest&, IResponse&, Params)>;

Path Parameters

Use :name syntax for parameters:

  • /users/:id matches /users/123
  • /api/:version/users/:id matches /api/v1/users/456

Parameters are accessed by index in order of appearance:

router.get("/api/:version/users/:id", [](IRequest& req, IResponse& res, Params params) {
	string version = string(params[0]); // :version
	string id = string(params[1]);      // :id
});

HTTP Server Example

#include "goldfish.hpp"
#include <iostream>
#include <thread>
// Your HTTP server headers here

using namespace goldfish;

class MyRequest : public IRequest {
private:
	HttpMethod method_;
	string_view path_;
	// ... other fields

public:
	MyRequest(const ServerRequest& req) {
		// Parse from your server's request format
		method_ = parse_method(req.method);
		path_ = req.path;
	}

	HttpMethod method() const override { return method_; }
	string_view path() const override { return path_; }
	// ... implement other methods
};

class MyResponse : public IResponse {
private:
	ServerResponse& response_;

public:
	MyResponse(ServerResponse& res) : response_(res) {}

	void set_status(int status) override {
		response_.status = status;
	}

	void set_body(string_view body) override {
		response_.body = string(body);
	}
	// ... implement other methods
};

int main() {
	Router router;

	// Define routes
	router.get("/", [](IRequest& req, IResponse& res, Params params) {
		res.set_content_type("text/html");
		res.set_body("<h1>Welcome to Goldfish!</h1>");
	});

	router.get("/api/users/:id", [](IRequest& req, IResponse& res, Params params) {
		string user_id = string(params[0]);
		res.set_content_type("application/json");
		res.set_body("{\"id\":\"" + user_id + "\",\"name\":\"User " + user_id + "\"}");
	});

	router.post("/api/users", [](IRequest& req, IResponse& res, Params params) {
		// Create user logic
		res.set_status(201);
		res.set_body("{\"message\":\"User created\"}");
	});

	// Start server
	HttpServer server;
	server.on_request([&](ServerRequest& req, ServerResponse& res) {
		MyRequest request(req);
		MyResponse response(res);

		if (!router.handle(request, response)) {
			response.set_status(404);
			response.set_body("Not Found");
		}
	});

	server.listen(8080);
	std::cout << "Server running on port 8080\n";

	return 0;
}

Performance

Benchmarked on typical hardware:

  • Lookup speed: 364K lookups/second
  • Average latency: 2.75μs per lookup
  • Memory: Zero allocations during routing
  • Scalability: Linear with route count

Building

g++ -std=c++20 -O3 your_app.cpp -o your_app
Description
Fast radix-trie router in C++!
Readme 37 KiB
Languages
C++ 100%