Vix.cpp v2.7.0 is here Read the blog
Skip to content
Build a REST API
This guide shows how to build a small REST API with Vix.
You will create:
GET /GET /healthGET /usersGET /users/{id}POST /users
Requirements
bash
vix --version
vix new rest-api
cd rest-api1
2
3
2
3
Minimal server
Create or replace src/main.cpp:
cpp
#include <vix.hpp>
using namespace vix;
int main()
{
App app;
app.get("/", [](Request &, Response &res){
res.json({
"message", "Hello from Vix",
"framework", "Vix.cpp"
});
});
app.run(8080);
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
bash
vix dev
curl -i http://127.0.0.1:8080/1
2
2
Basic Vix HTTP structure
| Part | Purpose |
|---|---|
App app; | Creates the HTTP application instance. |
app.get(...) | Registers a GET route handler. |
Request &req | Provides access to request data. |
Response &res | Provides methods for sending responses. |
res.json(...) | Sends a JSON response. |
app.run(8080) | Starts the server on port 8080. |
Create a health route
cpp
app.get("/health", [](Request &, Response &res){
res.json({
"ok", true,
"service", "rest-api"
});
});1
2
3
4
5
6
2
3
4
5
6
Add an in-memory users list
cpp
std::vector<json::Json> users = {
{ {"id", 1}, {"name", "Alice"}, {"role", "admin"} },
{ {"id", 2}, {"name", "Bob"}, {"role", "user"}}
};1
2
3
4
2
3
4
Add GET /users
cpp
app.get("/users", [&users](Request &, Response &res){
res.json({
"ok", true,
"count", users.size(),
"data", users
});
});1
2
3
4
5
6
7
2
3
4
5
6
7
Add GET /users/
cpp
app.get("/users/{id}", [&users](Request &req, Response &res){
const std::string id = req.param("id");
for (const auto &user : users)
{
if (std::to_string(user.value("id", 0)) == id)
{
res.json({
"ok", true,
"data", user
});
return;
}
}
res.status(404).json({
"ok", false,
"error", "user not found",
"id", id
});
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Add query params
cpp
app.get("/users", [&users](Request &req, Response &res){
const std::string page = req.query_value("page", "1");
const std::string limit = req.query_value("limit", "10");
res.json({
"ok", true,
"page", page,
"limit", limit,
"count", users.size(),
"data", users
});
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
Useful request APIs:
| API | Purpose |
|---|---|
req.param("id") | Reads a route path parameter. |
req.param("id", "0") | Reads a route parameter with fallback. |
req.query_value("page", "1") | Reads a query parameter with fallback. |
req.query() | Reads all query parameters. |
req.body() | Reads the raw request body. |
req.json() | Reads the parsed JSON body. |
req.header("Authorization") | Reads a request header value. |
Add POST /users
cpp
app.post("/users", [&users](Request &req, Response &res){
const auto &body = req.json();
if (!body.is_object())
{
res.status(400).json({
"ok", false,
"error", "expected JSON object body"
});
return;
}
const std::string name = body.value("name", "");
const std::string role = body.value("role", "user");
if (name.empty())
{
res.status(400).json({
"ok", false,
"error", "field 'name' is required"
});
return;
}
const int new_id = users.empty() ? 1 : users.back().value("id", 0) + 1;
json::Json user = {
{"id", new_id},
{"name", name},
{"role", role}
};
users.push_back(user);
res.status(201).json({
"ok", true,
"message", "user created",
"data", user
});
});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
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
bash
curl -i -X POST http://127.0.0.1:8080/users \
-H "Content-Type: application/json" \
-d '{"name":"Charlie","role":"user"}'1
2
3
2
3
Final version
Replace src/main.cpp with this complete, organized version:
cpp
#include <vix.hpp>
#include <string>
#include <vector>
using namespace vix;
struct AppState
{
std::vector<json::Json> users;
};
static AppState create_state()
{
AppState state;
state.users = {
{ {"id", 1}, {"name", "Alice"}, {"role", "admin"} },
{ {"id", 2}, {"name", "Bob"}, {"role", "user"} }
};
return state;
}
static void register_public_routes(App &app)
{
app.get("/", [](Request &, Response &res){
res.json({
"message", "Vix REST API",
"framework", "Vix.cpp"
});
});
app.get("/health", [](Request &, Response &res){
res.json({
"ok", true,
"service", "rest-api"
});
});
}
static void register_user_routes(App &app, AppState &state)
{
app.get("/users", [&state](Request &req, Response &res){
const std::string page = req.query_value("page", "1");
const std::string limit = req.query_value("limit", "10");
res.json({
"ok", true,
"page", page,
"limit", limit,
"count", state.users.size(),
"data", state.users
});
});
app.get("/users/{id}", [&state](Request &req, Response &res){
const std::string id = req.param("id");
for (const auto &user : state.users)
{
if (std::to_string(user.value("id", 0)) == id)
{
res.json({
"ok", true,
"data", user
});
return;
}
}
res.status(404).json({
"ok", false,
"error", "user not found",
"id", id
});
});
app.post("/users", [&state](Request &req, Response &res){
const auto &body = req.json();
if (!body.is_object())
{
res.status(400).json({
"ok", false,
"error", "expected JSON object body"
});
return;
}
const std::string name = body.value("name", "");
const std::string role = body.value("role", "user");
if (name.empty())
{
res.status(400).json({
"ok", false,
"error", "field 'name' is required"
});
return;
}
const int new_id = state.users.empty() ? 1 : state.users.back().value("id", 0) + 1;
json::Json user = {
{"id", new_id},
{"name", name},
{"role", role}
};
state.users.push_back(user);
res.status(201).json({
"ok", true,
"message", "user created",
"data", user
});
});
}
int main()
{
App app;
AppState state = create_state();
register_public_routes(app);
register_user_routes(app, state);
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
Test the API
bash
curl -i http://127.0.0.1:8080/
curl -i http://127.0.0.1:8080/health
curl -i http://127.0.0.1:8080/users
curl -i "http://127.0.0.1:8080/users?page=1&limit=10"
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","role":"user"}'1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Response helpers
cpp
res.json({"ok", true, "message", "Hello"}); // JSON
res.text("Hello Vix"); // Text
res.send("Created"); // Generic
res.status(201).json({"ok", true}); // With status
res.file("public/index.html"); // File1
2
3
4
5
2
3
4
5
Status codes
| Status | Meaning | Example |
|---|---|---|
200 | OK. | Successful GET request. |
201 | Created. | Successful POST request. |
400 | Bad Request. | Invalid input was provided. |
401 | Unauthorized. | Authentication is missing. |
403 | Forbidden. | Access is not allowed. |
404 | Not Found. | Requested resource is missing. |
500 | Internal Server Error. | Server-side failure occurred. |
Recommended JSON shape
json
{ "ok": true, "data": {} }
{ "ok": false, "error": "message" }
{ "ok": true, "count": 2, "data": [] }1
2
3
2
3
Common mistakes
Forgetting to return after sending an error
cpp
// Wrong
if (name.empty()) {
res.status(400).json({
"error", "name is required"
});
}
res.json({"ok", true});
// Correct
if (name.empty()) {
res.status(400).json({
"error", "name is required"
});
return;
}
res.json({"ok", true});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Passing runtime args incorrectly
bash
vix run main.cpp --run --port 8080 # correct
vix run main.cpp -- --port 8080 # wrong: -- is for compiler flags1
2
2
Expecting in-memory data to persist
The users vector is in memory. If the server restarts, created users are lost. For persistence, use SQLite or MySQL.
What to use next
- SQLite API guide — for persistence
- Validation guide — for validating input
- Authentication guide — for auth
