Server with oat++. Installation. CmakeLists.txt
Tags: cpp, oatpp, backend, cmake
Published: 2022-09-07 02:02:28

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: '/'