I've always found it exciting to use C++ for back-end of my projects, but information on how to do this has to be pieced together. Difficulties are also added by the fact that most of the articles are intended for experienced developers, and much of them is omitted in the expectation that developers are quite familiar with server programming, the C++ language, and build systems.
I will venture to write a series of articles about producing CRUD api for "Farm-fellows"(service for subscribing on farm foods), as if you are encountering many topics for the first time. First of all, I am writing these articles in order to structure the knowledge gained in my head, but if it helps you become more determined to use c++ for the server, I will be very happy.
To create a server, I will use the oat ++ framework. I will be using Ubuntu Linux as my operating system. To save data, I will first use sqlite. Later I will also try to use mongo and postgres.
As a build system, I will use Cmake. You also need git to be installed to clone oat++ and its modules.
So let's start.
First of all we need oat++ itself and two oat++ modules oatpp-sqlite and oatpp-swagger (for good looking representation of our future CRUD api)
cd "some/temp/path/for/repositories"
git clone https://github.com/oatpp/oatpp.git
cd oatpp
mkdir build && cd build
cmake ..
(sudo) make install
cd ../../ (back to repository root folder)
git clone https://github.com/oatpp/oatpp-sqlite.git
cd oatpp
mkdir build && cd build
cmake ..
(sudo) make install
Note: You can also use -DOATPP_SQLITE_AMALGAMATION=ON to install oatpp-sqlite together with SQLite amalgamation in which case you don't need to install SQLite
cd ../../ (back to repository root folder)
git clone https://github.com/oatpp/oatpp-swagger.git
cd oatpp
mkdir build && cd build
cmake ..
(sudo) make install
Oat++ and it's modules now will be added in /usr/local/oatpp-1.3.1/ folder as oatpp, oatpp-swagger, oatpp-sqlite includes
You also need to add sqlite if you didn't use amalgamation sqlite files while making oatpp-sqlite module, so let's install it too.
sudo apt update
sudo apt install sqlite3
sqlite3 --version
sudo apt install sqlitebrowser
Now we ready to start code our project
cd /some/path/for/projects/root
mkdir farm-fellows
cd farm-fellows
touch CMakeLists.txt
mkdir src
cd src
touch App.cpp
mkdir component
cd component
touch AppComponent.hpp
cd ../../
So, for very begining we need at least two source files, one is App.cpp with main() function and AppComponent.hpp with several oatpp components which needs for running http server.
Let's edit AppComponent.hpp first
#ifndef AppComponent_hpp
#define AppComponent_hpp
#include "oatpp/core/macro/component.hpp"
#include "oatpp/web/server/HttpConnectionHandler.hpp"
#include "oatpp/network/tcp/server/ConnectionProvider.hpp"
#include "oatpp/parser/json/mapping/ObjectMapper.hpp"
class AppComponent {
public:
/**
* Create ObjectMapper component to serialize/deserialize DTOs in Contoller's API
*/
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::data::mapping::ObjectMapper>, apiObjectMapper)([] {
return oatpp::parser::json::mapping::ObjectMapper::createShared();
}());
/**
* Create ConnectionProvider component which listens on the port
*/
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ServerConnectionProvider>, serverConnectionProvider)([] {
return oatpp::network::tcp::server::ConnectionProvider::createShared({SERVER_HOST, SERVER_PORT, oatpp::network::Address::IP_4});
}());
/**
* Create Router component
*/
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, httpRouter)([] {
return oatpp::web::server::HttpRouter::createShared();
}());
/**
* Create ConnectionHandler component which uses Router component to route requests
*/
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ConnectionHandler>, serverConnectionHandler)([] {
OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router); // get Router component
return oatpp::web::server::HttpConnectionHandler::createShared(router);
}());
};
#endif
Oat++ using macros OATPP_CREATE_COMPONENT with shared_ptr of component instance, we use lambda as argument for callback, when oatpp is deciding to declare new instance of component.
Now we can add our components to App (src/App.cpp):
#include <iostream>
#include "./component/AppComponent.hpp"
#include "oatpp/network/Server.hpp"
void run() {
AppComponent components; // Create scope Environment components
/* Get connection handler component */
OATPP_COMPONENT(std::shared_ptr<oatpp::network::ConnectionHandler>, connectionHandler);
/* Get connection provider component */
OATPP_COMPONENT(std::shared_ptr<oatpp::network::ServerConnectionProvider>, connectionProvider);
/* create server */
oatpp::network::Server server(connectionProvider,
connectionHandler);
OATPP_LOGD("Server", "Running on port %s...", connectionProvider->getProperty("port").toString()->c_str());
server.run();
}
/**
* main
*/
int main(int argc, const char * argv[]) {
oatpp::base::Environment::init();
run();
oatpp::base::Environment::destroy();
return 0;
}
Now we can edit our CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(farm-fellows)
set(CMAKE_CXX_STANDARD 17)
add_library(farm-fellows-lib
src/component/AppComponent.hpp)
## include directories
target_include_directories(farm-fellows-lib PUBLIC src)
## link libs
## Oat++
find_package(oatpp 1.3.0 REQUIRED)
find_package(oatpp-swagger 1.3.0 REQUIRED)
find_package(oatpp-sqlite 1.3.0 REQUIRED)
target_link_libraries(farm-fellows-lib
PUBLIC oatpp::oatpp
PUBLIC oatpp::oatpp-swagger
PUBLIC oatpp::oatpp-sqlite
)
## Sqlite3
find_package(SQLite3 REQUIRED)
target_link_libraries(farm-fellows-lib
PUBLIC SQLite::SQLite3
)
if(CMAKE_SYSTEM_NAME MATCHES Linux)
find_package(Threads REQUIRED)
target_link_libraries(farm-fellows-lib INTERFACE Threads::Threads ${CMAKE_DL_LIBS})
endif()
add_definitions(
# define host
-DSERVER_HOST="127.0.0.0"
# define port
-DSERVER_PORT=8000
)
## add executables
add_executable(farm-fellows-exe src/App.cpp)
target_link_libraries(farm-fellows-exe farm-fellows-lib)
In add_definitions we added two constants which used for ConnectionProvider instance initialization.
Now we can make our very basic server:
(you should be in project root path /farm-fellows)
mkdir build && cd build
cmake ..
make
./farm-fellows-exe
open 127.0.0.0:8000 in your browser. because of no controllers matching with responses yet we should see as response:
server=oatpp/1.3.0
code=404
description=Not Found
message=No mapping for HTTP-method: 'GET', URL: '/'
Top comments (0)