Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions bin/configs/other/cpp-oatpp-server.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
generatorName: cpp-oatpp-server
outputDir: samples/server/petstore/cpp-oatpp
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/cpp-oatpp-server

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ org.openapitools.codegen.languages.ClojureClientCodegen
org.openapitools.codegen.languages.ConfluenceWikiCodegen
org.openapitools.codegen.languages.CppQt5ClientCodegen
org.openapitools.codegen.languages.CppQt5QHttpEngineServerCodegen
org.openapitools.codegen.languages.CppOatppServerCodegen
org.openapitools.codegen.languages.CppPistacheServerCodegen
org.openapitools.codegen.languages.CppRestbedServerCodegen
org.openapitools.codegen.languages.CppRestSdkClientCodegen
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# REST API Server for {{appName}}

## Overview
This API Server was generated by the [OpenAPI Generator](https://openapi-generator.tech) project.
It uses the [Oat++](https://github.com/oatpp/oatpp) Framework.

## Files organization
The Oat++ C++ REST server generator creates three folders:
- `api`: This folder contains the handlers for each method specified in the OpenAPI definition. Every handler extracts
the path and body parameters (if any) from the requests and tries to parse and possibly validate them.
Once this step is completed, the main API class calls the corresponding abstract method that should be implemented
by the developer (a basic implementation is provided under the `impl` folder)
- `impl`: As written above, the implementation folder contains, for each API, the corresponding implementation class,
which extends the main API class and implements the abstract methods.
Every method receives the path and body parameters as constant reference variables and a reference to the response
object, that should be filled with the right response and sent at the end of the method with the command:
response.send(returnCode, responseBody, [mimeType])
- `model`: This folder contains the corresponding class for every object schema found in the OpenAPI specification.

The main folder contains also a file with a main that can be used to start the server.
Of course, is you should customize this file based on your needs

## Installation
First of all, you need to download and install the libraries listed [here](#libraries-required).

Once the libraries are installed, in order to compile and run the server please follow the steps below:
```bash
mkdir build
cd build
cmake ..
make
```

Once compiled run the server:

```bash
cd build
./api-server
```

## Libraries required
- [Oat++](https://github.com/oatpp/oatpp)
- [JSON for Modern C++](https://github.com/nlohmann/json/#integration): Please download the `json.hpp` file and
put it under the model/nlohmann folder

## Namespaces
{{{apiPackage}}}
{{{modelPackage}}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{{>licenseInfo}}
{{#operations}}/*
* {{classname}}.h
*
* {{description}}
*/

#ifndef {{classname}}_H_
#define {{classname}}_H_

{{{defaultInclude}}}
#include <pistache/http.h>
#include <pistache/router.h>
#include <pistache/http_headers.h>
#include <pistache/optional.h>
{{^hasModelImport}}#include <nlohmann/json.hpp>{{/hasModelImport}}

{{#imports}}{{{import}}}
{{/imports}}

{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}

{{#hasModelImport}}
using namespace {{modelNamespace}};{{/hasModelImport}}

class {{declspec}} {{classname}} {
public:
{{classname}}(std::shared_ptr<Pistache::Rest::Router>);
virtual ~{{classname}}() {}
void init();

const std::string base = "{{basePathWithoutHost}}";

private:
void setupRoutes();

{{#operation}}
void {{operationIdSnakeCase}}_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
{{/operation}}
void {{classnameSnakeLowerCase}}_default_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);

std::shared_ptr<Pistache::Rest::Router> router;
{{#operation}}

/// <summary>
/// {{summary}}
/// </summary>
/// <remarks>
/// {{notes}}
/// </remarks>
{{#vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
{{#allParams}}
/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
{{/allParams}}
virtual void {{operationIdSnakeCase}}({{#allParams}}const {{{dataType}}} &{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}Pistache::Http::ResponseWriter &response) = 0;
{{/vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
{{^vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
virtual void {{operationIdSnakeCase}}(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter &response) = 0;
{{/vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
{{/operation}}

};

{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}

#endif /* {{classname}}_H_ */

{{/operations}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{{>licenseInfo}}

{{#operations}}/*
* {{classname}}Impl.h
*
* {{description}}
*/

#ifndef {{classnameSnakeUpperCase}}_IMPL_H_
#define {{classnameSnakeUpperCase}}_IMPL_H_

{{{defaultInclude}}}
#include <pistache/endpoint.h>
#include <pistache/http.h>
#include <pistache/router.h>
#include <memory>

#include <{{classname}}.h>

#include <pistache/optional.h>

{{#imports}}{{{import}}}
{{/imports}}

{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}

{{#hasModelImport}}
using namespace {{modelNamespace}};{{/hasModelImport}}

class {{classname}}Impl : public {{apiNamespace}}::{{classname}} {
public:
{{classname}}Impl(std::shared_ptr<Pistache::Rest::Router>);
~{{classname}}Impl() {}

{{#operation}}
{{#vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
void {{operationIdSnakeCase}}({{#allParams}}const {{{dataType}}} &{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}Pistache::Http::ResponseWriter &response);
{{/vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
{{^vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
void {{operationIdSnakeCase}}(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter &response);
{{/vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
{{/operation}}

};

{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}

{{/operations}}


#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{{>licenseInfo}}
{{#operations}}

#include "{{classname}}Impl.h"

{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}

{{#hasModelImport}}
using namespace {{modelNamespace}};{{/hasModelImport}}

{{classname}}Impl::{{classname}}Impl(std::shared_ptr<Pistache::Rest::Router> rtr)
: {{classname}}(rtr)
{ }

{{#operation}}
{{#vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
void {{classname}}Impl::{{operationIdSnakeCase}}({{#allParams}}const {{{dataType}}} &{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}Pistache::Http::ResponseWriter &response) {
response.send(Pistache::Http::Code::Ok, "Do some magic\n");
}
{{/vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
{{^vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
void {{classname}}Impl::{{operationIdSnakeCase}}(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter &response){
response.send(Pistache::Http::Code::Ok, "Do some magic\n");
}
{{/vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
{{/operation}}

{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}

{{/operations}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
{{>licenseInfo}}
{{#operations}}

#include "{{classname}}.h"
#include "{{prefix}}Helpers.h"

{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}

using namespace {{helpersNamespace}};
{{#hasModelImport}}
using namespace {{modelNamespace}};{{/hasModelImport}}

{{classname}}::{{classname}}(std::shared_ptr<Pistache::Rest::Router> rtr) {
router = rtr;
}

void {{classname}}::init() {
setupRoutes();
}

void {{classname}}::setupRoutes() {
using namespace Pistache::Rest;

{{#operation}}
Routes::{{httpMethod}}(*router, base + "{{{vendorExtensions.x-codegen-oatpp-path}}}", Routes::bind(&{{classname}}::{{operationIdSnakeCase}}_handler, this));
{{/operation}}

// Default handler, called when a route is not found
router->addCustomHandler(Routes::bind(&{{classname}}::{{classnameSnakeLowerCase}}_default_handler, this));
}

{{#operation}}
void {{classname}}::{{operationIdSnakeCase}}_handler(const Pistache::Rest::Request &{{#hasParams}}request{{/hasParams}}, Pistache::Http::ResponseWriter response) {
{{#vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
{{#hasPathParams}}
// Getting the path params
{{#pathParams}}
auto {{paramName}} = request.param(":{{paramName}}").as<{{dataType}}>();
{{/pathParams}}
{{/hasPathParams}}{{#hasBodyParam}}
// Getting the body param
{{#bodyParam}}
{{^isPrimitiveType}}{{^isContainer}}
{{baseType}} {{paramName}};{{/isContainer}}{{#isArray}}std::vector<{{items.baseType}}> {{paramName}};{{/isArray}}{{#isMap}}std::map<std::string, {{items.baseType}}> {{paramName}};{{/isMap}}{{/isPrimitiveType}}
{{#isPrimitiveType}}
{{dataType}} {{paramName}};
{{/isPrimitiveType}}
{{/bodyParam}}
{{/hasBodyParam}}{{#hasQueryParams}}
// Getting the query params
{{#queryParams}}
auto {{paramName}}Query = request.query().get("{{baseName}}");
Pistache::Optional<{{^isContainer}}{{dataType}}{{/isContainer}}{{#isArray}}std::vector<{{items.baseType}}>{{/isArray}}> {{paramName}};
if(!{{paramName}}Query.isEmpty()){
{{^isContainer}}{{dataType}}{{/isContainer}}{{#isArray}}std::vector<{{items.baseType}}>{{/isArray}} valueQuery_instance;
if(fromStringValue({{paramName}}Query.get(), valueQuery_instance)){
{{paramName}} = Pistache::Some(valueQuery_instance);
}
}
{{/queryParams}}
{{/hasQueryParams}}{{#hasHeaderParams}}
// Getting the header params
{{#headerParams}}
auto {{paramName}} = request.headers().tryGetRaw("{{baseName}}");
{{/headerParams}}
{{/hasHeaderParams}}

try {
{{#hasBodyParam}}
{{#bodyParam}}
{{^isPrimitiveType}}
nlohmann::json::parse(request.body()).get_to({{paramName}});
{{/isPrimitiveType}}
{{#isPrimitiveType}}
{{paramName}} = request.body();
{{/isPrimitiveType}}
{{/bodyParam}}
{{/hasBodyParam}}
this->{{operationIdSnakeCase}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}response);
{{/vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
{{^vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
try {
this->{{operationIdSnakeCase}}(request, response);
{{/vendorExtensions.x-codegen-oatpp-is-parsing-supported}}
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
return;
}

}
{{/operation}}

void {{classname}}::{{classnameSnakeLowerCase}}_default_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
response.send(Pistache::Http::Code::Not_Found, "The requested method does not exist");
}

{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}

{{/operations}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
cmake_minimum_required (VERSION 3.2)

project(api-server)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pg -g3" )

{{#addExternalLibs}}
include(ExternalProject)

set(EXTERNAL_INSTALL_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/external)

ExternalProject_Add(PISTACHE
GIT_REPOSITORY https://github.com/oktal/pistache.git
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTERNAL_INSTALL_LOCATION}
)

ExternalProject_Add(NLOHMANN
GIT_REPOSITORY https://github.com/nlohmann/json.git
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTERNAL_INSTALL_LOCATION}

)
include_directories(${EXTERNAL_INSTALL_LOCATION}/include)
link_directories(${EXTERNAL_INSTALL_LOCATION}/lib)
{{/addExternalLibs}}

include_directories(model)
include_directories(api)
include_directories(impl)

file(GLOB SRCS
${CMAKE_CURRENT_SOURCE_DIR}/api/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/impl/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/model/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
)

add_executable(${PROJECT_NAME} ${SRCS} )
{{#addExternalLibs}}add_dependencies(${PROJECT_NAME} PISTACHE NLOHMANN){{/addExternalLibs}}
target_link_libraries(${PROJECT_NAME} pistache pthread)
Loading