Vix.cpp v2.7.0 is here Read the blog
Skip to content
HTTP API
The HTTP API is the core application API of Vix. It gives you the main building blocks for web applications and APIs.
txt
App — Request — Response — Routes — Static files — Server lifecycle1
Public header
cpp
#include <vix.hpp>1
Basic example
cpp
#include <vix.hpp>
using namespace vix;
int main()
{
App app;
app.get("/", [](Request &, Response &res) {
res.text("Hello from Vix");
});
app.run(8080);
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vix::App
App is the main application object. It owns the router, middleware chain, server lifecycle, static files, and runtime configuration.
cpp
App app;1
Server lifecycle
cpp
app.run(8080); // start and block
app.listen(8080, []() { // start async with callback
std::cout << "listening\n";
});
app.wait(); // block until server stops
app.close(); // stop the server1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Routes
A route connects an HTTP method and path to a C++ handler.
cpp
app.get("/users/{id}", [](Request &req, Response &res){
const std::string id = req.param("id");
res.json({"id", id});
});1
2
3
4
2
3
4
HTTP methods
cpp
app.get("/users", list_handler);
app.post("/users", create_handler);
app.put("/users/{id}", replace_handler);
app.patch("/users/{id}", update_handler);
app.del("/users/{id}", delete_handler);
app.head("/health", head_handler);
app.options("/users", options_handler);1
2
3
4
5
6
7
2
3
4
5
6
7
Path parameters
cpp
// Matches /users/1, /users/42, /users/abc
app.get("/users/{id}", [](Request &req, Response &res){
res.json({"id", req.param("id")});
});
// Multiple parameters
app.get("/posts/{year}/{slug}", [](Request &req, Response &res){
res.json({
"year", req.param("year"),
"slug", req.param("slug")
});
});1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
Query parameters
cpp
// /users?page=2&limit=10
app.get("/users", [](Request &req, Response &res){
const std::string page = req.query_value("page", "1");
const std::string limit = req.query_value("limit", "20");
res.json({
"page", page,
"limit", limit
});
});1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
Use path parameters to identify a resource (/users/42), query parameters to modify how resources are read (/users?page=2).
Request
| Method | Purpose |
|---|---|
req.param("id") | Read a path parameter |
req.param("id", "0") | Read with fallback |
req.query_value("page", "1") | Read a query parameter with fallback |
req.query() | Read all query parameters |
req.header("Authorization") | Read a request header |
req.body() | Read the raw request body |
req.json() | Read the parsed JSON body |
req.path() | Read the request path |
req.method() | Read the HTTP method |
Read JSON body
cpp
app.post("/users", [](Request &req, Response &res){
const auto &body = req.json();
if (!body.is_object())
{
res.status(400).json({
"ok", false,
"error", "expected JSON object"
});
return;
}
const std::string name = body.value("name", "");
if (name.empty())
{
res.status(400).json({
"ok", false,
"error", "name is required"
});
return;
}
res.status(201).json({
"ok", true,
"name", name
});
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Response
| Method | Purpose |
|---|---|
res.text("Hello") | Send plain text |
res.send("Hello") | Send a basic response body |
res.json({...}) | Send JSON |
res.status(201) | Set HTTP status (chainable) |
res.header("X-Foo", "bar") | Set a response header |
res.file("public/index.html") | Send a file |
cpp
res.status(201).json({
"ok", true,
"message", "created"
});
res.header("X-Powered-By", "Vix.cpp");
res.file("public/index.html");1
2
3
4
5
6
2
3
4
5
6
Status codes
| Status | Meaning |
|---|---|
| 200 | OK |
| 201 | Created |
| 204 | No Content |
| 400 | Bad Request |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Not Found |
| 409 | Conflict |
| 429 | Too Many Requests |
| 500 | Internal Server Error |
Error helper
cpp
static void respond_error(Response &res, int status,
const std::string &code,
const std::string &message)
{
res.status(status).json({
"ok", false,
"error", code,
"message", message
});
}
// Always return after sending an error
if (id == "0") {
respond_error(res, 404, "user_not_found", "User not found");
return;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Good response shapes
json
{ "ok": true, "data": {} }
{ "ok": true, "count": 2, "data": [] }
{ "ok": false, "error": "validation_failed", "message": "name is required" }1
2
3
2
3
Route order
Register specific routes before generic ones:
cpp
// Correct
app.get("/users/search", search_handler);
app.get("/users/{id}", user_handler);
app.get("/*", fallback_handler);
// Wrong — wildcard catches everything first
app.get("/*", fallback_handler);
app.get("/users/{id}", user_handler);1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Wildcard and static files
cpp
// Manual static file fallback
app.get("/*", [](Request &req, Response &res){
res.header("Cache-Control", "public, max-age=86400");
res.file("public" + req.path());
});
// Simple static directory
app.static_dir("public");1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Route groups
cpp
app.group("/api", [](auto &api){
api.get("/health", [](Request &, Response &res) {
res.json({"ok", true});
});
api.get("/users", [](Request &, Response &res) {
res.json({"ok", true});
});
api.group("/admin", [](auto &admin){
admin.get("/stats", [](Request &, Response &res){
res.json({"ok", true});
});
});
});
// Routes: GET /api/health, GET /api/users, GET /api/admin/stats1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Organizing routes
cpp
static void register_public_routes(App &app)
{
app.get("/", [](Request &, Response &res) {
res.json({"message", "Hello"});
});
app.get("/health", [](Request &, Response &res) {
res.json({"ok", true});
});
}
int main()
{
App app;
register_public_routes(app);
app.run(8080);
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Complete example
cpp
#include <vix.hpp>
using namespace vix;
static void respond_error(Response &res, int status,
const std::string &code, const std::string &message)
{
res.status(status).json({
"ok", false,
"error", code,
"message", message
});
}
static void register_user_routes(App &app)
{
app.get("/users", [](Request &req, Response &res){
res.json({
"ok", true,
"page", req.query_value("page", "1"),
"data", vix::json::array({"Alice", "Bob"})
});
});
app.get("/users/{id}", [](Request &req, Response &res){
const std::string id = req.param("id");
if (id == "0") {
respond_error(res, 404, "user_not_found", "User not found");
return;
}
res.json({
"ok", true,
"data", vix::json::o("id", id),
"name", "Ada"
});
});
app.post("/users", [](Request &req, Response &res){
const auto &body = req.json();
if (!body.is_object()) {
respond_error(res, 400, "invalid_body", "Expected JSON object");
return;
}
const std::string name = body.value("name", "");
if (name.empty()) {
respond_error(res, 400, "validation_failed", "name is required");
return;
}
res.status(201).json({
"ok", true,
"message", "user created"
});
});
app.del("/users/{id}", [](Request &req, Response &res){
const std::string id = req.param("id");
if (id == "0") {
respond_error(res, 404, "user_not_found", "User not found");
return;
}
res.json({
"ok", true,
"message", "user deleted",
"id", id
});
});
}
int main()
{
App app;
app.get("/health", [](Request &, Response &res) {
res.json({"ok", true});
});
register_user_routes(app);
app.run(8080);
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
Test
bash
curl -i http://127.0.0.1:8080/health
curl -i "http://127.0.0.1:8080/users?page=2"
curl -i http://127.0.0.1:8080/users/1
curl -i -X POST http://127.0.0.1:8080/users \
-H "Content-Type: application/json" -d '{"name":"Charlie"}'
curl -i -X DELETE http://127.0.0.1:8080/users/11
2
3
4
5
6
2
3
4
5
6
Common mistakes
Missing leading slash
cpp
app.get("health", handler); // Wrong
app.get("/health", handler); // Correct1
2
2
Forgetting to return after an error
cpp
// Wrong — continues after error
respond_error(res, 400, "...", "...");
res.status(201).json({"ok", true});
// Correct
respond_error(res, 400, "...", "...");
return;1
2
3
4
5
6
7
2
3
4
5
6
7
Using -- for runtime arguments
bash
vix run main.cpp -- --port 8080 # Wrong — compiler flags
vix run main.cpp --run --port 8080 # Correct — runtime args1
2
2
What you should remember
The HTTP API is built around three types: App, Request, Response.
txt
client → Request → route handler → Response1
The most common starting point: #include <vix.hpp>
Next: JSON API
