Backend server with Crow C++
Hello World !
This is my favorite backend server framework with C++ so i will share simple CRUD with linux debian setup
✅ Requirements
- C/C++ Compiler with pthread support
- C++17 or newer
- Crow installed framework
install dependencies
1
$ apt install -y build-essential cmake curl git libasio-dev libboost-all-dev
installed crow to path external/crow
1
2
$ mkdir -p external
$ git clone https://github.com/CrowCpp/Crow.git external/crow
🗃️ Project structure file
here is our project structure file
1
2
3
4
5
6
7
8
9
10
.
├── external/
│ └── crow/
├── include/
│ └── item.hpp
├── src/
│ ├── controllers.cpp
│ ├── main.cpp
│ └── routes.cpp
└── CMakeLists.txt
🛠️ Build system
first we need to init our build system here in CMakeLists.txt
I use CMake build system for this project
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cmake_minimum_required(VERSION 3.10)
project(backend_crow)
set(CMAKE_CXX_STANDARD 17)
include_directories(include)
include_directories(external/crow/include)
find_package(Boost REQUIRED system)
add_executable(app
src/controllers.cpp
src/main.cpp
src/routes.cpp
)
target_link_libraries(app Boost::system pthread)
📄 Header
create our data model header in include/item.hpp
1
2
3
4
5
6
7
#pragma once
#include <string>
struct Item {
int id;
std::string name;
};
💻 Setup code
first create our logic business logic in src/controllers.cpp
so because this was a simple project we will keep our data into memory
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
#include "../include/item.hpp"
#include <vector>
#include <optional>
static std::vector<Item> items;
static int nextId = 1;
std::vector<Item> &getItems() {
return items;
}
int createItem(const std::string &name) {
items.push_back({nextId, name});
return nextId++;
}
bool updateItem(int id, const std::string &name) {
for (auto &i : items) {
if (i.id == id) {
i.name = name;
return true;
}
}
return false;
}
bool deleteItem(int id) {
for (auto it = items.begin(); it != items.end(); ++it) {
if (it->id == id) {
items.erase(it);
return true;
}
}
return false;
}
next create the routes in src/routes.cpp
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
#include "crow.h"
#include "../include/item.hpp"
#include <vector>
std::vector<Item> &getItems();
int createItem(const std::string &name);
bool updateItem(int id, const std::string &name);
bool deleteItem(int id);
void setupRoutes(crow::SimpleApp &app) {
// read
CROW_ROUTE(app, "/items").methods("GET"_method)
([](){
auto &items = getItems();
crow::json::wvalue res;
crow::json::wvalue::list list;
for (auto &i : items) {
crow::json::wvalue item;
item["id"] = i.id;
item["name"] = i.name;
list.push_back(item);
}
res["items"] = std::move(list);
return res;
});
// create
CROW_ROUTE(app, "/items").methods("POST"_method)
([](const crow::request &req){
auto body = crow::json::load(req.body);
if (!body || !body.has("name"))
return crow::response(400, "Invalid JSON");
int id = createItem(body["name"].s());
crow::json::wvalue res;
res["message"] = "created";
res["id"] = id;
return crow::response(res);
});
// get per items
CROW_ROUTE(app, "/items/<int>").methods("GET"_method)
([](int id){
auto &items = getItems();
for (auto &i : items) {
if (i.id == id) {
crow::json::wvalue res;
res["id"] = i.id;
res["name"] = i.name;
return crow::response(res);
}
}
return crow::response(404, "Not found");
});
// update
CROW_ROUTE(app, "/items/<int>").methods("PUT"_method)
([](const crow::request &req, int id){
auto body = crow::json::load(req.body);
if (!body || !body.has("name"))
return crow::response(400, "Invalid JSON");
bool ok = updateItem(id, body["name"].s());
if (!ok)
return crow::response(404, "Not found");
crow::json::wvalue res;
res["message"] = "updated";
return crow::response(res);
});
// delete
CROW_ROUTE(app, "/items/<int>").methods("DELETE"_method)
([](int id){
bool ok = deleteItem(id);
if (!ok)
return crow::response(404, "Not found");
crow::json::wvalue res;
res["message"] = "deleted";
return crow::response(res);
});
}
finally create our main config file in src/main.cpp
1
2
3
4
5
6
7
8
9
10
#include "crow.h"
void setupRoutes(crow::SimpleApp &app);
int main() {
crow::SimpleApp app;
setupRoutes(app);
app.port(8000).multithreaded().run();
}
🚀 Build and run
after setup our code lets build and run with this command
1
2
3
4
$ mkdir build && cd build
$ cmake ..
$ make
$ ./app
server will be run on: http://localhost:8000
test our project with curl
create
1 2 3 $ curl -X POST http://localhost:8000/items \ -H "Content-Type: application/json" \ -d '{"name":"Apple"}'
Read all
1$ curl http://localhost:8000/items
Read one per items
1$ curl http://localhost:8000/items/1
update
1 2 3 $ curl -X PUT http://localhost:8000/items/1 \ -H "Content-Type: application/json" \ -d '{"name":"Banana"}'
delete
1 $ curl -X DELETE http://localhost:8000/items/1
🌐 Other frameworks
Crow is popular c++ framework for backend server especially best for small and fast microservices but you can try popular c++ framework among this: