├── .gitignore ├── CMakeLists.txt ├── Dockerfile ├── LICENSE ├── README.md ├── azure-pipelines.yml ├── docker-compose.yaml ├── src ├── App.cpp ├── AppComponent.hpp ├── SwaggerComponent.hpp ├── controller │ └── UserController.hpp ├── db │ ├── Database.cpp │ ├── Database.hpp │ └── Model.hpp └── dto │ └── DTOs.hpp ├── test └── tests.cpp └── utility └── install-oatpp-modules.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # custom build 35 | build/ 36 | 37 | # idea 38 | .idea/ 39 | cmake-build-debug/ 40 | */cmake-build-debug/ 41 | 42 | # Mac 43 | **/.DS_Store 44 | 45 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | 3 | set(project_name example-mongodb) 4 | 5 | project(${project_name}) 6 | 7 | set(CMAKE_CXX_STANDARD 11) 8 | 9 | add_library(${project_name}-lib 10 | src/db/Database.cpp 11 | src/db/Database.hpp 12 | src/AppComponent.hpp 13 | src/SwaggerComponent.hpp 14 | src/controller/UserController.hpp 15 | src/dto/DTOs.hpp 16 | src/db/Model.hpp) 17 | 18 | ################################################################### 19 | # Find mongocxx 20 | 21 | find_package(mongocxx REQUIRED) 22 | 23 | message("LIBBSONCXX_INCLUDE_DIRS=${LIBBSONCXX_INCLUDE_DIRS}") 24 | message("LIBBSONCXX_LIBRARIES=${LIBBSONCXX_LIBRARIES}") 25 | 26 | message("LIBMONGOCXX_INCLUDE_DIRS=${LIBMONGOCXX_INCLUDE_DIRS}") 27 | message("LIBMONGOCXX_LIBRARIES=${LIBMONGOCXX_LIBRARIES}") 28 | 29 | ################################################################### 30 | 31 | find_package(oatpp 1.3.0 REQUIRED) 32 | find_package(oatpp-swagger 1.3.0 REQUIRED) 33 | find_package(oatpp-mongo 1.3.0 REQUIRED) 34 | 35 | ## include directories 36 | 37 | target_include_directories(${project_name}-lib 38 | PUBLIC src 39 | ) 40 | 41 | ## link libs 42 | 43 | target_link_libraries(${project_name}-lib 44 | PUBLIC oatpp::oatpp 45 | PUBLIC oatpp::oatpp-swagger 46 | PUBLIC oatpp::oatpp-mongo 47 | ) 48 | 49 | if (TARGET mongo::mongocxx_shared) 50 | target_link_libraries(${project_name}-lib 51 | PUBLIC mongo::mongocxx_shared 52 | ) 53 | message("mongo::mongocxx_shared is used") 54 | elseif(TARGET mongo::mongocxx_static) 55 | target_link_libraries(${project_name}-lib 56 | PUBLIC mongo::mongocxx_static 57 | ) 58 | endif() 59 | 60 | ## define path to swagger-ui res folder 61 | 62 | add_definitions( 63 | -DOATPP_SWAGGER_RES_PATH="${oatpp-swagger_INCLUDE_DIRS}/../bin/oatpp-swagger/res" 64 | ) 65 | 66 | ################################################################# 67 | ## add executables 68 | 69 | add_executable(${project_name} 70 | src/App.cpp 71 | ) 72 | 73 | target_link_libraries(${project_name} ${project_name}-lib) 74 | add_dependencies(${project_name} ${project_name}-lib) 75 | 76 | add_executable(${project_name}-test 77 | test/tests.cpp 78 | ) 79 | 80 | target_link_libraries(${project_name}-test ${project_name}-lib) 81 | add_dependencies(${project_name}-test ${project_name}-lib) 82 | 83 | enable_testing() 84 | add_test(project-tests ${project_name}-test) 85 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM lganzzzo/alpine-mongocxx:latest 2 | 3 | ADD src/ /service/src/ 4 | ADD test/ /service/test/ 5 | 6 | ADD utility/ /service/utility/ 7 | ADD CMakeLists.txt /service/CMakeLists.txt 8 | 9 | WORKDIR /service/utility 10 | 11 | RUN ./install-oatpp-modules.sh Release 12 | 13 | WORKDIR /service/build 14 | 15 | RUN cmake .. 16 | RUN make 17 | 18 | EXPOSE 8000 8000 19 | 20 | ENTRYPOINT ["./example-mongodb"] 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # example-mongodb [![Build Status](https://dev.azure.com/lganzzzo/lganzzzo/_apis/build/status/oatpp.example-mongodb?branchName=master)](https://dev.azure.com/lganzzzo/lganzzzo/_build/latest?definitionId=27&branchName=master) 2 | 3 | Example project how to work with MongoDB using [oatpp-mongo](https://github.com/oatpp/oatpp-mongo) mondule. 4 | Project is a web-service with basic CRUD and Swagger-UI. 5 | *Dockerfile and docker-compose.yaml files included.* 6 | 7 | More About Oat++: 8 | 9 | - [Oat++ Website](https://oatpp.io/) 10 | - [Oat++ Github Repository](https://github.com/oatpp/oatpp) 11 | - [Get Started](https://oatpp.io/docs/start) 12 | 13 | ## Overview 14 | 15 | ### Dependencies 16 | 17 | - [oatpp](https://github.com/oatpp/oatpp) 18 | - [oatpp-swagger](https://github.com/oatpp/oatpp-swagger) 19 | - [oatpp-mongo](https://github.com/oatpp/oatpp-mongo) 20 | - [mongocxx](http://mongocxx.org/) - Temporary dependency. Until the oatpp-mongo driver will be ready-to-use* 21 | 22 | ### Project layout 23 | 24 | ``` 25 | |- CMakeLists.txt // projects CMakeLists.txt 26 | |- src/ 27 | | | 28 | | |- controller/ // Folder containing Controller where all endpoints are declared 29 | | |- db/ // Database class is here 30 | | |- dto/ // DTOs are declared here 31 | | |- App.cpp // main() is here 32 | | |- AppComponent.hpp // Service configuration is loaded here 33 | | |- SwaggerComponent.hpp // Configuration for swagger-ui 34 | | 35 | |- utility/install-oatpp-modules.sh // utility script to install required oatpp-modules. 36 | |- Dockerfile // Dockerfile 37 | |- docker-compose.yaml // Docker-compose with this service and postgresql 38 | ``` 39 | 40 | ## Build and Run 41 | 42 | ### Using CMake 43 | 44 | **Requires** 45 | 46 | - mongocxx installed. To install mongocxx: 47 | - On Mac `$ brew install mongo-cxx-driver` 48 | - On Linux - See Installing mongocxx on Linux section. 49 | 50 | - `oatpp`, `oatpp-swagger`, `oatpp-mongo` modules installed. You may run `utility/install-oatpp-modules.sh` 51 | script to install required oatpp modules. 52 | 53 | ``` 54 | $ mkdir build && cd build 55 | $ cmake .. 56 | $ make 57 | $ ./example-mongodb # - run application. 58 | ``` 59 | 60 | ### In Docker 61 | 62 | #### Dockerfile 63 | 64 | To run the web-service only: 65 | 66 | ``` 67 | $ docker build -t example-mongodb . 68 | $ docker run -p 8000:8000 -e DEMO_MONGO_CONN_STR='mongodb://localhost/UserDB' -t example-mongodb 69 | ``` 70 | 71 | #### docker-compose 72 | 73 | To run both web-service and mongodb: 74 | 75 | ``` 76 | $ docker-compose up 77 | ``` 78 | 79 | 80 | ### After run 81 | 82 | Go to [http://localhost:8000/swagger/ui](http://localhost:8000/swagger/ui) to try endpoints. 83 | 84 | ## Installing mongocxx on Linux 85 | 86 | Installing mongocxx on Linux is an unclear and painful process. 87 | See [ubuntu-cmake-mongocxx/Dockerfile](https://github.com/oatpp/dockerfiles/blob/master/ci/ubuntu-cmake-mongocxx/Dockerfile) 88 | for instructions that worked for us. 89 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Starter pipeline 2 | # Start with a minimal pipeline that you can customize to build and deploy your code. 3 | # Add steps that build, run tests, deploy, and more: 4 | # https://aka.ms/yaml 5 | 6 | jobs: 7 | - job: ubuntu_20_04 8 | displayName: 'Build - Ubuntu 20.04' 9 | continueOnError: false 10 | pool: 11 | vmImage: 'ubuntu-20.04' 12 | container: 13 | image: lganzzzo/ubuntu-cmake-mongocxx:latest 14 | workspace: 15 | clean: all 16 | steps: 17 | - script: | 18 | sudo /bin/bash ./install-oatpp-modules.sh 19 | displayName: 'install oatpp modules' 20 | workingDirectory: utility 21 | - script: | 22 | mkdir build 23 | - script: | 24 | cmake .. 25 | sudo make 26 | displayName: 'CMake' 27 | workingDirectory: build 28 | - script: | 29 | make test ARGS="-V" 30 | displayName: 'Test' 31 | workingDirectory: build 32 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | mongodb: 5 | image: mongo 6 | restart: always 7 | environment: 8 | MONGO_INITDB_ROOT_USERNAME: 9 | MONGO_INITDB_ROOT_PASSWORD: 10 | ports: 11 | - "27017:27017" 12 | 13 | example-service: 14 | build: . 15 | ports: 16 | - "8000:8000" 17 | depends_on: 18 | - "mongodb" 19 | environment: 20 | DEMO_MONGO_CONN_STR: mongodb://mongodb/UserDB 21 | -------------------------------------------------------------------------------- /src/App.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "controller/UserController.hpp" 3 | #include "./AppComponent.hpp" 4 | 5 | #include "oatpp-swagger/Controller.hpp" 6 | #include "oatpp/network/Server.hpp" 7 | 8 | #include 9 | 10 | #include 11 | 12 | void run(const oatpp::base::CommandLineArguments& args) { 13 | 14 | mongocxx::instance instance{}; 15 | 16 | AppComponent components(args); 17 | 18 | /* create ApiControllers and add endpoints to router */ 19 | auto router = components.httpRouter.getObject(); 20 | 21 | oatpp::web::server::api::Endpoints docEndpoints; 22 | 23 | docEndpoints.append(router->addController(UserController::createShared())->getEndpoints()); 24 | 25 | router->addController(oatpp::swagger::Controller::createShared(docEndpoints)); 26 | 27 | /* create server */ 28 | oatpp::network::Server server(components.serverConnectionProvider.getObject(), 29 | components.serverConnectionHandler.getObject()); 30 | 31 | OATPP_LOGD("Server", "Running on port %s...", components.serverConnectionProvider.getObject()->getProperty("port").toString()->c_str()); 32 | 33 | server.run(); 34 | 35 | } 36 | 37 | /** 38 | * main 39 | */ 40 | int main(int argc, const char * argv[]) { 41 | 42 | oatpp::base::Environment::init(); 43 | 44 | run(oatpp::base::CommandLineArguments(argc, argv)); 45 | 46 | /* Print how much objects were created during app running, and what have left-probably leaked */ 47 | /* Disable object counting for release builds using '-D OATPP_DISABLE_ENV_OBJECT_COUNTERS' flag for better performance */ 48 | std::cout << "\nEnvironment:\n"; 49 | std::cout << "objectsCount = " << oatpp::base::Environment::getObjectsCount() << "\n"; 50 | std::cout << "objectsCreated = " << oatpp::base::Environment::getObjectsCreated() << "\n\n"; 51 | 52 | oatpp::base::Environment::destroy(); 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /src/AppComponent.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef example_oatpp_mongo_AppComponent_hpp 3 | #define example_oatpp_mongo_AppComponent_hpp 4 | 5 | #include "db/Database.hpp" 6 | #include "SwaggerComponent.hpp" 7 | 8 | #include "oatpp/web/server/HttpConnectionHandler.hpp" 9 | #include "oatpp/web/server/HttpRouter.hpp" 10 | 11 | #include "oatpp/network/tcp/server/ConnectionProvider.hpp" 12 | 13 | #include "oatpp/parser/json/mapping/ObjectMapper.hpp" 14 | 15 | #include "oatpp/core/base/CommandLineArguments.hpp" 16 | #include "oatpp/core/macro/component.hpp" 17 | 18 | #include 19 | 20 | /** 21 | * Class which creates and holds Application components and registers components in oatpp::base::Environment 22 | * Order of components initialization is from top to bottom 23 | */ 24 | class AppComponent { 25 | private: 26 | oatpp::base::CommandLineArguments m_cmdArgs; 27 | public: 28 | AppComponent(const oatpp::base::CommandLineArguments& cmdArgs) 29 | : m_cmdArgs(cmdArgs) 30 | {} 31 | public: 32 | 33 | /** 34 | * Swagger component 35 | */ 36 | SwaggerComponent swaggerComponent; 37 | 38 | /** 39 | * Create ConnectionProvider component which listens on the port 40 | */ 41 | OATPP_CREATE_COMPONENT(std::shared_ptr, serverConnectionProvider)([] { 42 | return oatpp::network::tcp::server::ConnectionProvider::createShared({"0.0.0.0", 8000, oatpp::network::Address::IP_4}); 43 | }()); 44 | 45 | /** 46 | * Create Router component 47 | */ 48 | OATPP_CREATE_COMPONENT(std::shared_ptr, httpRouter)([] { 49 | return oatpp::web::server::HttpRouter::createShared(); 50 | }()); 51 | 52 | /** 53 | * Create ConnectionHandler component which uses Router component to route requests 54 | */ 55 | OATPP_CREATE_COMPONENT(std::shared_ptr, serverConnectionHandler)([] { 56 | OATPP_COMPONENT(std::shared_ptr, router); // get Router component 57 | return oatpp::web::server::HttpConnectionHandler::createShared(router); 58 | }()); 59 | 60 | /** 61 | * Create ObjectMapper component to serialize/deserialize DTOs in Contoller's API 62 | */ 63 | OATPP_CREATE_COMPONENT(std::shared_ptr, apiObjectMapper)([] { 64 | auto objectMapper = oatpp::parser::json::mapping::ObjectMapper::createShared(); 65 | objectMapper->getDeserializer()->getConfig()->allowUnknownFields = false; 66 | objectMapper->getSerializer()->getConfig()->useBeautifier = true; 67 | return objectMapper; 68 | }()); 69 | 70 | OATPP_CREATE_COMPONENT(std::shared_ptr, database)([this] { 71 | 72 | oatpp::String connectionString = std::getenv("DEMO_MONGO_CONN_STR"); 73 | if(!connectionString){ 74 | connectionString = m_cmdArgs.getNamedArgumentValue("--conn-str", "mongodb://localhost/UserDB"); 75 | } 76 | 77 | mongocxx::uri uri(*connectionString); 78 | return std::make_shared(uri, "UserDB", "all"); 79 | 80 | }()); 81 | 82 | }; 83 | 84 | #endif /* example_oatpp_mongo_AppComponent_hpp */ 85 | -------------------------------------------------------------------------------- /src/SwaggerComponent.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef example_oatpp_mongo_SwaggerComponent_hpp 3 | #define example_oatpp_mongo_SwaggerComponent_hpp 4 | 5 | #include "oatpp-swagger/Model.hpp" 6 | #include "oatpp-swagger/Resources.hpp" 7 | #include "oatpp/core/macro/component.hpp" 8 | 9 | /** 10 | * Swagger ui is served at 11 | * http://host:port/swagger/ui 12 | */ 13 | class SwaggerComponent { 14 | public: 15 | 16 | /** 17 | * General API docs info 18 | */ 19 | OATPP_CREATE_COMPONENT(std::shared_ptr, swaggerDocumentInfo)([] { 20 | 21 | oatpp::swagger::DocumentInfo::Builder builder; 22 | 23 | builder 24 | .setTitle("Example Project - Oat++ MongoDB") 25 | .setDescription("Example project how-to work with MongoDB using oatpp-mongo module") 26 | .setVersion("1.0") 27 | .setContactName("Mr. Porridge") 28 | .setContactUrl("https://oatpp.io/") 29 | 30 | .addServer("http://localhost:8000", "server on localhost"); 31 | 32 | return builder.build(); 33 | 34 | }()); 35 | 36 | 37 | /** 38 | * Swagger-Ui Resources (/lib/oatpp-swagger/res) 39 | */ 40 | OATPP_CREATE_COMPONENT(std::shared_ptr, swaggerResources)([] { 41 | // Make sure to specify correct full path to oatpp-swagger/res folder !!! 42 | return oatpp::swagger::Resources::loadResources(OATPP_SWAGGER_RES_PATH); 43 | }()); 44 | 45 | }; 46 | 47 | #endif /* example_oatpp_mongo_SwaggerComponent_hpp */ 48 | -------------------------------------------------------------------------------- /src/controller/UserController.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef example_oatpp_mongo_UserController_hpp 3 | #define example_oatpp_mongo_UserController_hpp 4 | 5 | #include "db/Database.hpp" 6 | #include "dto/DTOs.hpp" 7 | 8 | #include "oatpp-swagger/Types.hpp" 9 | 10 | #include "oatpp/web/server/api/ApiController.hpp" 11 | #include "oatpp/parser/json/mapping/ObjectMapper.hpp" 12 | 13 | #include "oatpp/core/data/stream/BufferStream.hpp" 14 | 15 | #include "oatpp/core/macro/codegen.hpp" 16 | #include "oatpp/core/macro/component.hpp" 17 | 18 | #include OATPP_CODEGEN_BEGIN(ApiController) 19 | 20 | class UserController : public oatpp::web::server::api::ApiController { 21 | private: 22 | OATPP_COMPONENT(std::shared_ptr, m_database); 23 | public: 24 | UserController(const std::shared_ptr& objectMapper) 25 | : oatpp::web::server::api::ApiController(objectMapper) 26 | {} 27 | public: 28 | 29 | static std::shared_ptr createShared( 30 | OATPP_COMPONENT(std::shared_ptr, objectMapper)) 31 | { 32 | return std::make_shared(objectMapper); 33 | } 34 | 35 | 36 | ENDPOINT_INFO(createUser) { 37 | info->summary = "Create new User"; 38 | info->addConsumes>("application/json"); 39 | info->addResponse>(Status::CODE_200, "application/json"); 40 | } 41 | ENDPOINT("POST", "demo/api/users", createUser, 42 | BODY_DTO(Object, userDto)) { 43 | return createDtoResponse(Status::CODE_200, m_database->createUser(userDto)); 44 | } 45 | 46 | 47 | ENDPOINT_INFO(putUser) { 48 | // general 49 | info->summary = "Update User by username"; 50 | info->addConsumes>("application/json"); 51 | info->addResponse>(Status::CODE_200, "application/json"); 52 | info->addResponse(Status::CODE_404, "text/plain"); 53 | // params specific 54 | info->pathParams["username"].description = "username/login"; 55 | } 56 | ENDPOINT("PUT", "demo/api/users/{username}", putUser, 57 | PATH(String, username), 58 | BODY_DTO(Object, userDto)) { 59 | userDto->username = username; 60 | return createDtoResponse(Status::CODE_200, m_database->updateUser(userDto)); 61 | } 62 | 63 | 64 | ENDPOINT_INFO(getUser) { 65 | // general 66 | info->summary = "Get one User by username"; 67 | info->addResponse>(Status::CODE_200, "application/json"); 68 | info->addResponse(Status::CODE_404, "text/plain"); 69 | // params specific 70 | info->pathParams["username"].description = "username/login"; 71 | } 72 | ENDPOINT("GET", "demo/api/users/{username}", getUser, 73 | PATH(String, username)) { 74 | auto user = m_database->getUser(username); 75 | OATPP_ASSERT_HTTP(user, Status::CODE_404, "User not found"); 76 | return createDtoResponse(Status::CODE_200, user); 77 | } 78 | 79 | 80 | ENDPOINT_INFO(getAllUsers) { 81 | info->summary = "get all stored users"; 82 | info->addResponse>>(Status::CODE_200, "application/json"); 83 | } 84 | ENDPOINT("GET", "demo/api/users", getAllUsers) { 85 | return createDtoResponse(Status::CODE_200, m_database->getAllUsers()); 86 | } 87 | 88 | 89 | ENDPOINT_INFO(deleteUser) { 90 | // general 91 | info->summary = "Delete User by username"; 92 | info->addResponse(Status::CODE_200, "text/plain"); 93 | info->addResponse(Status::CODE_404, "text/plain"); 94 | // params specific 95 | info->pathParams["username"].description = "username/login"; 96 | } 97 | ENDPOINT("DELETE", "demo/api/users/{username}", deleteUser, 98 | PATH(String, username)) { 99 | bool success = m_database->deleteUser(username); 100 | OATPP_ASSERT_HTTP(success, Status::CODE_500, "User not deleted. Perhaps no such User in the Database"); 101 | return createResponse(Status::CODE_200, "User successfully deleted"); 102 | } 103 | 104 | }; 105 | 106 | #include OATPP_CODEGEN_END(ApiController) 107 | 108 | #endif /* example_oatpp_mongo_UserController_hpp */ 109 | -------------------------------------------------------------------------------- /src/db/Database.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Database.hpp" 3 | 4 | #include "db/Model.hpp" 5 | #include "oatpp/core/data/stream/BufferStream.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace db { 12 | 13 | Database::Database(const mongocxx::uri &uri, const std::string &dbName, const std::string &collectionName) 14 | : m_pool(std::make_shared(uri)), m_databaseName(dbName), m_collectionName(collectionName) 15 | {} 16 | 17 | oatpp::Object Database::userFromDto(const oatpp::Object& dto) { 18 | auto user = User::createShared(); 19 | user->_id = dto->username; 20 | user->username = dto->username; 21 | user->active = dto->active; 22 | user->role = dto->role; 23 | return user; 24 | } 25 | 26 | oatpp::Object Database::dtoFromUser(const oatpp::Object& user) { 27 | auto dto = UserDto::createShared(); 28 | dto->username = user->username; 29 | dto->active = user->active; 30 | dto->role = user->role; 31 | return dto; 32 | } 33 | 34 | bsoncxx::document::value Database::createMongoDocument(const oatpp::Void &polymorph) { 35 | // if you have huge docs, you may want to increase starting BufferOutputStream size. 36 | // Or you may want to use oatpp::data::stream::ChunkedBuffer instead - for no-copy growth. 37 | oatpp::data::stream::BufferOutputStream stream; 38 | m_objectMapper.write(&stream, polymorph); 39 | bsoncxx::document::view view(stream.getData(), stream.getCurrentPosition()); 40 | return bsoncxx::document::value(view); 41 | } 42 | 43 | oatpp::Object Database::createUser(const oatpp::Object &userDto) { 44 | auto conn = m_pool->acquire(); 45 | auto collection = (*conn)[m_databaseName][m_collectionName]; 46 | collection.insert_one(createMongoDocument(userFromDto(userDto))); 47 | return userDto; 48 | } 49 | 50 | oatpp::Object Database::updateUser(const oatpp::Object &userDto) { 51 | auto conn = m_pool->acquire(); 52 | auto collection = (*conn)[m_databaseName][m_collectionName]; 53 | 54 | collection.update_one( 55 | createMongoDocument( // <-- Filter 56 | oatpp::Fields({ 57 | {"_id", userDto->username} 58 | }) 59 | ), 60 | createMongoDocument( // <-- Set 61 | oatpp::Fields({ // map 62 | { // pair 63 | "$set", oatpp::Fields({ // you can also define a "strict" DTO for $set operation. 64 | {"active", userDto->active}, 65 | {"role", userDto->role} 66 | }) 67 | } // pair 68 | }) // map 69 | ) 70 | ); 71 | 72 | return userDto; 73 | } 74 | 75 | oatpp::Object Database::getUser(const oatpp::String& username) { 76 | auto conn = m_pool->acquire(); 77 | auto collection = (*conn)[m_databaseName][m_collectionName]; 78 | 79 | auto result = 80 | collection.find_one(createMongoDocument( // <-- Filter 81 | oatpp::Fields({ 82 | {"_id", username} 83 | }) 84 | )); 85 | 86 | if(result) { 87 | auto view = result->view(); 88 | auto bson = oatpp::String((const char*)view.data(), view.length()); 89 | auto user = m_objectMapper.readFromString>(bson); 90 | return dtoFromUser(user); 91 | } 92 | 93 | return nullptr; 94 | } 95 | 96 | oatpp::List> Database::getAllUsers() { 97 | auto conn = m_pool->acquire(); 98 | auto collection = (*conn)[m_databaseName][m_collectionName]; 99 | 100 | auto cursor = collection.find( 101 | createMongoDocument(oatpp::Fields({}) 102 | )); 103 | 104 | oatpp::List> list({}); 105 | 106 | for(auto view : cursor) { 107 | auto bson = oatpp::String((const char*)view.data(), view.length()); 108 | auto user = m_objectMapper.readFromString>(bson); 109 | list->push_back(dtoFromUser(user)); 110 | } 111 | 112 | return list; 113 | 114 | } 115 | 116 | bool Database::deleteUser(const oatpp::String& username) { 117 | auto conn = m_pool->acquire(); 118 | auto collection = (*conn)[m_databaseName][m_collectionName]; 119 | 120 | auto result = 121 | collection.delete_one(createMongoDocument( // <-- Filter 122 | oatpp::Fields({ 123 | {"_id", username} 124 | }) 125 | )); 126 | 127 | if(result) { 128 | return result->deleted_count() == 1; 129 | } 130 | return false; 131 | } 132 | 133 | } -------------------------------------------------------------------------------- /src/db/Database.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef example_oatpp_mongo_Database_hpp 3 | #define example_oatpp_mongo_Database_hpp 4 | 5 | #include "dto/DTOs.hpp" 6 | #include "Model.hpp" 7 | 8 | #include "oatpp-mongo/bson/mapping/ObjectMapper.hpp" 9 | 10 | #include 11 | #include 12 | 13 | namespace db { 14 | 15 | class Database { 16 | private: 17 | std::shared_ptr m_pool; 18 | std::string m_databaseName; 19 | std::string m_collectionName; 20 | oatpp::mongo::bson::mapping::ObjectMapper m_objectMapper; 21 | private: 22 | oatpp::Object userFromDto(const oatpp::Object& dto); 23 | oatpp::Object dtoFromUser(const oatpp::Object& user); 24 | private: 25 | bsoncxx::document::value createMongoDocument(const oatpp::Void &polymorph); 26 | public: 27 | 28 | Database(const mongocxx::uri &uri, const std::string &dbName, const std::string &collectionName); 29 | 30 | oatpp::Object createUser(const oatpp::Object &userDto); 31 | oatpp::Object updateUser(const oatpp::Object &userDto); 32 | oatpp::Object getUser(const oatpp::String& username); 33 | oatpp::List> getAllUsers(); 34 | 35 | bool deleteUser(const oatpp::String& username); 36 | 37 | }; 38 | 39 | } 40 | 41 | #endif //example_oatpp_mongo_Database_hpp 42 | -------------------------------------------------------------------------------- /src/db/Model.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef example_oatpp_mongo_Model_hpp 3 | #define example_oatpp_mongo_Model_hpp 4 | 5 | #include "dto/DTOs.hpp" 6 | 7 | #include "oatpp/core/Types.hpp" 8 | #include "oatpp/core/macro/codegen.hpp" 9 | 10 | #include OATPP_CODEGEN_BEGIN(DTO) 11 | 12 | namespace db { 13 | 14 | class User : public oatpp::DTO { 15 | 16 | DTO_INIT(User, DTO) 17 | 18 | DTO_FIELD(String, _id); 19 | DTO_FIELD(String, username); 20 | DTO_FIELD(Boolean, active); 21 | DTO_FIELD(String, role); 22 | 23 | }; 24 | 25 | } 26 | 27 | #include OATPP_CODEGEN_END(DTO) 28 | 29 | #endif // example_oatpp_mongo_Model_hpp 30 | -------------------------------------------------------------------------------- /src/dto/DTOs.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef example_oatpp_mongo_DTOs_hpp 3 | #define example_oatpp_mongo_DTOs_hpp 4 | 5 | #include "oatpp/core/Types.hpp" 6 | #include "oatpp/core/macro/codegen.hpp" 7 | 8 | #include OATPP_CODEGEN_BEGIN(DTO) 9 | 10 | class UserDto : public oatpp::DTO { 11 | 12 | DTO_INIT(UserDto, DTO) 13 | 14 | DTO_FIELD(String, username); 15 | DTO_FIELD(Boolean, active); 16 | DTO_FIELD(String, role); 17 | 18 | }; 19 | 20 | #include OATPP_CODEGEN_END(DTO) 21 | 22 | #endif /* example_oatpp_mongo_DTOs_hpp */ 23 | -------------------------------------------------------------------------------- /test/tests.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "oatpp-test/UnitTest.hpp" 3 | #include 4 | 5 | namespace { 6 | 7 | class Test : public oatpp::test::UnitTest { 8 | public: 9 | Test() : oatpp::test::UnitTest("[MyTest]") 10 | {} 11 | 12 | void onRun() override { 13 | OATPP_LOGD(TAG, "Hello Test"); 14 | // TODO write correct tests 15 | } 16 | }; 17 | 18 | void runTests() { 19 | OATPP_RUN_TEST(Test); 20 | } 21 | 22 | } 23 | 24 | int main() { 25 | 26 | oatpp::base::Environment::init(); 27 | 28 | runTests(); 29 | 30 | /* Print how much objects were created during app running, and what have left-probably leaked */ 31 | /* Disable object counting for release builds using '-D OATPP_DISABLE_ENV_OBJECT_COUNTERS' flag for better performance */ 32 | std::cout << "\nEnvironment:\n"; 33 | std::cout << "objectsCount = " << oatpp::base::Environment::getObjectsCount() << "\n"; 34 | std::cout << "objectsCreated = " << oatpp::base::Environment::getObjectsCreated() << "\n\n"; 35 | 36 | OATPP_ASSERT(oatpp::base::Environment::getObjectsCount() == 0); 37 | 38 | oatpp::base::Environment::destroy(); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /utility/install-oatpp-modules.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BUILD_TYPE=$1 4 | 5 | if [ -z "$BUILD_TYPE" ]; then 6 | BUILD_TYPE="Debug" 7 | fi 8 | 9 | rm -rf tmp 10 | 11 | mkdir tmp 12 | cd tmp 13 | 14 | ########################################################## 15 | ## install oatpp module 16 | 17 | function install_module () { 18 | 19 | BUILD_TYPE=$1 20 | MODULE_NAME=$2 21 | NPROC=$(nproc) 22 | 23 | if [ -z "$NPROC" ]; then 24 | NPROC=1 25 | fi 26 | 27 | echo "\n\nINSTALLING MODULE '$MODULE_NAME' ($BUILD_TYPE) using $NPROC threads ...\n\n" 28 | 29 | git clone --depth=1 https://github.com/oatpp/$MODULE_NAME 30 | 31 | cd $MODULE_NAME 32 | mkdir build 33 | cd build 34 | 35 | cmake -DOATPP_DISABLE_ENV_OBJECT_COUNTERS=ON -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DOATPP_BUILD_TESTS=OFF .. 36 | make install -j $NPROC 37 | 38 | cd ../../ 39 | 40 | } 41 | 42 | ########################################################## 43 | 44 | install_module $BUILD_TYPE oatpp 45 | install_module $BUILD_TYPE oatpp-swagger 46 | install_module $BUILD_TYPE oatpp-mongo 47 | 48 | cd ../ 49 | rm -rf tmp 50 | --------------------------------------------------------------------------------