From b7b64cf3966a0699f4b1216bdf70c857b76b03b0 Mon Sep 17 00:00:00 2001 From: Artem Sheptunov <106321977+Infindery@users.noreply.github.com> Date: Wed, 18 Mar 2026 16:12:44 +0500 Subject: [PATCH 01/14] feat(app-config): #36: adding an app-config layer to work with environment variables --- CMakeLists.txt | 1 + src/data/db_connection.cpp | 14 ++--- src/main.cpp | 6 +- src/utils/app-config/app-config.cpp | 67 +++++++++++++++++++++++ src/utils/app-config/app-config.h | 85 +++++++++++++++++++++++++++++ 5 files changed, 165 insertions(+), 8 deletions(-) create mode 100644 src/utils/app-config/app-config.cpp create mode 100644 src/utils/app-config/app-config.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f56a1c..e9b1e3e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ project(${PROJECT_NAME} CXX) file(GLOB_RECURSE sources CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/src/*/*.cpp ${CMAKE_SOURCE_DIR}/src/data/models/odb-gen/*.cxx + ${CMAKE_SOURCE_DIR}/src/utils/**/*.cpp ) set(PROJECT_OBJECTS ${PROJECT_NAME}_lib) diff --git a/src/data/db_connection.cpp b/src/data/db_connection.cpp index 38ec95a..184813f 100644 --- a/src/data/db_connection.cpp +++ b/src/data/db_connection.cpp @@ -14,15 +14,15 @@ std::shared_ptr DbConnection::get() flag, []() { - const std::string user = std::getenv("POSTGRES_USER"); - const std::string password = std::getenv("POSTGRES_PASSWORD"); - const std::string db_name = std::getenv("POSTGRES_DB"); - const std::string host = std::getenv("POSTGRES_HOST"); - const std::string port = std::getenv("POSTGRES_PORT"); + const std::string host = AppConfig::databaseHost(); + const std::string port = AppConfig::databasePort(); + const std::string user = AppConfig::databaseUser(); + const std::string password = AppConfig::databasePassword(); + const std::string dbname = AppConfig::databaseName(); - std::string conninfo = "host=" + host + " port=" + port + " dbname=" + db_name + " user=" + user + " password=" + password; + std::string conn = "host=" + host + " port=" + port + " dbname=" + dbname + " user=" + user + " password=" + password; - instance_ = std::shared_ptr(new odb::pgsql::database(conninfo)); + instance_ = std::shared_ptr(new odb::pgsql::database(conn)); } ); diff --git a/src/main.cpp b/src/main.cpp index be21213..61dd802 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,11 @@ int main() { - drogon::app().addListener("127.0.0.1", 8080); + drogon::app() + .addListener(AppConfig::apiHost(), AppConfig::apiPort()) + .setLogLevel(AppConfig::apiLogLevel()) + .setThreadNum(AppConfig::apiNumThreads()); + drogon::app().run(); return 0; diff --git a/src/utils/app-config/app-config.cpp b/src/utils/app-config/app-config.cpp new file mode 100644 index 0000000..c34ed19 --- /dev/null +++ b/src/utils/app-config/app-config.cpp @@ -0,0 +1,67 @@ +#include + +#include "app-config.h" + +std::string AppConfig::getEnv(std::string name, std::string defaultValue) +{ + char* value = std::getenv(name.c_str()); + return value ? std::string(value) : defaultValue; +} + +std::string AppConfig::apiHost() +{ + return getEnv("API_HOST", "0.0.0.0"); +} + +int AppConfig::apiPort() +{ + return std::stoi(getEnv("API_PORT", "80")); +} + +trantor::Logger::LogLevel AppConfig::apiLogLevel() +{ + auto logLevel = getEnv("API_LOG_LEVEL", "INFO"); + + trantor::Logger::LogLevel level; + + if (logLevel == "DEBUG") + level = trantor::Logger::kDebug; + else if (logLevel == "WARN") + level = trantor::Logger::kWarn; + else if (logLevel == "TRACE") + level = trantor::Logger::kTrace; + else + level = trantor::Logger::kInfo; + + return level; +} + +int AppConfig::apiNumThreads() +{ + return std::stoi(getEnv("API_NUMBER_OF_THREADS", "1")); +} + +std::string AppConfig::databaseHost() +{ + return getEnv("POSTGRES_HOST", "0.0.0.0"); +} + +std::string AppConfig::databasePort() +{ + return getEnv("POSTGRES_PORT", "5432"); +} + +std::string AppConfig::databaseName() +{ + return getEnv("POSTGRES_DB", "to-dos-api-cpp-db"); +} + +std::string AppConfig::databaseUser() +{ + return getEnv("POSTGRES_USER", "postgres"); +} + +std::string AppConfig::databasePassword() +{ + return getEnv("POSTGRES_PASSWORD", "password"); +} \ No newline at end of file diff --git a/src/utils/app-config/app-config.h b/src/utils/app-config/app-config.h new file mode 100644 index 0000000..774b302 --- /dev/null +++ b/src/utils/app-config/app-config.h @@ -0,0 +1,85 @@ +#ifndef APP_CONFIG_H +#define APP_CONFIG_H + +#include +#include +#include + +class AppConfig +{ +public: + /** + * @brief Function for retrieving the value of an environment variable + * @param name is the name of the environment variable + * @param defaultValue is the value that will be used if the environment variable doesn't exist + * @return std::string + */ + static std::string getEnv(std::string name, std::string defaultValue); + + /** + * @brief Function to get the host value from the environment + * variable `API_HOST`. Default is `0.0.0.0` + * @return std::string + */ + static std::string apiHost(); + + /** + * @brief Function to get the port value from the environment + * variable `API_PORT`. Default is `80` + * @return int + */ + static int apiPort(); + + /** + * @brief Function to get the log level value from the environment + * variable `API_LOG_LEVEL`. Default is `INFO` + * @return trantor::Logger::LogLevel + */ + static trantor::Logger::LogLevel apiLogLevel(); + + /** + * @brief Function to get the numbers of threads value from the + * environment variable `API_NUMBER_OF_THREADS`. Default is `1` + * @return int + */ + static int apiNumThreads(); + + /** + * @brief Function to get the database host value from the + * environment variable `POSTGRES_HOST`. Default is `0.0.0.0` + * @return std::string + */ + static std::string databaseHost(); + + /** + * @brief Function to get the database port value from the + * environment variable `POSTGRES_PORT`. Default is `5432` + * @return std::string + */ + static std::string databasePort(); + + /** + * @brief Function to get the database name value from the + * environment variable `POSTGRES_DB`. Default is + * `to-dos-api-cpp-db` + * @return std::string + */ + static std::string databaseName(); + + /** + * @brief Function to get the database user value from the + * environment variable `POSTGRES_USER`. Default is `postgres` + * @return std::string + */ + static std::string databaseUser(); + + /** + * @brief Function to get the database password value from the + * environment variable `POSTGRES_PASSWORD`. Default is + * `password` + * @return std::string + */ + static std::string databasePassword(); +}; + +#endif // APP_CONFIG_H \ No newline at end of file From 25bbb4974dac56ad9863fffc2b2dd51e39ac5bcf Mon Sep 17 00:00:00 2001 From: Artem Sheptunov <106321977+Infindery@users.noreply.github.com> Date: Thu, 19 Mar 2026 09:48:17 +0500 Subject: [PATCH 02/14] chore(devcontainer): #36: adding the --env-file argument to the devcontainer configuration to automatically evaluate environment variables when the devcontainer starts --- .devcontainer/devcontainer.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index aaf2351..5887f9e 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -15,6 +15,12 @@ // "customizations": {}, // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. "remoteUser": "root", + "runArgs": [ + // This is necessary to avoid having to manually export environment variables from + // the .env file in every terminal session. + "--env-file", + "${localWorkspaceFolder}/.env" + ], "customizations": { "vscode": { "extensions": [ From 2ffab6df604761b0de6bec585087dd1bb0ad094a Mon Sep 17 00:00:00 2001 From: Artem Sheptunov <106321977+Infindery@users.noreply.github.com> Date: Thu, 19 Mar 2026 10:14:05 +0500 Subject: [PATCH 03/14] docs(readme): #36: adding information to the README about the automatic export of environment variables when building a container --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f29eaa1..023d897 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ When dependencies are built, use the command `conan build . -pr:h profiles/to-do #### Before launching web server: - Run the database container via docker compose command `docker compose up -d` from workspace. -- Import environment variables declared in the `.env` file while in the dev container and using the command `export $(grep -v '^#' .env | xargs)`. If the file containing the environment variables is named something other than `.env`, you should modify the command to specify the correct name. +- Import the environment variables defined in the .env file in the project root. The environment variables were automatically exported from .env when the container was built. If the contents of the .env file have been modified after the container was built, run the command `export $(grep -v ‘^#’ .env | xargs)`, but keep in mind that the environment variables will only be visible in the terminal session where the command was executed. To launch the executable, click Launch in the CMake extension.

cmakeLaunch

From 378dec3cbb5b22c379b9b22d93fb3aaae45710e7 Mon Sep 17 00:00:00 2001 From: Artem Sheptunov <106321977+Infindery@users.noreply.github.com> Date: Fri, 20 Mar 2026 13:10:18 +0500 Subject: [PATCH 04/14] refactor(environment): #36: convert `app-config` into a singleton class so that the values of the environment variables are stored within the class --- src/data/db_connection.cpp | 13 ++-- src/main.cpp | 8 +- src/utils/app-config/app-config.cpp | 88 ++++++++++------------ src/utils/app-config/app-config.h | 110 +++++++++++++++++++--------- 4 files changed, 124 insertions(+), 95 deletions(-) diff --git a/src/data/db_connection.cpp b/src/data/db_connection.cpp index 184813f..319db7b 100644 --- a/src/data/db_connection.cpp +++ b/src/data/db_connection.cpp @@ -1,4 +1,5 @@ #include "db_connection.h" +#include "../utils/app-config/app-config.h" #include #include @@ -14,11 +15,13 @@ std::shared_ptr DbConnection::get() flag, []() { - const std::string host = AppConfig::databaseHost(); - const std::string port = AppConfig::databasePort(); - const std::string user = AppConfig::databaseUser(); - const std::string password = AppConfig::databasePassword(); - const std::string dbname = AppConfig::databaseName(); + auto& config = AppConfig::GetInstance(); + + const std::string host = config.databaseHost(); + const std::string port = config.databasePort(); + const std::string user = config.databaseUser(); + const std::string password = config.databasePassword(); + const std::string dbname = config.databaseName(); std::string conn = "host=" + host + " port=" + port + " dbname=" + dbname + " user=" + user + " password=" + password; diff --git a/src/main.cpp b/src/main.cpp index 61dd802..91b7361 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,11 @@ +#include "utils/app-config/app-config.h" #include int main() { - drogon::app() - .addListener(AppConfig::apiHost(), AppConfig::apiPort()) - .setLogLevel(AppConfig::apiLogLevel()) - .setThreadNum(AppConfig::apiNumThreads()); + auto& config = AppConfig::GetInstance(); + + drogon::app().addListener(config.apiHost(), config.apiPort()).setLogLevel(config.apiLogLevel()).setThreadNum(config.apiNumThreads()); drogon::app().run(); diff --git a/src/utils/app-config/app-config.cpp b/src/utils/app-config/app-config.cpp index c34ed19..2ab12f0 100644 --- a/src/utils/app-config/app-config.cpp +++ b/src/utils/app-config/app-config.cpp @@ -1,67 +1,53 @@ -#include - #include "app-config.h" -std::string AppConfig::getEnv(std::string name, std::string defaultValue) -{ - char* value = std::getenv(name.c_str()); - return value ? std::string(value) : defaultValue; -} - -std::string AppConfig::apiHost() -{ - return getEnv("API_HOST", "0.0.0.0"); -} - -int AppConfig::apiPort() -{ - return std::stoi(getEnv("API_PORT", "80")); -} - -trantor::Logger::LogLevel AppConfig::apiLogLevel() -{ - auto logLevel = getEnv("API_LOG_LEVEL", "INFO"); - - trantor::Logger::LogLevel level; +AppConfig::AppConfig() +: apiHost_(getEnv("API_HOST", "0.0.0.0")), + apiPort_(getEnvInt("API_PORT", 80)), + apiNumThreads_(getEnvInt("API_NUMBER_OF_THREADS", 1)), + apiLogLevel_(parseLogLevel(getEnv("API_LOG_LEVEL", "INFO"))), + databaseHost_(getEnv("POSTGRES_HOST", "0.0.0.0")), + databasePort_(getEnv("POSTGRES_PORT", "5432")), + databaseName_(getEnv("POSTGRES_DB", "to-dos-api-cpp-db")), + databaseUser_(getEnv("POSTGRES_USER", "postgres")), + databasePassword_(getEnv("POSTGRES_PASSWORD", "password")) +{} - if (logLevel == "DEBUG") - level = trantor::Logger::kDebug; - else if (logLevel == "WARN") - level = trantor::Logger::kWarn; - else if (logLevel == "TRACE") - level = trantor::Logger::kTrace; - else - level = trantor::Logger::kInfo; - - return level; -} - -int AppConfig::apiNumThreads() +AppConfig& AppConfig::GetInstance() { - return std::stoi(getEnv("API_NUMBER_OF_THREADS", "1")); + static AppConfig instance; + return instance; } -std::string AppConfig::databaseHost() +std::string AppConfig::getEnv(std::string name, std::string defaultValue) { - return getEnv("POSTGRES_HOST", "0.0.0.0"); + char* value = std::getenv(name.c_str()); + return value ? std::string(value) : defaultValue; } -std::string AppConfig::databasePort() +int AppConfig::getEnvInt(std::string name, int defaultValue) { - return getEnv("POSTGRES_PORT", "5432"); -} + char* value = std::getenv(name.c_str()); -std::string AppConfig::databaseName() -{ - return getEnv("POSTGRES_DB", "to-dos-api-cpp-db"); -} + if (!value) + return defaultValue; -std::string AppConfig::databaseUser() -{ - return getEnv("POSTGRES_USER", "postgres"); + try + { + return std::stoi(value); + } + catch (const std::exception&) + { + return defaultValue; + } } -std::string AppConfig::databasePassword() +trantor::Logger::LogLevel AppConfig::parseLogLevel(const std::string& level) { - return getEnv("POSTGRES_PASSWORD", "password"); + if (level == "DEBUG") + return trantor::Logger::kDebug; + if (level == "WARN") + return trantor::Logger::kWarn; + if (level == "TRACE") + return trantor::Logger::kTrace; + return trantor::Logger::kInfo; } \ No newline at end of file diff --git a/src/utils/app-config/app-config.h b/src/utils/app-config/app-config.h index 774b302..05b8a61 100644 --- a/src/utils/app-config/app-config.h +++ b/src/utils/app-config/app-config.h @@ -1,5 +1,4 @@ -#ifndef APP_CONFIG_H -#define APP_CONFIG_H +#pragma once #include #include @@ -7,79 +6,120 @@ class AppConfig { +private: + /** + * @brief AppConfig class constructor + * @return void + */ + AppConfig(); + + // No copying + AppConfig(const AppConfig&) = delete; + AppConfig& operator=(const AppConfig&) = delete; + + std::string apiHost_; + int apiPort_; + int apiNumThreads_; + trantor::Logger::LogLevel apiLogLevel_; + + std::string databaseHost_; + std::string databasePort_; + std::string databaseName_; + std::string databaseUser_; + std::string databasePassword_; + public: + /** + * @brief Function to retrieve an instance of the AppConfig class + * @return an instance of the AppConfig class + */ + static AppConfig& GetInstance(); + /** * @brief Function for retrieving the value of an environment variable * @param name is the name of the environment variable * @param defaultValue is the value that will be used if the environment variable doesn't exist * @return std::string */ - static std::string getEnv(std::string name, std::string defaultValue); + std::string getEnv(std::string name, std::string defaultValue); + + /** + * @brief Function that retrieves a value from an environment variable and converts it to an integer type + * @param name is the name of the environment variable + * @param defaultValue is the value that will be used if the environment variable doesn't exist + * @return int + */ + int getEnvInt(std::string name, int defaultValue); + + /** + * @brief Function for converting a string representing a logging level to the `trantor` type. Default is `trantor::Logger::kInfo` + * @param level is a string containing the logging level. + */ + trantor::Logger::LogLevel parseLogLevel(const std::string& level); /** - * @brief Function to get the host value from the environment + * @brief Getter for the host value from the environment * variable `API_HOST`. Default is `0.0.0.0` - * @return std::string + * @return const std::string */ - static std::string apiHost(); + const std::string& apiHost() const { return apiHost_; } /** - * @brief Function to get the port value from the environment + * @brief Getter for the port value from the environment * variable `API_PORT`. Default is `80` - * @return int + * @return const int */ - static int apiPort(); + const int apiPort() const { return apiPort_; } /** - * @brief Function to get the log level value from the environment - * variable `API_LOG_LEVEL`. Default is `INFO` - * @return trantor::Logger::LogLevel + * @brief Getter for the numbers of threads value from the + * environment variable `API_NUMBER_OF_THREADS`. Default is `1` + * @return const int */ - static trantor::Logger::LogLevel apiLogLevel(); + const int apiNumThreads() const { return apiNumThreads_; } /** - * @brief Function to get the numbers of threads value from the - * environment variable `API_NUMBER_OF_THREADS`. Default is `1` - * @return int + * @brief Getter for the log level value from the environment + * variable `API_LOG_LEVEL`. Default is `INFO` + * @return const trantor::Logger::LogLevel */ - static int apiNumThreads(); + const trantor::Logger::LogLevel apiLogLevel() const { return apiLogLevel_; } /** - * @brief Function to get the database host value from the + * @brief Getter for the database host value from the * environment variable `POSTGRES_HOST`. Default is `0.0.0.0` - * @return std::string + * @return const std::string */ - static std::string databaseHost(); + const std::string& databaseHost() const { return databaseHost_; } /** - * @brief Function to get the database port value from the + * @brief Getter for the database port value from the * environment variable `POSTGRES_PORT`. Default is `5432` - * @return std::string + + * @return const std::string */ - static std::string databasePort(); + const std::string& databasePort() const { return databasePort_; } /** - * @brief Function to get the database name value from the + * @brief Getter for the database name value from the * environment variable `POSTGRES_DB`. Default is * `to-dos-api-cpp-db` - * @return std::string + * @return const std::string */ - static std::string databaseName(); + const std::string& databaseName() const { return databaseName_; } /** - * @brief Function to get the database user value from the + * @brief Getter for the database user value from the * environment variable `POSTGRES_USER`. Default is `postgres` - * @return std::string + * @return const std::string */ - static std::string databaseUser(); + const std::string& databaseUser() const { return databaseUser_; } /** - * @brief Function to get the database password value from the + * @brief Getter for the database password value from the * environment variable `POSTGRES_PASSWORD`. Default is * `password` - * @return std::string + * @return const std::string */ - static std::string databasePassword(); -}; - -#endif // APP_CONFIG_H \ No newline at end of file + const std::string& databasePassword() const { return databasePassword_; } +}; \ No newline at end of file From eab4313f187d89506d2cf5e0774df7d924f14641 Mon Sep 17 00:00:00 2001 From: Artem Sheptunov <106321977+Infindery@users.noreply.github.com> Date: Fri, 20 Mar 2026 14:06:06 +0500 Subject: [PATCH 05/14] docs(readme): #36: add the necessary step to create the .env file in the project setup section; add the missing environment variables to .env.example --- .env.example | 6 +++++- README.md | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index ba3f92e..93c26a7 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,8 @@ -# Database +API_HOST=tobemodified +API_PORT=tobemodified +API_LOG_LEVEL=tobemodified +API_NUMBER_OF_THREADS=tobemodified + POSTGRES_HOST=tobemodified POSTGRES_PORT=tobemodified POSTGRES_DB=tobemodified diff --git a/README.md b/README.md index 023d897..c8936db 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ For development purposes use a devcontainer named `developing`. - Microsoft VS Code - VS Code should also have the "Dev Containers" extension installed. To check it, open "View: Extensions" with `Ctrl + Shift + X` or as shown in the screenshot below:

vscodeExtensions

+- Before running the container, create a .env file in the project root and specify the environment variables in it, just as you did in .env.example. Otherwise, running the devcontainer will result in an error. - Make sure Docker daemon is running before opening the dev container (`Ctrl + Shift + P` -> "Reopen in container" or click here + "Reopen in container")

vscodeContainer

From 8244c7769f8f6bfdfc6e516f65524f5e81d8ac52 Mon Sep 17 00:00:00 2001 From: Artem Sheptunov <106321977+Infindery@users.noreply.github.com> Date: Fri, 20 Mar 2026 14:09:55 +0500 Subject: [PATCH 06/14] fix(workflows): #36: fixing a pipeline error related to the missing required .env file for running the devcontainer --- .github/workflows/build.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 571c090..d5b01f0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,12 +23,16 @@ jobs: .conan2 build/Debug/generators key: ${{ env.cache-name }}-${{ hashFiles('conanfile.py') }} + + - name: Prepare + # we need to create a .env file, because without it, the Dev Container won't be able to start + run: touch .env - name: Install and build Conan dependencies if: steps.cache-conan-packages.outputs.cache-hit != 'true' uses: devcontainers/ci@v0.3 with: - runCmd: | + runCmd: | mkdir -p .conan2/profiles cp .devcontainer/to-dos-conan-profile.conf .conan2/profiles/default From e8de3d108f68996c8adaf3790a368910bd45b86f Mon Sep 17 00:00:00 2001 From: Artem Sheptunov <106321977+Infindery@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:15:54 +0500 Subject: [PATCH 07/14] refactor(environment): #36: add error handling to app-config, add log output, add clarifying comments --- .env.example | 4 +- src/main.cpp | 6 +- src/utils/app-config/app-config.cpp | 144 ++++++++++++++++++++++++---- src/utils/app-config/app-config.h | 44 +++++---- 4 files changed, 156 insertions(+), 42 deletions(-) diff --git a/.env.example b/.env.example index 93c26a7..d672252 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,7 @@ API_HOST=tobemodified API_PORT=tobemodified -API_LOG_LEVEL=tobemodified -API_NUMBER_OF_THREADS=tobemodified +API_LOG_LEVEL=tobemodified # Possible values: TRACE (0), DEBUG (1), INFO (2), WARN (3) or ERROR (4) +API_NUMBER_OF_THREADS=tobemodified # Cannot be less than 1 POSTGRES_HOST=tobemodified POSTGRES_PORT=tobemodified diff --git a/src/main.cpp b/src/main.cpp index 91b7361..ac88e03 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,10 +3,12 @@ int main() { - auto& config = AppConfig::GetInstance(); + // We need to set the logging level so that it is used instead of the default + drogon::app().setLogLevel(AppConfig::apiLogLevel()); - drogon::app().addListener(config.apiHost(), config.apiPort()).setLogLevel(config.apiLogLevel()).setThreadNum(config.apiNumThreads()); + auto& config = AppConfig::GetInstance(); + drogon::app().addListener(config.apiHost(), config.apiPort()).setThreadNum(config.apiNumThreads()); drogon::app().run(); return 0; diff --git a/src/utils/app-config/app-config.cpp b/src/utils/app-config/app-config.cpp index 2ab12f0..caf86c4 100644 --- a/src/utils/app-config/app-config.cpp +++ b/src/utils/app-config/app-config.cpp @@ -1,16 +1,16 @@ #include "app-config.h" AppConfig::AppConfig() -: apiHost_(getEnv("API_HOST", "0.0.0.0")), - apiPort_(getEnvInt("API_PORT", 80)), - apiNumThreads_(getEnvInt("API_NUMBER_OF_THREADS", 1)), - apiLogLevel_(parseLogLevel(getEnv("API_LOG_LEVEL", "INFO"))), - databaseHost_(getEnv("POSTGRES_HOST", "0.0.0.0")), - databasePort_(getEnv("POSTGRES_PORT", "5432")), - databaseName_(getEnv("POSTGRES_DB", "to-dos-api-cpp-db")), - databaseUser_(getEnv("POSTGRES_USER", "postgres")), - databasePassword_(getEnv("POSTGRES_PASSWORD", "password")) -{} +{ + apiHost(); + apiPort(); + apiNumThreads(); + databaseHost(); + databasePort(); + databaseName(); + databaseUser(); + databasePort(); +} AppConfig& AppConfig::GetInstance() { @@ -24,7 +24,7 @@ std::string AppConfig::getEnv(std::string name, std::string defaultValue) return value ? std::string(value) : defaultValue; } -int AppConfig::getEnvInt(std::string name, int defaultValue) +uint32_t AppConfig::getEnvInt(std::string name, uint32_t defaultValue) { char* value = std::getenv(name.c_str()); @@ -33,21 +33,129 @@ int AppConfig::getEnvInt(std::string name, int defaultValue) try { - return std::stoi(value); + auto result = std::stoi(value); + auto limit = std::numeric_limits::max(); + + if (result < 0 || result > limit) + throw std::overflow_error( + "error: an attempt to write a " + name + " value which is larger than what can be stored in a " + std::to_string(limit) + ); + + return static_cast(result); } - catch (const std::exception&) + catch (const std::exception& e) { + LOG_ERROR << e.what(); return defaultValue; } } trantor::Logger::LogLevel AppConfig::parseLogLevel(const std::string& level) { - if (level == "DEBUG") - return trantor::Logger::kDebug; - if (level == "WARN") - return trantor::Logger::kWarn; + // kTrace < kDebug < kInfo < kWarn < kError if (level == "TRACE") return trantor::Logger::kTrace; - return trantor::Logger::kInfo; + else if (level == "DEBUG") + return trantor::Logger::kDebug; + else if (level == "INFO") + return trantor::Logger::kInfo; + else if (level == "WARN") + return trantor::Logger::kWarn; + else + return trantor::Logger::kError; +} + +const std::string& AppConfig::apiHost() +{ + if (apiHost_.empty()) + { + apiHost_ = getEnv("API_HOST", "0.0.0.0"); + LOG_DEBUG << "Update value: apiHost_=" << apiHost_; + } + + return apiHost_; +} + +const uint32_t& AppConfig::apiPort() +{ + if (!apiPort_) + { + apiPort_ = getEnvInt("API_PORT", 80); + LOG_DEBUG << "Update value: apiPort_=" << apiPort_; + } + + return apiPort_; +} + +const uint32_t& AppConfig::apiNumThreads() +{ + if (!apiNumThreads_) + { + uint32_t numberOfThreads = getEnvInt("API_NUMBER_OF_THREADS", 1); + apiNumThreads_ = numberOfThreads > 0 ? numberOfThreads : 1; + LOG_ERROR << "The number of allocated threads cannot be less than 1"; + LOG_DEBUG << "Update value: apiNumThreads_=" << apiNumThreads_; + } + + return apiNumThreads_; +} + +const trantor::Logger::LogLevel AppConfig::apiLogLevel() +{ + return parseLogLevel(getEnv("API_LOG_LEVEL", "INFO")); +} + +const std::string& AppConfig::databaseHost() +{ + if (databaseHost_.empty()) + { + databaseHost_ = getEnv("POSTGRES_HOST", "0.0.0.0"); + LOG_DEBUG << "Update value: databaseHost_=" << databaseHost_; + } + + return databaseHost_; +} + +const std::string& AppConfig::databasePort() +{ + if (databasePort_.empty()) + { + databasePort_ = getEnv("POSTGRES_PORT", "5432"); + LOG_DEBUG << "Update value: databasePort_=" << databasePort_; + } + + return databasePort_; +} + +const std::string& AppConfig::databaseName() +{ + if (databaseName_.empty()) + { + databaseName_ = getEnv("POSTGRES_DB", "to-dos-api-cpp-db"); + LOG_DEBUG << "Update value: databaseName_=" << databaseName_; + } + + return databaseName_; +} + +const std::string& AppConfig::databaseUser() +{ + if (databaseUser_.empty()) + { + databaseUser_ = getEnv("POSTGRES_USER", "postgres"); + LOG_DEBUG << "Update value: databaseUser_=" << databaseUser_; + } + + return databaseUser_; +} + +const std::string& AppConfig::databasePassword() +{ + if (databasePassword_.empty()) + { + databasePassword_ = getEnv("POSTGRES_PASSWORD", "password"); + LOG_DEBUG << "Update value: databasePassword_=" << databasePassword_; + } + + return databasePassword_; } \ No newline at end of file diff --git a/src/utils/app-config/app-config.h b/src/utils/app-config/app-config.h index 05b8a61..f4cf07b 100644 --- a/src/utils/app-config/app-config.h +++ b/src/utils/app-config/app-config.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include #include @@ -18,9 +20,9 @@ class AppConfig AppConfig& operator=(const AppConfig&) = delete; std::string apiHost_; - int apiPort_; - int apiNumThreads_; - trantor::Logger::LogLevel apiLogLevel_; + uint32_t apiPort_ = 0; + uint32_t apiNumThreads_ = 0; + trantor::Logger::LogLevel apiLogLevel_ = trantor::Logger::kInfo; std::string databaseHost_; std::string databasePort_; @@ -41,56 +43,58 @@ class AppConfig * @param defaultValue is the value that will be used if the environment variable doesn't exist * @return std::string */ - std::string getEnv(std::string name, std::string defaultValue); + static std::string getEnv(std::string name, std::string defaultValue); /** * @brief Function that retrieves a value from an environment variable and converts it to an integer type * @param name is the name of the environment variable * @param defaultValue is the value that will be used if the environment variable doesn't exist - * @return int + * @return uint32_t */ - int getEnvInt(std::string name, int defaultValue); + static uint32_t getEnvInt(std::string name, uint32_t defaultValue); /** - * @brief Function for converting a string representing a logging level to the `trantor` type. Default is `trantor::Logger::kInfo` + * @brief Function for converting a string representing a logging level to the `trantor` type. Default is `trantor::Logger::kError` * @param level is a string containing the logging level. */ - trantor::Logger::LogLevel parseLogLevel(const std::string& level); + static trantor::Logger::LogLevel parseLogLevel(const std::string& level); /** * @brief Getter for the host value from the environment * variable `API_HOST`. Default is `0.0.0.0` * @return const std::string */ - const std::string& apiHost() const { return apiHost_; } + const std::string& apiHost(); /** * @brief Getter for the port value from the environment * variable `API_PORT`. Default is `80` - * @return const int + * @return const uint32_t */ - const int apiPort() const { return apiPort_; } + const uint32_t& apiPort(); /** * @brief Getter for the numbers of threads value from the * environment variable `API_NUMBER_OF_THREADS`. Default is `1` - * @return const int + * @return const uint32_t */ - const int apiNumThreads() const { return apiNumThreads_; } + const uint32_t& apiNumThreads(); /** - * @brief Getter for the log level value from the environment + * @brief Function for getting the log level value from the environment * variable `API_LOG_LEVEL`. Default is `INFO` + * @note The method must be static so that the level can be set before the class is initialized; + * otherwise, logs from other levels will be displayed. * @return const trantor::Logger::LogLevel */ - const trantor::Logger::LogLevel apiLogLevel() const { return apiLogLevel_; } + static const trantor::Logger::LogLevel apiLogLevel(); /** * @brief Getter for the database host value from the * environment variable `POSTGRES_HOST`. Default is `0.0.0.0` * @return const std::string */ - const std::string& databaseHost() const { return databaseHost_; } + const std::string& databaseHost(); /** * @brief Getter for the database port value from the @@ -98,7 +102,7 @@ class AppConfig * @return const std::string */ - const std::string& databasePort() const { return databasePort_; } + const std::string& databasePort(); /** * @brief Getter for the database name value from the @@ -106,14 +110,14 @@ class AppConfig * `to-dos-api-cpp-db` * @return const std::string */ - const std::string& databaseName() const { return databaseName_; } + const std::string& databaseName(); /** * @brief Getter for the database user value from the * environment variable `POSTGRES_USER`. Default is `postgres` * @return const std::string */ - const std::string& databaseUser() const { return databaseUser_; } + const std::string& databaseUser(); /** * @brief Getter for the database password value from the @@ -121,5 +125,5 @@ class AppConfig * `password` * @return const std::string */ - const std::string& databasePassword() const { return databasePassword_; } + const std::string& databasePassword(); }; \ No newline at end of file From 221c5f45382e78c12beacb3bce6bfdd3965ec710 Mon Sep 17 00:00:00 2001 From: Artem Sheptunov <106321977+Infindery@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:16:38 +0500 Subject: [PATCH 08/14] ci(workflows): #36: add a step to create the .env file so that the devcontainer can start correctly --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d5b01f0..0eb78e5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,15 +24,15 @@ jobs: build/Debug/generators key: ${{ env.cache-name }}-${{ hashFiles('conanfile.py') }} - - name: Prepare - # we need to create a .env file, because without it, the Dev Container won't be able to start + # we need to create a .env file, because without it, the Dev Container won't be able to start + - name: Creating a .env file run: touch .env - name: Install and build Conan dependencies if: steps.cache-conan-packages.outputs.cache-hit != 'true' uses: devcontainers/ci@v0.3 with: - runCmd: | + runCmd: | mkdir -p .conan2/profiles cp .devcontainer/to-dos-conan-profile.conf .conan2/profiles/default From 7242eaa022a9e2d6c37296c9864d425767eb3b0d Mon Sep 17 00:00:00 2001 From: Artem Sheptunov <106321977+aasheptunov@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:54:48 +0500 Subject: [PATCH 09/14] docs(readme): #36: reverted the automatic change, as it was not necessary --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c8936db..3458435 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ When dependencies are built, use the command `conan build . -pr:h profiles/to-do #### Before launching web server: - Run the database container via docker compose command `docker compose up -d` from workspace. -- Import the environment variables defined in the .env file in the project root. The environment variables were automatically exported from .env when the container was built. If the contents of the .env file have been modified after the container was built, run the command `export $(grep -v ‘^#’ .env | xargs)`, but keep in mind that the environment variables will only be visible in the terminal session where the command was executed. +- Import the environment variables defined in the .env file in the project root. The environment variables were automatically exported from .env when the container was built. If the contents of the .env file have been modified after the container was built, run the command `export $(grep -v '^#' .env | xargs)`, but keep in mind that the environment variables will only be visible in the terminal session where the command was executed. To launch the executable, click Launch in the CMake extension.

cmakeLaunch

@@ -94,4 +94,4 @@ The alembic tool is used to work with migrations. To work with it, you need to m - Create/change python model according declared cpp model. - Change terminal workspace to `src/data`. - Use the alembic command `alembic revision --autogenerate -m ''` for create new migration to database. -- If its needed upgrade local database with latest migration with commnd `alembic upgrade head`. \ No newline at end of file +- If its needed upgrade local database with latest migration with commnd `alembic upgrade head`. From 84dcbb9d6dce6d2b95da7717c1fe0face21c8ce1 Mon Sep 17 00:00:00 2001 From: Artem Sheptunov <106321977+Infindery@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:26:03 +0500 Subject: [PATCH 10/14] fix(environment): #36: fixed a logic error in the error logging, as the log was logged in any case --- src/utils/app-config/app-config.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/utils/app-config/app-config.cpp b/src/utils/app-config/app-config.cpp index caf86c4..9fc2963 100644 --- a/src/utils/app-config/app-config.cpp +++ b/src/utils/app-config/app-config.cpp @@ -92,8 +92,17 @@ const uint32_t& AppConfig::apiNumThreads() if (!apiNumThreads_) { uint32_t numberOfThreads = getEnvInt("API_NUMBER_OF_THREADS", 1); - apiNumThreads_ = numberOfThreads > 0 ? numberOfThreads : 1; - LOG_ERROR << "The number of allocated threads cannot be less than 1"; + + if (numberOfThreads > 0) + { + apiNumThreads_ = numberOfThreads; + } + else + { + apiNumThreads_ = 1; + LOG_ERROR << "The number of allocated threads cannot be less than 1"; + } + LOG_DEBUG << "Update value: apiNumThreads_=" << apiNumThreads_; } From 67814bbf39b1a4aaba928ee2f328f38499a6c0b1 Mon Sep 17 00:00:00 2001 From: Artem Sheptunov <106321977+Infindery@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:29:20 +0500 Subject: [PATCH 11/14] refactor(environment): #36: removal of an unused variable, since the logging level value was removed --- src/utils/app-config/app-config.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils/app-config/app-config.h b/src/utils/app-config/app-config.h index f4cf07b..e922278 100644 --- a/src/utils/app-config/app-config.h +++ b/src/utils/app-config/app-config.h @@ -22,7 +22,6 @@ class AppConfig std::string apiHost_; uint32_t apiPort_ = 0; uint32_t apiNumThreads_ = 0; - trantor::Logger::LogLevel apiLogLevel_ = trantor::Logger::kInfo; std::string databaseHost_; std::string databasePort_; From c531bd7b2408f1d6e1502cc604fc462dc9801ae6 Mon Sep 17 00:00:00 2001 From: Artem Sheptunov <106321977+Infindery@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:47:03 +0500 Subject: [PATCH 12/14] docs(logging): #36: editing the comment to make it clearer --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index ac88e03..f4f682d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,7 +3,8 @@ int main() { - // We need to set the logging level so that it is used instead of the default + // We need to set the logging level right away; otherwise, the default level + // will be used until .setLogLevel is called drogon::app().setLogLevel(AppConfig::apiLogLevel()); auto& config = AppConfig::GetInstance(); From 0125b7885bb3d7e2c28bd17961988eb975062d6d Mon Sep 17 00:00:00 2001 From: Artem Sheptunov <106321977+Infindery@users.noreply.github.com> Date: Wed, 25 Mar 2026 10:30:33 +0500 Subject: [PATCH 13/14] feat(environment): #36: add setters for variables, move the set logic from getters to setters to follow the logic of the methods --- src/data/db_connection.cpp | 10 +- src/main.cpp | 4 +- src/utils/app-config/app-config.cpp | 160 ++++++++++++---------------- src/utils/app-config/app-config.h | 110 +++++++++++++------ 4 files changed, 155 insertions(+), 129 deletions(-) diff --git a/src/data/db_connection.cpp b/src/data/db_connection.cpp index 319db7b..d7ae6f4 100644 --- a/src/data/db_connection.cpp +++ b/src/data/db_connection.cpp @@ -17,11 +17,11 @@ std::shared_ptr DbConnection::get() { auto& config = AppConfig::GetInstance(); - const std::string host = config.databaseHost(); - const std::string port = config.databasePort(); - const std::string user = config.databaseUser(); - const std::string password = config.databasePassword(); - const std::string dbname = config.databaseName(); + const std::string host = config.getDatabaseHost(); + const std::string port = config.getDatabasePort(); + const std::string user = config.getDatabaseUser(); + const std::string password = config.getDatabasePassword(); + const std::string dbname = config.getDatabaseName(); std::string conn = "host=" + host + " port=" + port + " dbname=" + dbname + " user=" + user + " password=" + password; diff --git a/src/main.cpp b/src/main.cpp index f4f682d..009554b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,11 +5,11 @@ int main() { // We need to set the logging level right away; otherwise, the default level // will be used until .setLogLevel is called - drogon::app().setLogLevel(AppConfig::apiLogLevel()); + drogon::app().setLogLevel(AppConfig::getApiLogLevel()); auto& config = AppConfig::GetInstance(); - drogon::app().addListener(config.apiHost(), config.apiPort()).setThreadNum(config.apiNumThreads()); + drogon::app().addListener(config.getApiHost(), config.getApiPort()).setThreadNum(config.getApiNumThreads()); drogon::app().run(); return 0; diff --git a/src/utils/app-config/app-config.cpp b/src/utils/app-config/app-config.cpp index 9fc2963..025c3c3 100644 --- a/src/utils/app-config/app-config.cpp +++ b/src/utils/app-config/app-config.cpp @@ -2,14 +2,14 @@ AppConfig::AppConfig() { - apiHost(); - apiPort(); - apiNumThreads(); - databaseHost(); - databasePort(); - databaseName(); - databaseUser(); - databasePort(); + setApiHost(getEnv("API_HOST", "0.0.0.0")); + setApiPort(getEnvInt("API_PORT", 80)); + setApiNumThreads(getEnvInt("API_NUMBER_OF_THREADS", 1)); + setDatabaseHost(getEnv("POSTGRES_HOST", "0.0.0.0")); + setDatabasePort(getEnv("POSTGRES_PORT", "5432")); + setDatabaseName(getEnv("POSTGRES_DB", "to-dos-api-cpp-db")); + setDatabaseUser(getEnv("POSTGRES_USER", "postgres")); + setDatabasePassword(getEnv("POSTGRES_PASSWORD", "password")); } AppConfig& AppConfig::GetInstance() @@ -34,7 +34,7 @@ uint32_t AppConfig::getEnvInt(std::string name, uint32_t defaultValue) try { auto result = std::stoi(value); - auto limit = std::numeric_limits::max(); + auto limit = std::numeric_limits::max(); if (result < 0 || result > limit) throw std::overflow_error( @@ -65,106 +65,88 @@ trantor::Logger::LogLevel AppConfig::parseLogLevel(const std::string& level) return trantor::Logger::kError; } -const std::string& AppConfig::apiHost() +void AppConfig::setApiHost(std::string apiHost) { - if (apiHost_.empty()) - { - apiHost_ = getEnv("API_HOST", "0.0.0.0"); - LOG_DEBUG << "Update value: apiHost_=" << apiHost_; - } + apiHost_ = apiHost; + LOG_DEBUG << "Update value: apiHost_=" << apiHost_; +}; - return apiHost_; -} +void AppConfig::setApiPort(uint32_t apiPort) +{ + apiPort_ = apiPort; + LOG_DEBUG << "Update value: apiPort_=" << apiPort_; +}; -const uint32_t& AppConfig::apiPort() +void AppConfig::setApiNumThreads(uint32_t apiNumThreads) { - if (!apiPort_) + uint32_t numberOfThreads = apiNumThreads; + + if (numberOfThreads > 0) { - apiPort_ = getEnvInt("API_PORT", 80); - LOG_DEBUG << "Update value: apiPort_=" << apiPort_; + apiNumThreads_ = numberOfThreads; } - - return apiPort_; -} - -const uint32_t& AppConfig::apiNumThreads() -{ - if (!apiNumThreads_) + else { - uint32_t numberOfThreads = getEnvInt("API_NUMBER_OF_THREADS", 1); - - if (numberOfThreads > 0) - { - apiNumThreads_ = numberOfThreads; - } - else - { - apiNumThreads_ = 1; - LOG_ERROR << "The number of allocated threads cannot be less than 1"; - } - - LOG_DEBUG << "Update value: apiNumThreads_=" << apiNumThreads_; + apiNumThreads_ = 1; + LOG_ERROR << "The number of allocated threads cannot be less than 1"; } - return apiNumThreads_; -} + LOG_DEBUG << "Update value: apiNumThreads_=" << apiNumThreads_; +}; -const trantor::Logger::LogLevel AppConfig::apiLogLevel() +void AppConfig::setDatabaseHost(std::string databaseHost) { - return parseLogLevel(getEnv("API_LOG_LEVEL", "INFO")); -} + databaseHost_ = databaseHost; + LOG_DEBUG << "Update value: databaseHost_=" << databaseHost_; +}; -const std::string& AppConfig::databaseHost() +void AppConfig::setDatabasePort(std::string databasePort) { - if (databaseHost_.empty()) - { - databaseHost_ = getEnv("POSTGRES_HOST", "0.0.0.0"); - LOG_DEBUG << "Update value: databaseHost_=" << databaseHost_; - } - - return databaseHost_; -} + databasePort_ = databasePort; + LOG_DEBUG << "Update value: databasePort_=" << databasePort_; +}; -const std::string& AppConfig::databasePort() +void AppConfig::setDatabaseName(std::string databaseName) { - if (databasePort_.empty()) - { - databasePort_ = getEnv("POSTGRES_PORT", "5432"); - LOG_DEBUG << "Update value: databasePort_=" << databasePort_; - } + databaseName_ = databaseName; + LOG_DEBUG << "Update value: databaseName_=" << databaseName_; +}; - return databasePort_; -} +void AppConfig::setDatabaseUser(std::string databaseUser) +{ + databaseUser_ = databaseUser; + LOG_DEBUG << "Update value: databaseUser_=" << databaseUser_; +}; -const std::string& AppConfig::databaseName() +void AppConfig::setDatabasePassword(std::string databasePassword) { - if (databaseName_.empty()) - { - databaseName_ = getEnv("POSTGRES_DB", "to-dos-api-cpp-db"); - LOG_DEBUG << "Update value: databaseName_=" << databaseName_; - } + databasePassword_ = databasePassword; + LOG_DEBUG << "Update value: databasePassword_=" << databasePassword_; +}; - return databaseName_; -} +const std::string& AppConfig::getApiHost() const +{ return apiHost_; } -const std::string& AppConfig::databaseUser() -{ - if (databaseUser_.empty()) - { - databaseUser_ = getEnv("POSTGRES_USER", "postgres"); - LOG_DEBUG << "Update value: databaseUser_=" << databaseUser_; - } +const uint32_t& AppConfig::getApiPort() const +{ return apiPort_; } - return databaseUser_; -} +const uint32_t& AppConfig::getApiNumThreads() const +{ return apiNumThreads_; } -const std::string& AppConfig::databasePassword() -{ - if (databasePassword_.empty()) - { - databasePassword_ = getEnv("POSTGRES_PASSWORD", "password"); - LOG_DEBUG << "Update value: databasePassword_=" << databasePassword_; - } +const trantor::Logger::LogLevel AppConfig::getApiLogLevel() +{ return parseLogLevel(getEnv("API_LOG_LEVEL", "INFO")); } + +const std::string& AppConfig::getDatabaseHost() const +{ return databaseHost_; } + +const std::string& AppConfig::getDatabasePort() const +{ return databasePort_; } + +const std::string& AppConfig::getDatabaseName() const +{ return databaseName_; } + +const std::string& AppConfig::getDatabaseUser() const +{ return databaseUser_; } - return databasePassword_; -} \ No newline at end of file +const std::string& AppConfig::getDatabasePassword() const +{ return databasePassword_; } \ No newline at end of file diff --git a/src/utils/app-config/app-config.h b/src/utils/app-config/app-config.h index e922278..86fa4b3 100644 --- a/src/utils/app-config/app-config.h +++ b/src/utils/app-config/app-config.h @@ -20,8 +20,8 @@ class AppConfig AppConfig& operator=(const AppConfig&) = delete; std::string apiHost_; - uint32_t apiPort_ = 0; - uint32_t apiNumThreads_ = 0; + uint32_t apiPort_; + uint32_t apiNumThreads_; std::string databaseHost_; std::string databasePort_; @@ -29,6 +29,62 @@ class AppConfig std::string databaseUser_; std::string databasePassword_; + /** + * @brief Setter for the `apiHost_` variable + * @param apiHost is host on which the API will be run + * @return void + */ + void setApiHost(std::string apiHost); + + /** + * @brief Setter for the `apiPort_` variable + * @param apiPort is port on which the API will be run + * @return void + */ + void setApiPort(uint32_t apiPort); + + /** + * @brief Setter for the `apiNumThreads_` variable + * @param apiNumThreads is number of threads on which the API will run + * @return void + */ + void setApiNumThreads(uint32_t apiNumThreads); + + /** + * @brief Setter for the `databaseHost_` variable + * @param databaseHost is the host that the API will use to connect to the database + * @return void + */ + void setDatabaseHost(std::string databaseHost); + + /** + * @brief Setter for the `databasePort_` variable + * @param databasePort is the port that the API will use to connect to the database + * @return void + */ + void setDatabasePort(std::string databasePort); + + /** + * @brief Setter for the `databaseName_` variable + * @param databaseName is the name that the API will use to connect to the database + * @return void + */ + void setDatabaseName(std::string databaseName); + + /** + * @brief Setter for the `databaseUser_` variable + * @param databaseUser is the user that the API will use to connect to the database + * @return void + */ + void setDatabaseUser(std::string databaseUser); + + /** + * @brief Setter for the `databasePassword_` variable + * @param databasePassword is the password that the API will use to connect to the database + * @return void + */ + void setDatabasePassword(std::string databasePassword); + public: /** * @brief Function to retrieve an instance of the AppConfig class @@ -59,70 +115,58 @@ class AppConfig static trantor::Logger::LogLevel parseLogLevel(const std::string& level); /** - * @brief Getter for the host value from the environment - * variable `API_HOST`. Default is `0.0.0.0` + * @brief Getter for the `apiHost_` variable * @return const std::string */ - const std::string& apiHost(); + const std::string& getApiHost() const; /** - * @brief Getter for the port value from the environment - * variable `API_PORT`. Default is `80` + * @brief Getter for the `apiPort_` variable * @return const uint32_t */ - const uint32_t& apiPort(); + const uint32_t& getApiPort() const; /** - * @brief Getter for the numbers of threads value from the - * environment variable `API_NUMBER_OF_THREADS`. Default is `1` + * @brief Getter for the `apiNumThreads_` variable * @return const uint32_t */ - const uint32_t& apiNumThreads(); + const uint32_t& getApiNumThreads() const; /** - * @brief Function for getting the log level value from the environment - * variable `API_LOG_LEVEL`. Default is `INFO` + * @brief Getter for the `apiLogLevel_` variable * @note The method must be static so that the level can be set before the class is initialized; - * otherwise, logs from other levels will be displayed. + * otherwise, logs from other levels will be displayed * @return const trantor::Logger::LogLevel */ - static const trantor::Logger::LogLevel apiLogLevel(); + static const trantor::Logger::LogLevel getApiLogLevel(); /** - * @brief Getter for the database host value from the - * environment variable `POSTGRES_HOST`. Default is `0.0.0.0` + * @brief Getter for the `databaseHost_` variable * @return const std::string */ - const std::string& databaseHost(); + const std::string& getDatabaseHost() const; /** - * @brief Getter for the database port value from the - * environment variable `POSTGRES_PORT`. Default is `5432` - + * @brief Getter for the `databasePort_` variable * @return const std::string */ - const std::string& databasePort(); + const std::string& getDatabasePort() const; /** - * @brief Getter for the database name value from the - * environment variable `POSTGRES_DB`. Default is - * `to-dos-api-cpp-db` + * @brief Getter for the `databaseName_` variable * @return const std::string */ - const std::string& databaseName(); + const std::string& getDatabaseName() const; /** - * @brief Getter for the database user value from the - * environment variable `POSTGRES_USER`. Default is `postgres` + * @brief Getter for the `databaseUser_` variable * @return const std::string */ - const std::string& databaseUser(); + const std::string& getDatabaseUser() const; /** - * @brief Getter for the database password value from the - * environment variable `POSTGRES_PASSWORD`. Default is - * `password` + * @brief Getter for the `databasePassword_` variable * @return const std::string */ - const std::string& databasePassword(); + const std::string& getDatabasePassword() const; }; \ No newline at end of file From 828e43cbf81203c9b6d5014f3e3e849e9131a043 Mon Sep 17 00:00:00 2001 From: Artem Sheptunov <106321977+Infindery@users.noreply.github.com> Date: Wed, 25 Mar 2026 13:33:15 +0500 Subject: [PATCH 14/14] feat(environment): #36: add a log message that appears when an error occurs during extraction to inform the user that the default value is being used --- src/utils/app-config/app-config.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/utils/app-config/app-config.cpp b/src/utils/app-config/app-config.cpp index 025c3c3..f8c48b0 100644 --- a/src/utils/app-config/app-config.cpp +++ b/src/utils/app-config/app-config.cpp @@ -21,7 +21,16 @@ AppConfig& AppConfig::GetInstance() std::string AppConfig::getEnv(std::string name, std::string defaultValue) { char* value = std::getenv(name.c_str()); - return value ? std::string(value) : defaultValue; + + if (value) + { + return std::string(value); + } + else + { + LOG_WARN << "Failed to get the value of the " << name << " environment variable; the default value will be used: " << defaultValue; + return defaultValue; + } } uint32_t AppConfig::getEnvInt(std::string name, uint32_t defaultValue)