Skip to content

Commit 71898ed

Browse files
committed
Added httplib server codegen
Introduces: * Code generation for cpp httplib server * API and model namespace customization. * Custom project naming * Pure virtual functions with request model arguments for custom logic * apiNamespace, modelNamespace, projectName as additionalProperties * CMake library integration * Auto-generated API model usage README
1 parent 815a732 commit 71898ed

File tree

10 files changed

+1795
-2
lines changed

10 files changed

+1795
-2
lines changed

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppHttplibServerCodegen.java

Lines changed: 1159 additions & 0 deletions
Large diffs are not rendered by default.

modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ org.openapitools.codegen.languages.ClojureClientCodegen
1414
org.openapitools.codegen.languages.ConfluenceWikiCodegen
1515
org.openapitools.codegen.languages.CppQtClientCodegen
1616
org.openapitools.codegen.languages.CppQtQHttpEngineServerCodegen
17-
org.openapitools.codegen.languages.CppOatppServerCodegen
1817
org.openapitools.codegen.languages.CppPistacheServerCodegen
1918
org.openapitools.codegen.languages.CppRestbedServerCodegen
2019
org.openapitools.codegen.languages.CppRestbedServerDeprecatedCodegen
@@ -123,7 +122,6 @@ org.openapitools.codegen.languages.RubySinatraServerCodegen
123122
org.openapitools.codegen.languages.RustAxumServerCodegen
124123
org.openapitools.codegen.languages.RustClientCodegen
125124
org.openapitools.codegen.languages.RustServerCodegen
126-
org.openapitools.codegen.languages.RustServerCodegenDeprecated
127125
org.openapitools.codegen.languages.ScalatraServerCodegen
128126
org.openapitools.codegen.languages.ScalaAkkaClientCodegen
129127
org.openapitools.codegen.languages.ScalaCaskServerCodegen
@@ -159,3 +157,4 @@ org.openapitools.codegen.languages.TypeScriptRxjsClientCodegen
159157
org.openapitools.codegen.languages.WsdlSchemaCodegen
160158
org.openapitools.codegen.languages.XojoClientCodegen
161159
org.openapitools.codegen.languages.ZapierClientCodegen
160+
org.openapitools.codegen.languages.CppHttplibServerCodegen
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
project({{cmakeProjectName}} LANGUAGES CXX)
3+
4+
set(TARGET_NAME {{cmakeProjectName}}_openapi_lib)
5+
set(CMAKE_CXX_STANDARD 17)
6+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
7+
file(GLOB API_SRCS
8+
${CMAKE_CURRENT_SOURCE_DIR}/api/*.h
9+
${CMAKE_CURRENT_SOURCE_DIR}/api/*.cpp
10+
)
11+
file(GLOB MODEL_SRCS
12+
${CMAKE_CURRENT_SOURCE_DIR}/model/*.h
13+
${CMAKE_CURRENT_SOURCE_DIR}/model/*.cpp
14+
)
15+
add_library(${TARGET_NAME} ${API_SRCS} ${MODEL_SRCS})
16+
target_include_directories (${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
17+
# Make sure these libraries/headers are available in the build environment before linking
18+
# Required libraries/headers are httplib,ssl,nlohmann::json
19+
target_link_libraries(${TARGET_NAME} httplib ssl nlohmann_json::nlohmann_json)
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# {{projectName}} - C++ Server
2+
3+
## Overview
4+
5+
This server was generated using the [OpenAPI Generator](https://openapi-generator.tech) project.
6+
It uses the [cpp-httplib](https://github.com/yhirose/cpp-httplib) library to implement a lightweight HTTP server
7+
with JSON request/response handling via [nlohmann/json](https://github.com/nlohmann/json).
8+
9+
## Requirements
10+
11+
- C++17 compatible compiler
12+
- [cpp-httplib](https://github.com/yhirose/cpp-httplib) library
13+
- [nlohmann/json](https://github.com/nlohmann/json) library
14+
- CMake (3.14 or higher)
15+
16+
## Project Structure
17+
18+
```
19+
├── CMakeLists.txt # Project build configuration
20+
├── README.md # This file
21+
├── model/ # Generated model classes
22+
└── api/ # Generated API handler classes
23+
```
24+
25+
## Building the Project
26+
27+
```bash
28+
mkdir build
29+
cd build
30+
cmake ..
31+
make
32+
```
33+
34+
## Working with Models
35+
36+
### Model Classes
37+
38+
{{#models}}
39+
{{#model}}
40+
#### {{vendorExtensions.modelNamespace}}::{{vendorExtensions.modelClassName}}
41+
42+
```cpp
43+
// Create a model
44+
auto model = {{vendorExtensions.modelNamespace}}::{{vendorExtensions.modelClassName}}();
45+
{{#vars}}
46+
model.{{vendorExtensions.setter}}(/* value */); // Set {{baseName}}
47+
{{/vars}}
48+
49+
// Serialize to JSON
50+
nlohmann::json json = {{vendorExtensions.modelNamespace}}::{{vendorExtensions.modelClassName}}::toJson(model);
51+
std::string jsonString = json.dump();
52+
53+
// Deserialize from JSON
54+
auto parsedModel = {{vendorExtensions.modelNamespace}}::{{vendorExtensions.modelClassName}}::fromJson(nlohmann::json::parse(jsonString));
55+
```
56+
{{/model}}
57+
{{/models}}
58+
59+
## Implementing API Handlers
60+
61+
### API Classes
62+
63+
{{#apiInfo}}
64+
{{#apis}}
65+
{{#operations}}
66+
#### {{classname}}
67+
68+
To implement this API, create a class that inherits from the generated base class:
69+
70+
```cpp
71+
class {{classname}}Impl : public {{apiNamespace}}::{{classname}} {
72+
public:
73+
{{#operation}}
74+
{{#vendorExtensions}}
75+
{{handlerFunction}}Response {{handlerFunction}}({{#requestModel}}const {{requestModel}}& request{{/requestModel}}{{^requestModel}}const httplib::Request& req{{/requestModel}}) override {
76+
// Implement your logic here
77+
{{#requestModel}}
78+
// Access request data with request.getters
79+
{{/requestModel}}
80+
{{^requestModel}}
81+
// Access request parameters with req.get_param_value("param_name")
82+
{{/requestModel}}
83+
84+
// For successful response:
85+
return {{successType}}();
86+
87+
// For error responses:
88+
{{#statusCodeToTypes}}
89+
// return {{typeName}}(); // Returns a {{statusCode}} status code
90+
{{/statusCodeToTypes}}
91+
}
92+
93+
{{/vendorExtensions}}
94+
{{/operation}}
95+
};
96+
```
97+
{{/operations}}
98+
{{/apis}}
99+
{{/apiInfo}}
100+
101+
## Running the Server
102+
103+
```cpp
104+
#include <httplib.h>
105+
#include "api/YourApiImpl.h"
106+
107+
int main() {
108+
// Create server
109+
auto svr = std::make_unique<httplib::Server>();
110+
111+
// Create API implementation
112+
auto <your_api>Impl = std::make_shared<YourApiImpl>();
113+
114+
// Register routes
115+
<your_api>Impl->RegisterRoutes(std::move(svr));
116+
117+
// Start server on port 8080
118+
svr->listen("localhost", 8080);
119+
120+
return 0;
121+
}
122+
```
123+
124+
## Error Handling
125+
126+
Each API endpoint returns a variant type that can hold either a success response or one of several error responses.
127+
The server automatically handles this variant and returns the appropriate HTTP status code.
128+
129+
## Working with Optional Fields
130+
131+
Optional parameters and model fields are represented using `std::optional`:
132+
133+
```cpp
134+
if (model.getOptionalField()) {
135+
// Field is present
136+
auto value = *model.getOptionalField();
137+
} else {
138+
// Field is not present
139+
}
140+
```
141+
142+
## Additional Resources
143+
144+
- [cpp-httplib Documentation](https://github.com/yhirose/cpp-httplib)
145+
- [nlohmann/json Documentation](https://github.com/nlohmann/json)
146+
- [OpenAPI Generator Documentation](https://openapi-generator.tech/docs/generators/)
147+
```cpp
148+
if (model.getOptionalField()) {
149+
// Field is present
150+
auto value = *model.getOptionalField();
151+
} else {
152+
// Field is not present
153+
}
154+
```
155+
156+
## Additional Resources
157+
158+
- [cpp-httplib Documentation](https://github.com/yhirose/cpp-httplib)
159+
- [nlohmann/json Documentation](https://github.com/nlohmann/json)
160+
- [OpenAPI Generator Documentation](https://openapi-generator.tech/docs/generators/)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{{#licenseHeader}}
2+
{{{licenseHeader}}}
3+
{{/licenseHeader}}
4+
{{^licenseHeader}}
5+
/*
6+
* Generated by OpenAPI Generator, do not edit.
7+
* https://openapi-generator.tech
8+
*/
9+
{{/licenseHeader}}
10+
11+
#pragma once
12+
#include <httplib.h>
13+
#include <nlohmann/json.hpp>
14+
#include <variant>
15+
#include <map>
16+
{{#modelsUsed}}
17+
#include "model/{{.}}.h"
18+
{{/modelsUsed}}
19+
20+
namespace {{apiNamespace}} {
21+
22+
class {{apiClassnameInPascalCase}} {
23+
public:
24+
{{apiClassnameInPascalCase}}() = default;
25+
virtual ~{{apiClassnameInPascalCase}}() = default;
26+
27+
void RegisterRoutes(httplib::Server& svr);
28+
29+
{{#operations}}
30+
{{#operation}}
31+
{{#vendorExtensions}}
32+
33+
// Response type for {{handlerFunction}}
34+
using {{handlerFunction}}Response = std::variant<
35+
{{successType}}
36+
{{#errorTypes}}
37+
,{{.}}
38+
{{/errorTypes}}
39+
>;
40+
virtual {{handlerFunction}}Response {{handlerFunction}}({{#requestModel}}const {{requestModel}}& request{{/requestModel}}) = 0;
41+
{{/vendorExtensions}}
42+
{{/operation}}
43+
{{/operations}}
44+
};
45+
46+
} // namespace {{apiNamespace}}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{{#licenseHeader}}
2+
{{{licenseHeader}}}
3+
{{/licenseHeader}}
4+
{{^licenseHeader}}
5+
/*
6+
* Generated by OpenAPI Generator, do not edit
7+
* https://openapi-generator.tech
8+
*/
9+
{{/licenseHeader}}
10+
11+
{{{apiHeaderFileName}}}
12+
13+
namespace {{apiNamespace}} {
14+
15+
void {{apiClassnameInPascalCase}}::RegisterRoutes(httplib::Server& svr) {
16+
{{#operations}}
17+
{{#operation}}
18+
{{#vendorExtensions}}
19+
svr.{{httpMethod}}("{{path}}", [this](const httplib::Request& req, httplib::Response& res) {
20+
try {
21+
{{#requestModel}}
22+
//request has schema in json, Hence parsing the request body to the model
23+
{{requestModel}} request = {{requestModel}}::fromJson(nlohmann::json::parse(req.body));
24+
auto result = {{handlerFunction}}(request);
25+
{{/requestModel}}
26+
{{^requestModel}}
27+
auto result = {{handlerFunction}}();
28+
{{/requestModel}}
29+
30+
std::visit([&](const auto& value) {
31+
using T = std::decay_t<decltype(value)>;
32+
if constexpr (std::is_same_v<T, {{successType}}>) {
33+
res.status = 200;
34+
res.set_content(value.toJson(value).dump(), "application/json");
35+
}
36+
{{#statusCodeToTypes}}
37+
else if constexpr (std::is_same_v<T, {{typeName}}>) {
38+
res.status = {{statusCode}};
39+
res.set_content(value.toJson(value).dump(), "application/json");
40+
}
41+
{{/statusCodeToTypes}}
42+
}, static_cast<const decltype(result)&>(result));
43+
} catch (const nlohmann::json::parse_error& e) {
44+
res.status = 400;
45+
nlohmann::json errorJson = {
46+
{"message", "Invalid JSON: " + std::string(e.what())}
47+
};
48+
res.set_content(errorJson.dump(), "application/json");
49+
} catch (const std::exception& e) {
50+
res.status = 500;
51+
nlohmann::json errorJson = {
52+
{"message", "Internal Server Error: " + std::string(e.what())}
53+
};
54+
res.set_content(errorJson.dump(), "application/json");
55+
}
56+
});
57+
{{/vendorExtensions}}
58+
59+
{{/operation}}
60+
{{/operations}}
61+
}
62+
63+
} // namespace {{apiNamespace}}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{{#licenseHeader}}
2+
{{{licenseHeader}}}
3+
{{/licenseHeader}}
4+
{{^licenseHeader}}
5+
/*
6+
* Generated by OpenAPI Generator, do not edit.
7+
* https://openapi-generator.tech
8+
*/
9+
{{/licenseHeader}}
10+
11+
#pragma once
12+
{{#models}}
13+
{{#model}}
14+
#include <nlohmann/json.hpp>
15+
16+
{{#vendorExtensions.filteredImports}}
17+
//filtered imports
18+
{{.}}
19+
{{/vendorExtensions.filteredImports}}
20+
21+
22+
{{#vars}}
23+
{{#isPrimitiveType}}
24+
{{#dataType}}
25+
#include <{{#isNumeric}}cstdint{{/isNumeric}}{{#isString}}string{{/isString}}>
26+
{{/dataType}}
27+
{{/isPrimitiveType}}
28+
{{/vars}}
29+
30+
namespace {{vendorExtensions.modelNamespace}} {
31+
32+
class {{vendorExtensions.modelClassName}} {
33+
public:
34+
{{vendorExtensions.modelClassName}}();
35+
virtual ~{{vendorExtensions.modelClassName}}() = default;
36+
37+
// JSON serialization
38+
static nlohmann::json toJson(const {{vendorExtensions.modelClassName}}& obj);
39+
static {{vendorExtensions.modelClassName}} fromJson(const nlohmann::json& json);
40+
41+
// Getters and setters
42+
{{#vars}}
43+
{{vendorExtensions.getterType}} {{vendorExtensions.getter}}() const;
44+
void {{vendorExtensions.setter}}(const {{vendorExtensions.setterType}}& {{nameInCamelCase}});
45+
{{/vars}}
46+
47+
private:
48+
// Member variables
49+
{{#vars}}
50+
{{datatypeWithEnum}} m_{{nameInCamelCase}};
51+
{{/vars}}
52+
};
53+
54+
} // namespace {{vendorExtensions.modelNamespace}}
55+
{{/model}}
56+
{{/models}}

0 commit comments

Comments
 (0)