diff --git a/.github/workflows/samples-cpp-httplib-server.yaml b/.github/workflows/samples-cpp-httplib-server.yaml new file mode 100644 index 000000000000..ec407c343401 --- /dev/null +++ b/.github/workflows/samples-cpp-httplib-server.yaml @@ -0,0 +1,59 @@ +name: Samples cpp httplib server + +on: + push: + paths: + - "samples/server/petstore/cpp-httplib-server/**" + - ".github/workflows/samples-cpp-httplib-server.yaml" + pull_request: + paths: + - "samples/server/petstore/cpp-httplib-server/**" + - ".github/workflows/samples-cpp-httplib-server.yaml" + +env: + GRADLE_VERSION: 6.9 + +jobs: + build: + name: Build cpp httplib server + strategy: + matrix: + sample: + - samples/server/petstore/cpp-httplib-server/petstore + - samples/server/petstore/cpp-httplib-server/feature-test + os: + - ubuntu-latest + - macOS-latest + - windows-latest + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + + - name: Install dependencies (Linux) + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y build-essential libssl-dev zlib1g-dev cmake + + - name: Install dependencies (macOS) + if: matrix.os == 'macOS-latest' + run: | + brew install openssl zlib cmake + + - name: Install dependencies (Windows) + if: matrix.os == 'windows-latest' + run: | + vcpkg install openssl:x64-windows zlib:x64-windows + shell: cmd + timeout-minutes: 20 + + - name: Build + working-directory: ${{ matrix.sample }} + run: | + if [ "${{ matrix.os }}" = "windows-latest" ]; then + cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE="C:/vcpkg/scripts/buildsystems/vcpkg.cmake" + else + cmake -S . -B build + fi + cmake --build build --verbose + shell: bash \ No newline at end of file diff --git a/README.md b/README.md index bcb1f9a157ca..23392062100b 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ OpenAPI Generator allows generation of API client libraries (SDK generation), se | | Languages/Frameworks | | -------------------------------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **API clients** | **ActionScript**, **Ada**, **Apex**, **Bash**, **C**, **C#** (.net 2.0, 3.5 or later, .NET Standard 1.3 - 2.1, .NET Core 3.1, .NET 5.0. Libraries: RestSharp, GenericHost, HttpClient), **C++** (Arduino, cpp-restsdk, Qt5, Tizen, Unreal Engine 4), **Clojure**, **Crystal**, **Dart**, **Elixir**, **Elm**, **Eiffel**, **Erlang**, **Go**, **Groovy**, **Haskell** (http-client, Servant), **Java** (Apache HttpClient 4.x, Apache HttpClient 5.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java, Rest-assured, Spring 5 Web Client, Spring 6 RestClient, MicroProfile Rest Client, Helidon), **Jetbrains HTTP Client**, **Julia**, **k6**, **Kotlin**, **Lua**, **N4JS**, **Nim**, **Node.js/JavaScript** (ES5, ES6, AngularJS with Google Closure Compiler annotations, Flow types, Apollo GraphQL DataStore), **Objective-C**, **OCaml**, **Perl**, **PHP**, **PowerShell**, **Python**, **R**, **Ruby**, **Rust** (hyper, reqwest, rust-server), **Scala** (akka, http4s, scalaz, sttp, swagger-async-httpclient, pekko), **Swift** (2.x, 3.x, 4.x, 5.x, 6.x), **Typescript** (AngularJS, Angular (9.x - 19.x), Aurelia, Axios, Fetch, Inversify, jQuery, Nestjs, Node, redux-query, Rxjs), **XoJo**, **Zapier** | -| **Server stubs** | **Ada**, **C#** (ASP.NET Core, Azure Functions), **C++** (Oat++, Pistache, Restbed, Qt5 QHTTPEngine), **Erlang**, **F#** (Giraffe), **Go** (net/http, Gin, Echo), **Haskell** (Servant, Yesod), **Java** (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, Jersey, RestEasy, Play Framework, [PKMST](https://github.com/ProKarma-Inc/pkmst-getting-started-examples), [Vert.x](https://vertx.io/), [Apache Camel](https://camel.apache.org/), [Helidon](https://helidon.io/)), **Julia**, **Kotlin** (Spring Boot, [Ktor](https://github.com/ktorio/ktor), [Vert.x](https://vertx.io/)), **PHP** ([Flight](https://docs.flightphp.com/), Laravel, Lumen, [Mezzio (fka Zend Expressive)](https://github.com/mezzio/mezzio), Slim, Silex, [Symfony](https://symfony.com/)), **Python** (FastAPI, Flask), **NodeJS**, **Ruby** (Sinatra, Rails5), **Rust** ([rust-server](https://openapi-generator.tech/docs/generators/rust-server/)), **Scala** (Akka, [Finch](https://github.com/finagle/finch), [Lagom](https://github.com/lagom/lagom), [Play](https://www.playframework.com/), [Cask](https://github.com/com-lihaoyi/cask), Scalatra) | +| **Server stubs** | **Ada**, **C#** (ASP.NET Core, Azure Functions), **C++** (Httplib, Oat++, Pistache, Restbed, Qt5 QHTTPEngine), **Erlang**, **F#** (Giraffe), **Go** (net/http, Gin, Echo), **Haskell** (Servant, Yesod), **Java** (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, Jersey, RestEasy, Play Framework, [PKMST](https://github.com/ProKarma-Inc/pkmst-getting-started-examples), [Vert.x](https://vertx.io/), [Apache Camel](https://camel.apache.org/), [Helidon](https://helidon.io/)), **Julia**, **Kotlin** (Spring Boot, [Ktor](https://github.com/ktorio/ktor), [Vert.x](https://vertx.io/)), **PHP** ([Flight](https://docs.flightphp.com/), Laravel, Lumen, [Mezzio (fka Zend Expressive)](https://github.com/mezzio/mezzio), Slim, Silex, [Symfony](https://symfony.com/)), **Python** (FastAPI, Flask), **NodeJS**, **Ruby** (Sinatra, Rails5), **Rust** ([rust-server](https://openapi-generator.tech/docs/generators/rust-server/)), **Scala** (Akka, [Finch](https://github.com/finagle/finch), [Lagom](https://github.com/lagom/lagom), [Play](https://www.playframework.com/), [Cask](https://github.com/com-lihaoyi/cask), Scalatra) | | **API documentation generators** | **HTML**, **Confluence Wiki**, **Asciidoc**, **Markdown**, **PlantUML** | | **Configuration files** | [**Apache2**](https://httpd.apache.org/) | | **Others** | **GraphQL**, **JMeter**, **Ktorm**, **MySQL Schema**, **Postman Collection**, **Protocol Buffer**, **WSDL** | @@ -1025,6 +1025,7 @@ Here is a list of template creators: * Apex: @asnelling * Bash: @bkryza * C: @PowerOfCreation @zhemant [:heart:](https://www.patreon.com/zhemant) + * C++ Httplib: @rajvesh * C++ Oat++: @Kraust * C++ REST: @Danielku15 * C++ Tiny: @AndersSpringborg @kaareHH @michelealbano @mkakbas diff --git a/bin/configs/cpp-httplib-server-feature-test.yaml b/bin/configs/cpp-httplib-server-feature-test.yaml new file mode 100644 index 000000000000..9f5f3e3fec14 --- /dev/null +++ b/bin/configs/cpp-httplib-server-feature-test.yaml @@ -0,0 +1,8 @@ +generatorName: cpp-httplib-server +outputDir: samples/server/petstore/cpp-httplib-server/feature-test +inputSpec: modules/openapi-generator/src/test/resources/3_0/cpp-httplib-server/feature-test.json +templateDir: modules/openapi-generator/src/main/resources/cpp-httplib-server +additionalProperties: + apiNamespace: "api" + modelNamespace: "models" + projectName: "cpp-httplib-server-feature-test" diff --git a/bin/configs/cpp-httplib-server-petstore.yaml b/bin/configs/cpp-httplib-server-petstore.yaml new file mode 100644 index 000000000000..c7f7b9168975 --- /dev/null +++ b/bin/configs/cpp-httplib-server-petstore.yaml @@ -0,0 +1,8 @@ +generatorName: cpp-httplib-server +outputDir: samples/server/petstore/cpp-httplib-server/petstore +inputSpec: modules/openapi-generator/src/test/resources/3_0/cpp-httplib-server/petstore.json +templateDir: modules/openapi-generator/src/main/resources/cpp-httplib-server +additionalProperties: + apiNamespace: "api" + modelNamespace: "models" + projectName: "cpp-httplib-server-petstore" diff --git a/docs/generators.md b/docs/generators.md index bfa97dd22e54..97cc078f8ccc 100644 --- a/docs/generators.md +++ b/docs/generators.md @@ -89,6 +89,7 @@ The following generators are available: * [ada-server](generators/ada-server.md) * [aspnet-fastendpoints](generators/aspnet-fastendpoints.md) * [aspnetcore](generators/aspnetcore.md) +* [cpp-httplib-server](generators/cpp-httplib-server.md) * [cpp-oatpp-server](generators/cpp-oatpp-server.md) * [cpp-pistache-server](generators/cpp-pistache-server.md) * [cpp-qt-qhttpengine-server](generators/cpp-qt-qhttpengine-server.md) diff --git a/docs/generators/README.md b/docs/generators/README.md index d61f00351d5a..8ae6bd7c255d 100644 --- a/docs/generators/README.md +++ b/docs/generators/README.md @@ -65,6 +65,7 @@ The following generators are available: ## SERVER generators * [ada-server](ada-server.md) * [aspnetcore](aspnetcore.md) +* [cpp-httplib-server](cpp-httplib-server.md) * [cpp-oatpp-server](cpp-oatpp-server.md) * [cpp-pistache-server](cpp-pistache-server.md) * [cpp-qt5-qhttpengine-server](cpp-qt5-qhttpengine-server.md) diff --git a/docs/generators/cpp-httplib-server.md b/docs/generators/cpp-httplib-server.md new file mode 100644 index 000000000000..24f4f1ba6e58 --- /dev/null +++ b/docs/generators/cpp-httplib-server.md @@ -0,0 +1,286 @@ +--- +title: Documentation for the cpp-httplib-server Generator +--- + +## METADATA + +| Property | Value | Notes | +| -------- | ----- | ----- | +| generator name | cpp-httplib-server | pass this to the generate command after -g | +| generator stability | STABLE | | +| generator type | SERVER | | +| generator language | C++ | | +| generator default templating engine | mustache | | +| helpTxt | Generates a C++ server using the httplib library. | | + +## CONFIG OPTIONS +These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details. + +| Option | Description | Values | Default | +| ------ | ----------- | ------ | ------- | +|addApiImplStubs|Generate API implementation stubs and a sample main.cpp for quick start| |false| +|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false| +|disallowAdditionalPropertiesIfNotPresent|If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.|
**false**
The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.
**true**
Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.
|true| +|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true| +|enumUnknownDefaultCase|If the server adds new enum cases, that are unknown by an old spec/client, the client will fail to parse the network response.With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the server sends an enum case that is not known by the client/spec, they can safely fallback to this case.|
**false**
No changes to the enum's are made, this is the default option.
**true**
With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the enum case sent by the server is not known by the client/spec, can safely be decoded to this case.
|false| +|legacyDiscriminatorBehavior|Set to false for generators with better support for discriminators. (Python, Java, Go, PowerShell, C# have this enabled by default).|
**true**
The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.
**false**
The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.
|true| +|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false| +|reservedWordPrefix|Prefix to prepend to reserved words in order to avoid conflicts| |r_| +|sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |true| +|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true| +|variableNameFirstCharacterUppercase|Make first character of variable name uppercase (eg. value -> Value)| |true| + +## IMPORT MAPPING + +| Type/Alias | Imports | +| ---------- | ------- | + + +## INSTANTIATION TYPES + +| Type/Alias | Instantiated By | +| ---------- | --------------- | + + +## LANGUAGE PRIMITIVES + + + +## RESERVED WORDS + + + +## FEATURE SET + + +### Client Modification Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|BasePath|✗|ToolingExtension +|Authorizations|✗|ToolingExtension +|UserAgent|✗|ToolingExtension +|MockServer|✗|ToolingExtension + +### Data Type Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|Custom|✗|OAS2,OAS3 +|Int32|✓|OAS2,OAS3 +|Int64|✓|OAS2,OAS3 +|Float|✓|OAS2,OAS3 +|Double|✓|OAS2,OAS3 +|Decimal|✓|ToolingExtension +|String|✓|OAS2,OAS3 +|Byte|✓|OAS2,OAS3 +|Binary|✓|OAS2,OAS3 +|Boolean|✓|OAS2,OAS3 +|Date|✓|OAS2,OAS3 +|DateTime|✓|OAS2,OAS3 +|Password|✓|OAS2,OAS3 +|File|✓|OAS2 +|Uuid|✗| +|Array|✓|OAS2,OAS3 +|Null|✗|OAS3 +|AnyType|✗|OAS2,OAS3 +|Object|✓|OAS2,OAS3 +|Maps|✓|ToolingExtension +|CollectionFormat|✓|OAS2 +|CollectionFormatMulti|✓|OAS2 +|Enum|✓|OAS2,OAS3 +|ArrayOfEnum|✓|ToolingExtension +|ArrayOfModel|✓|ToolingExtension +|ArrayOfCollectionOfPrimitives|✓|ToolingExtension +|ArrayOfCollectionOfModel|✓|ToolingExtension +|ArrayOfCollectionOfEnum|✓|ToolingExtension +|MapOfEnum|✓|ToolingExtension +|MapOfModel|✓|ToolingExtension +|MapOfCollectionOfPrimitives|✓|ToolingExtension +|MapOfCollectionOfModel|✓|ToolingExtension +|MapOfCollectionOfEnum|✓|ToolingExtension + +### Documentation Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|Readme|✓|ToolingExtension +|Model|✓|ToolingExtension +|Api|✓|ToolingExtension + +### Global Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|Host|✓|OAS2,OAS3 +|BasePath|✓|OAS2,OAS3 +|Info|✓|OAS2,OAS3 +|Schemes|✗|OAS2,OAS3 +|PartialSchemes|✓|OAS2,OAS3 +|Consumes|✓|OAS2 +|Produces|✓|OAS2 +|ExternalDocumentation|✓|OAS2,OAS3 +|Examples|✓|OAS2,OAS3 +|XMLStructureDefinitions|✗|OAS2,OAS3 +|MultiServer|✗|OAS3 +|ParameterizedServer|✗|OAS3 +|ParameterStyling|✗|OAS3 +|Callbacks|✗|OAS3 +|LinkObjects|✗|OAS3 + +### Parameter Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|Path|✓|OAS2,OAS3 +|Query|✓|OAS2,OAS3 +|Header|✓|OAS2,OAS3 +|Body|✓|OAS2 +|FormUnencoded|✓|OAS2 +|FormMultipart|✓|OAS2 +|Cookie|✓|OAS3 + +### Schema Support Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|Simple|✓|OAS2,OAS3 +|Composite|✓|OAS2,OAS3 +|Polymorphism|✓|OAS2,OAS3 +|Union|✗|OAS3 +|allOf|✗|OAS2,OAS3 +|anyOf|✗|OAS3 +|oneOf|✗|OAS3 +|not|✗|OAS3 + +### Security Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|BasicAuth|✓|OAS2,OAS3 +|ApiKey|✓|OAS2,OAS3 +|OpenIDConnect|✗|OAS3 +|BearerToken|✓|OAS3 +|OAuth2_Implicit|✗|OAS2,OAS3 +|OAuth2_Password|✗|OAS2,OAS3 +|OAuth2_ClientCredentials|✗|OAS2,OAS3 +|OAuth2_AuthorizationCode|✗|OAS2,OAS3 +|SignatureAuth|✗|OAS3 +|AWSV4Signature|✗|ToolingExtension + +### Wire Format Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|JSON|✓|OAS2,OAS3 +|XML|✗|OAS2,OAS3 +|PROTOBUF|✗|ToolingExtension +|Custom|✗|OAS2,OAS3 diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppHttplibServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppHttplibServerCodegen.java new file mode 100644 index 000000000000..c621a9c8329f --- /dev/null +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppHttplibServerCodegen.java @@ -0,0 +1,2575 @@ +/* + * Copyright 2026 OpenAPI-Generator Contributors (https://openapi-generator.tech) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openapitools.codegen.languages; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenType; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenParameter; +import org.openapitools.codegen.CodegenProperty; +import org.openapitools.codegen.CodegenResponse; +import org.openapitools.codegen.SupportingFile; +import org.openapitools.codegen.meta.features.DocumentationFeature; +import org.openapitools.codegen.meta.features.GlobalFeature; +import org.openapitools.codegen.meta.features.SecurityFeature; +import org.openapitools.codegen.meta.features.WireFormatFeature; +import org.openapitools.codegen.model.ModelMap; +import org.openapitools.codegen.model.ModelsMap; +import org.openapitools.codegen.model.OperationMap; +import org.openapitools.codegen.model.OperationsMap; +import org.openapitools.codegen.utils.CamelizeOption; +import org.openapitools.codegen.utils.ModelUtils; +import org.openapitools.codegen.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.media.MediaType; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.responses.ApiResponse; + +/** + * C++ HTTP Library Server Code Generator. + * This code generator creates C++ server stubs using the httplib library for handling HTTP requests. + * It generates: + * - Model classes with proper C++ typing (std::string, std::vector, std::optional, etc.) + * - API handler interfaces with type-safe request/response handling + * - CMake build configuration + * - JSON serialization/deserialization using nlohmann::json + * Key features: + * - Supports nullable types using std::optional + * - Proper namespace organization for models and APIs + * - Status code to error type mapping for responses + * - Standard C++ container types (vector, map, etc.) + * - Automatic include generation for dependencies + * + * @author OpenAPI Generator Contributors + */ +public class CppHttplibServerCodegen extends AbstractCppCodegen { + private final Logger LOGGER = LoggerFactory.getLogger(CppHttplibServerCodegen.class); + + @Override + public void preprocessOpenAPI(OpenAPI openAPI) { + super.preprocessOpenAPI(openAPI); + + // Check if any security is defined in the spec + boolean hasAnySecurity = (openAPI.getComponents() != null + && openAPI.getComponents().getSecuritySchemes() != null + && !openAPI.getComponents().getSecuritySchemes().isEmpty()); + additionalProperties.put("hasAuthMethods", hasAnySecurity); + + // Process all paths to enhance inline schemas with meaningful titles + if (openAPI.getPaths() != null) { + for (Map.Entry pathEntry : openAPI.getPaths().entrySet()) { + PathItem pathItem = pathEntry.getValue(); + if (pathItem.readOperations() != null) { + for (Operation operation : pathItem.readOperations()) { + String operationId = operation.getOperationId() != null ? operation.getOperationId() : pathEntry.getKey(); + + // Process request body schema + if (operation.getRequestBody() != null && operation.getRequestBody().getContent() != null) { + for (MediaType mediaType : operation.getRequestBody().getContent().values()) { + if (mediaType.getSchema() != null && mediaType.getSchema().getTitle() == null) { + mediaType.getSchema().setTitle(toPascalCase(operationId) + "Request"); + processNestedSchemas(mediaType.getSchema(), toPascalCase(operationId) + "Request"); + } + } + } + + // Process response schemas + if (operation.getResponses() != null) { + for (Map.Entry respEntry : operation.getResponses().entrySet()) { + ApiResponse response = respEntry.getValue(); + if (response.getContent() != null) { + for (MediaType mediaType : response.getContent().values()) { + if (mediaType.getSchema() != null && mediaType.getSchema().getTitle() == null) { + // Format: {OperationId}{StatusCode}Response (e.g., TestHeaderParameters200Response) + String responseTitle = toPascalCase(operationId) + respEntry.getKey() + "Response"; + mediaType.getSchema().setTitle(responseTitle); + processNestedSchemas(mediaType.getSchema(), responseTitle); + } + } + } + } + } + } + } + } + } + } + + public static final String PROJECT_NAME = "projectName"; + private static final String DEFAULT_PROJECT_NAME = "cpp-httplib-server"; + + public static final String MODEL_NAMESPACE = "modelNamespace"; + public static final String API_NAMESPACE = "apiNamespace"; + public static final String ENUM_NAMESPACE = "enumNamespace"; + public static final String MODEL_SUFFIX = "models"; + public static final String API_SUFFIX = "api"; + public static final String ENUM_SUFFIX = "enum"; + public static final String INCLUDE_VARIANT = "#include "; + public static final String INCLUDE_OPTIONAL = "#include "; + public static final String HTTP_RESPONSE_PREFIX = "HTTP_RESPONSE_CODE_"; + public static final String ADD_API_IMPL_STUBS = "addApiImplStubs"; + public static final String ENUM_FROM_STRING = "EnumFromString"; + public static final String ENUM_TO_STRING = "EnumToString"; + public static final String PRIMITIVE_FROM_STRING = "PrimitiveFromString"; + public static final String PRIMITIVE_TO_STRING = "PrimitiveToString"; + + // Standard includes for mapped C++ types + private static final Map standardIncludes = Map.ofEntries( + Map.entry("std::string", "#include "), + Map.entry("std::vector", "#include "), + Map.entry("std::map", "#include "), + Map.entry("std::set", "#include "), + Map.entry("std::list", "#include "), + Map.entry("std::unordered_map", "#include "), + Map.entry("std::unordered_set", "#include "), + Map.entry("std::deque", "#include "), + Map.entry("std::queue", "#include "), + Map.entry("std::stack", "#include "), + Map.entry("std::pair", "#include "), + Map.entry("std::tuple", "#include "), + Map.entry("std::optional", "#include "), + Map.entry("std::any", "#include "), + Map.entry("std::variant", "#include ") + ); + + // Numeric types for include + private static final Set cstdintTypes = Set.of( + "byte", "int", "integer", "long", "short", "unsigned int", "unsigned long", + "unsigned short", "size_t", "ssize_t", "ptrdiff_t", "double", "float", + "boolean", "bool", "char", "wchar_t", "char16_t", "char32_t" + ); + + /** + * Constructor for CppHttplibServerCodegen. + * Initializes the code generator with C++ httplib server specific configurations, + * type mappings, and template files. + */ + public CppHttplibServerCodegen() { + super(); + embeddedTemplateDir = templateDir = "cpp-httplib-server"; + + // Enable inline schema options to prevent schema reuse + // This ensures each operation gets its own uniquely named response model + inlineSchemaOption.put("SKIP_SCHEMA_REUSE", "true"); + + // Map OpenAPI types/formats to C++ types (always use std:: prefix) + typeMapping.put("integer", "int"); + typeMapping.put("long", "long"); + typeMapping.put("float", "float"); + typeMapping.put("double", "double"); + // Default: OpenAPI 'number' → 'double', unless format is 'float' + typeMapping.put("number", "double"); + typeMapping.put("boolean", "bool"); + typeMapping.put("string", "std::string"); + typeMapping.put("byte", "unsigned char"); + typeMapping.put("ByteArray", "std::vector"); + typeMapping.put("binary", "std::string"); + typeMapping.put("date", "std::string"); + typeMapping.put("date-time", "std::string"); + typeMapping.put("password", "std::string"); + typeMapping.put("object", "nlohmann::json"); + typeMapping.put("array", "std::vector"); + typeMapping.put("file", "std::string"); + typeMapping.put("oas_any_type_not_mapped", "nlohmann::json"); + + // Only mapped C++ types as primitives + languageSpecificPrimitives.addAll(Arrays.asList( + "int", "long", "float", "double", "bool", "char", "unsigned int", "unsigned long", "unsigned char", "size_t", "void", + "std::string", "std::vector", "std::map", "std::set", "std::list", "std::unordered_map", "std::unordered_set", "std::deque", "std::queue", "std::stack", "std::pair", "std::tuple", "std::optional", "std::any", "std::variant" + )); + + // Configure template files for code generation + modelTemplateFiles.put("model-header.mustache", ".h"); + modelTemplateFiles.put("model-source.mustache", ".cpp"); + apiTemplateFiles.put("api-header.mustache", ".h"); + apiTemplateFiles.put("api-source.mustache", ".cpp"); + + // Add CLI options + cliOptions.add(org.openapitools.codegen.CliOption.newBoolean(ADD_API_IMPL_STUBS, + "Generate API implementation stubs and a sample main.cpp for quick start").defaultValue("false")); + + // Add supporting files for project structure + supportingFiles.add(new SupportingFile("CMakeLists.txt.mustache", "", "CMakeLists.txt")); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("License.mustache", "", "LICENSE")); + + // Initialize feature set for httplib server + // Note: Polymorphism is partially supported: + // ✅ allOf (inheritance/composition) + // ✅ anyOf/oneOf (std::variant) + // ❌ discriminator (not implemented) + modifyFeatureSet(features -> features + .includeDocumentationFeatures(DocumentationFeature.Readme) + .wireFormatFeatures(EnumSet.of(WireFormatFeature.JSON)) + .securityFeatures(EnumSet.of( + SecurityFeature.ApiKey, + SecurityFeature.BasicAuth, + SecurityFeature.BearerToken + )) + .excludeGlobalFeatures( + GlobalFeature.XMLStructureDefinitions, + GlobalFeature.Callbacks, + GlobalFeature.LinkObjects + ) + ); + + } + + @Override + public CodegenType getTag() { + return CodegenType.SERVER; + } + + /** + * Returns the name identifier for this code generator. + * + * @return the generator name + */ + @Override + public String getName() { + return DEFAULT_PROJECT_NAME; + } + + /** + * Returns a brief description of what this code generator does. + * + * @return help text describing the generator's purpose + */ + @Override + public String getHelp() { + return "Generates a C++ server using the httplib library."; + } + + /** + * Converts a model name to its corresponding import statement. + * Handles both standard C++ types and custom model types. + * + * @param name the model name to import + * @return the appropriate #include directive or empty string + */ + @Override + public String toModelImport(String name) { + // Skip if already formatted as an include + String includeFile; + if (name.startsWith("#include")) { + includeFile = null; + } + // Use import mapping if available + if (importMapping.containsKey(name)) { + includeFile = importMapping.get(name); + } + // Map OpenAPI type to C++ type if possible + String mappedType = typeMapping.getOrDefault(name, name); + if (languageSpecificPrimitives.contains(mappedType)) { + String include = getStandardIncludeForType(mappedType); + includeFile = include != null ? include : ""; + } else { + Map pathFromClassName = stripPathFromClassName(mappedType); + includeFile = "#include \"" + pathFromClassName.get("className") + ".h\""; + } + return includeFile; + } + + /** + * Returns the appropriate #include directive for a given C++ standard type. + * + * @param typeName the C++ type name + * @return the include directive or null if no include is needed + */ + private String getStandardIncludeForType(String typeName) { + String mappedType = typeMapping.getOrDefault(typeName, typeName); + if (standardIncludes.containsKey(mappedType)) { + return standardIncludes.get(mappedType); + } + if (cstdintTypes.contains(typeName)) { + return "#include "; + } + else if (cstdintTypes.contains(mappedType)) { + return "#include "; + } + return null; + } + + /** + * Post-processes operations after model processing to add C++ specific configurations. + * This method: + * - Sets up class names and namespaces for API classes + * - Processes request and response models for each operation + * - Maps response status codes to their corresponding types + * - Collects all used models for proper include generation + * + * @param objs the operations map to process + * @param allModels list of all models in the API + * @return the processed operations map + */ + + @Override + public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List allModels) { + + // No allParams logic; only expose requestModel, queryParams, headerParams as vendorExtensions + if (objs == null || objs.getOperations() == null) { + LOGGER.warn("Operations or operations map is null"); + return objs; + } + OperationMap operations = objs.getOperations(); + List operationList = operations.getOperation(); + // Per-operation unique status code constants + // Set classname and compute apiNamespace ONCE per API class + String classname = operations.getClassname(); + if ("DefaultApi".equals(classname) || classname == null || classname.isEmpty()) { + classname = addProjectOrDefaultName(classname, "DefaultApi"); + operations.setClassname(classname); + } + objs.put("apiHeaderFileName", toPascalCase(classname) + toPascalCase(API_SUFFIX) + ".h"); + objs.put("apiClassnameInPascalCase", toPascalCase(classname)); + + // Compute API namespace ONCE, append classname only if not already present as last segment + String apiNamespace = (String) additionalProperties.get(API_NAMESPACE); + if (apiNamespace == null || apiNamespace.isEmpty()) { + apiNamespace = API_SUFFIX.toLowerCase(Locale.ROOT); + } + + objs.put("apiNamespace", apiNamespace); + + // Build a lookup map: PascalCase className -> modelNamespace + Map modelNamespaceMap = new HashMap<>(); + for (ModelMap modelMap : allModels) { + CodegenModel model = modelMap.getModel(); + if (model != null && model.vendorExtensions.containsKey("modelNamespace")) { + modelNamespaceMap.put(model.classname, (String) model.vendorExtensions.get("modelNamespace")); + } + } + + // Track all models used for includes + Set modelsUsed = new HashSet<>(); + List> opStatusCodeConsts = new ArrayList<>(); + boolean includeOptionalHeader = false; + for (CodegenOperation op : operationList) { + boolean hasPrimitiveParams = false; + Set seenSuccessTypes = new HashSet<>(); + if (op.vendorExtensions == null) { + op.vendorExtensions = new HashMap<>(); + } + // Add modelNamespace to vendorExtensions + String modelNamespace = (String) additionalProperties.get(MODEL_NAMESPACE); + final String apiNamespacetoFilter = apiNamespace; + //Filter common words in api and model namespaces + String namespaceFiltered = Arrays.stream(modelNamespace.toLowerCase(Locale.ROOT).split("::")) + .filter(word -> !Arrays.asList(apiNamespacetoFilter.toLowerCase(Locale.ROOT).split("::")).contains(word)) + .collect(Collectors.joining("::")); + // Handle request model + if (op.bodyParam != null && op.bodyParam.baseType != null) { + String className = op.bodyParam.baseType; + String requestModel = toPascalCase(className); + op.vendorExtensions.put("requestModel", requestModel); + + // Set bodyParam dataType with namespace prefix + if(!namespaceFiltered.isEmpty()) { + op.vendorExtensions.put("requestModelNamespace", namespaceFiltered); + op.bodyParam.dataType = namespaceFiltered + "::" + requestModel; + } else { + op.bodyParam.dataType = requestModel; + } + + // Wrap in std::optional if not required + if (!op.bodyParam.required) { + op.bodyParam.dataType = "std::optional<" + op.bodyParam.dataType + ">"; + } + + includeOptionalHeader = true; + modelsUsed.add(requestModel); + } + // Add type flags for query and header params for template type conversion + if (op.queryParams != null) { + for (CodegenParameter qp : op.queryParams) { +// setCppTypeFlags(qp); + if (!hasPrimitiveParams && Boolean.TRUE.equals(qp.vendorExtensions.get("isPrimitive"))) { + hasPrimitiveParams = true; + } + } + } + if (op.headerParams != null) { + for (CodegenParameter hp : op.headerParams) { +// setCppTypeFlags(hp); + if (!hasPrimitiveParams && Boolean.TRUE.equals(hp.vendorExtensions.get("isPrimitive"))) { + hasPrimitiveParams = true; + } + } + } + op.vendorExtensions.put("hasPrimitiveParams", hasPrimitiveParams); + op.vendorExtensions.put("operationIdPascalCase", toHandlerFunctionName(op.httpMethod, op.path.toString(),false)); + op.vendorExtensions.put("httpMethod", op.httpMethod != null ? toPascalCase(op.httpMethod) : ""); + op.vendorExtensions.put("handlerFunctionName", toHandlerFunctionName(op.httpMethod, op.path.toString(),true)); + op.vendorExtensions.put("requestType", toHandlerFunctionRequest(op.path.toString(),op.httpMethod)); + op.vendorExtensions.put("responseType", toHandlerFunctionResponse(op.path.toString(),op.httpMethod)); + if (op.path != null) { + op.vendorExtensions.put("path", op.path); + } + + // Expose query, header, path, and cookie parameters for mustache + if (op.queryParams == null) op.queryParams = new ArrayList<>(); + if (op.headerParams == null) op.headerParams = new ArrayList<>(); + if (op.pathParams == null) op.pathParams = new ArrayList<>(); + if (op.cookieParams == null) op.cookieParams = new ArrayList<>(); + + // Track path parameter indices for regex matching in C++ + int pathParamIndex = 1; // Start at 1 for regex match groups + + // Add style/explode/allowReserved to each param + for (CodegenParameter param : op.queryParams) { + param.vendorExtensions.put("style", param.style); + param.vendorExtensions.put("explode", param.isExplode); + // Set parameter type flags + setParameterTypeFlags(param); + + // Track models used in parameters (for includes and namespace prefix) + if (param.baseType != null && !param.isPrimitiveType && !languageSpecificPrimitives.contains(param.baseType)) { + String className = toPascalCase(param.baseType); + modelsUsed.add(className); + // Add namespace prefix to parameter dataType if it's a model and doesn't already have namespace + // Extract inner type from containers like std::optional and std::vector + String innerType = param.dataType; + if (param.dataType.contains("<")) { + int startIdx = param.dataType.indexOf('<') + 1; + int endIdx = param.dataType.lastIndexOf('>'); + if (startIdx > 0 && endIdx > startIdx) { + innerType = param.dataType.substring(startIdx, endIdx).trim(); + } + } + if (!innerType.contains("::") && !languageSpecificPrimitives.contains(innerType)) { + String prefixedType = namespaceFiltered + "::" + innerType; + param.dataType = param.dataType.replace(innerType, prefixedType); + } + } else if (param.dataType != null && param.dataType.contains("<")) { + // Additional handling: extract model from dataType when baseType might not be set + // This handles cases like std::optional where baseType might be incorrectly set + String innerType = param.dataType; + int startIdx = param.dataType.indexOf('<') + 1; + int endIdx = param.dataType.lastIndexOf('>'); + if (startIdx > 0 && endIdx > startIdx) { + innerType = param.dataType.substring(startIdx, endIdx).trim(); + // Check if this looks like a model class (PascalCase) + if (!languageSpecificPrimitives.contains(innerType) && + !innerType.startsWith("std::") && + !innerType.contains("::") && + innerType.length() > 0 && + Character.isUpperCase(innerType.charAt(0))) { + modelsUsed.add(innerType); + // Add namespace prefix + String prefixedType = namespaceFiltered + "::" + innerType; + param.dataType = param.dataType.replace(innerType, prefixedType); + } + } + } + + // Extract unwrapped type for JSON deserialization AFTER namespace has been added + // For std::optional, we need T for the .get() call + String unwrappedType = param.dataType; + if (param.dataType != null && param.dataType.contains("<")) { + int startIdx = param.dataType.indexOf('<') + 1; + int endIdx = param.dataType.lastIndexOf('>'); + if (startIdx > 0 && endIdx > startIdx) { + unwrappedType = param.dataType.substring(startIdx, endIdx).trim(); + } + } + param.vendorExtensions.put("unwrappedDataType", unwrappedType); + } + for (CodegenParameter param : op.headerParams) { + param.vendorExtensions.put("style", param.style); + param.vendorExtensions.put("explode", param.isExplode); + setParameterTypeFlags(param); + // Track models used in parameters + if (param.baseType != null && !param.isPrimitiveType && !languageSpecificPrimitives.contains(param.baseType)) { + String className = toPascalCase(param.baseType); + modelsUsed.add(className); + // Extract inner type from containers + String innerType = param.dataType; + if (param.dataType.contains("<")) { + int startIdx = param.dataType.indexOf('<') + 1; + int endIdx = param.dataType.lastIndexOf('>'); + if (startIdx > 0 && endIdx > startIdx) { + innerType = param.dataType.substring(startIdx, endIdx).trim(); + } + } + if (!innerType.contains("::") && !languageSpecificPrimitives.contains(innerType)) { + String prefixedType = namespaceFiltered + "::" + innerType; + param.dataType = param.dataType.replace(innerType, prefixedType); + } + } + } + for (CodegenParameter param : op.pathParams) { + param.vendorExtensions.put("style", param.style); + param.vendorExtensions.put("explode", param.isExplode); + param.vendorExtensions.put("pathIndex", pathParamIndex); + pathParamIndex++; + setParameterTypeFlags(param); + // Track models used in parameters + if (param.baseType != null && !param.isPrimitiveType && !languageSpecificPrimitives.contains(param.baseType)) { + String className = toPascalCase(param.baseType); + modelsUsed.add(className); + // Extract inner type from containers + String innerType = param.dataType; + if (param.dataType.contains("<")) { + int startIdx = param.dataType.indexOf('<') + 1; + int endIdx = param.dataType.lastIndexOf('>'); + if (startIdx > 0 && endIdx > startIdx) { + innerType = param.dataType.substring(startIdx, endIdx).trim(); + } + } + if (!innerType.contains("::") && !languageSpecificPrimitives.contains(innerType)) { + String prefixedType = namespaceFiltered + "::" + innerType; + param.dataType = param.dataType.replace(innerType, prefixedType); + } + } + } + for (CodegenParameter param : op.cookieParams) { + param.vendorExtensions.put("style", param.style); + param.vendorExtensions.put("explode", param.isExplode); + setParameterTypeFlags(param); + // Track models used in parameters + if (param.baseType != null && !param.isPrimitiveType && !languageSpecificPrimitives.contains(param.baseType)) { + String className = toPascalCase(param.baseType); + modelsUsed.add(className); + // Extract inner type from containers + String innerType = param.dataType; + if (param.dataType.contains("<")) { + int startIdx = param.dataType.indexOf('<') + 1; + int endIdx = param.dataType.lastIndexOf('>'); + if (startIdx > 0 && endIdx > startIdx) { + innerType = param.dataType.substring(startIdx, endIdx).trim(); + } + } + if (!innerType.contains("::") && !languageSpecificPrimitives.contains(innerType)) { + String prefixedType = namespaceFiltered + "::" + innerType; + param.dataType = param.dataType.replace(innerType, prefixedType); + } + } + } + op.vendorExtensions.put("queryParams", op.queryParams); + op.vendorExtensions.put("headerParams", op.headerParams); + op.vendorExtensions.put("pathParams", op.pathParams); + op.vendorExtensions.put("cookieParams", op.cookieParams); + + // Process security requirements + processSecurityRequirements(op); + + // Process responses + List errorTypes = new ArrayList<>(); + Set successTypesSet = new LinkedHashSet<>(); + Set allResponseTypesSet = new LinkedHashSet<>(); + List> successCodeToTypes = new ArrayList<>(); + List> errorCodeToTypes = new ArrayList<>(); + boolean isSuccessResponseType = false; + boolean isSuccessResponsePrimitive = false; + boolean isErrorResponsePrimitive = false; + boolean hasVoidResponse = false; + + for (CodegenResponse resp : op.responses) { + boolean hasAnyResponseSchema = false; + + if (resp.code != null) { + // Check if response has no schema (void response) + if (resp.baseType == null || resp.baseType.isEmpty()) { + hasVoidResponse = true; + continue; + } + + // Collect all 2xx response types as successTypes + if (resp.code.startsWith("2") && resp.baseType != null) { + hasAnyResponseSchema = true; + String successType; + String successConstName; + if (!typeMapping.containsKey(resp.baseType)) { + String className = toPascalCase(resp.baseType); + successType = namespaceFiltered + "::" + className; + modelsUsed.add(className); + successConstName = HTTP_RESPONSE_PREFIX + StringUtils.underscore(className).toUpperCase(Locale.ROOT); + } else { + successType = typeMapping.get(resp.baseType); + successConstName = HTTP_RESPONSE_PREFIX + "PRIMITIVE_"+StringUtils.underscore(resp.baseType).toUpperCase(Locale.ROOT); + isSuccessResponsePrimitive = true; + } + // Only add if not already in set (deduplication across all responses) + successTypesSet.add(successType); + if (allResponseTypesSet.add(successType)) { + if(successConstName != null && !successConstName.isEmpty() && successType!= null && !successType.isEmpty()) { + final String finalSuccessConstName = successConstName; + boolean successConstExists = opStatusCodeConsts.stream() + .anyMatch(listitem -> finalSuccessConstName.equals(listitem.get("constName"))); + if (!successConstExists) { + Map item = new HashMap<>(); + item.put("constName", successConstName); + item.put("statusCode", resp.code); + opStatusCodeConsts.add(item); + } + Map successItem = new HashMap<>(); + successItem.put("successType", successType); + successItem.put("successConstName", successConstName); + successCodeToTypes.add(successItem); + } + } + } else { + String errorBaseType = resp.baseType; + String errorConstName = ""; + if (errorBaseType != null && !errorBaseType.isEmpty()) { + hasAnyResponseSchema = true; + String errorType = ""; + if (!typeMapping.containsKey(errorBaseType)) { + String className = toPascalCase(errorBaseType); + errorType = namespaceFiltered + "::" + className; + modelsUsed.add(className); + errorConstName = HTTP_RESPONSE_PREFIX + StringUtils.underscore(className).toUpperCase(Locale.ROOT); + // errorTypeIsEnum = Boolean.TRUE.equals(classNameIsEnumMap.get(toPascalCase(className))); + } else { + isErrorResponsePrimitive = true; + errorType = typeMapping.get(resp.baseType); + errorConstName = HTTP_RESPONSE_PREFIX + "PRIMITIVE_" + StringUtils.underscore(resp.baseType).toUpperCase(Locale.ROOT); + } + + if(errorConstName != null && !errorConstName.isEmpty()) { + errorTypes.add(errorType); + op.vendorExtensions.put("errorTypes", errorTypes); + // Only add to errorCodeToTypes if not already used in any response + if (allResponseTypesSet.add(errorType)) { + final String finalErrorConstName = errorConstName; + boolean errorConstExists = opStatusCodeConsts.stream() + .anyMatch(listitem -> finalErrorConstName.equals(listitem.get("constName"))); + if (!errorConstName.isEmpty() && !errorConstExists) { + Map item = new HashMap<>(); + item.put("constName", errorConstName); + item.put("statusCode", resp.code); + opStatusCodeConsts.add(item); + } + Map errorItem = new HashMap<>(); + errorItem.put("errorType", errorType); + errorItem.put("errorConstName", errorConstName); + // errorItem.put("errorTypeIsEnum", errorTypeIsEnum); + errorCodeToTypes.add(errorItem); + } + } + } + } + if (hasAnyResponseSchema) { + op.vendorExtensions.put("hasAnyResponseSchema", true); + } + } + } + + op.vendorExtensions.put("hasVoidResponse", hasVoidResponse); + op.vendorExtensions.put("isSuccessResponseType", isSuccessResponseType); + op.vendorExtensions.put("isSuccessResponsePrimitive", isSuccessResponsePrimitive); + op.vendorExtensions.put("isErrorResponsePrimitive", isErrorResponsePrimitive); + + // Convert Set to List for template + if (!successTypesSet.isEmpty()) { + op.vendorExtensions.put("successTypes", new ArrayList<>(successTypesSet)); + } + if (successCodeToTypes != null && !successCodeToTypes.isEmpty()) { + op.vendorExtensions.put("successCodeToTypes", successCodeToTypes); + } + if (errorCodeToTypes != null && !errorCodeToTypes.isEmpty()) { + op.vendorExtensions.put("errorCodeToTypes", errorCodeToTypes); + } + + // Check if we have only one response type (to avoid unnecessary std::variant) + int totalResponseTypes = successCodeToTypes.size() + errorCodeToTypes.size(); + if (totalResponseTypes == 1) { + op.vendorExtensions.put("hasSingleResponseType", true); + // Store the single response type + if (!successCodeToTypes.isEmpty()) { + op.vendorExtensions.put("singleResponseType", successCodeToTypes.get(0).get("successType")); + } else if (!errorCodeToTypes.isEmpty()) { + op.vendorExtensions.put("singleResponseType", errorCodeToTypes.get(0).get("errorType")); + } + } else { + op.vendorExtensions.put("hasSingleResponseType", false); + } + + boolean hasRequestSchema = (op.queryParams != null && !op.queryParams.isEmpty()) || + (op.headerParams != null && !op.headerParams.isEmpty()) || + (op.cookieParams != null && !op.cookieParams.isEmpty()) || + (op.pathParams != null && !op.pathParams.isEmpty()) || + (op.bodyParams != null && !op.bodyParams.isEmpty()); + op.vendorExtensions.put("hasAnyRequestSchema", hasRequestSchema); + + // Check if operation has any array parameters (for sstream include) + boolean hasArrayParams = false; + for (CodegenParameter param : op.allParams) { + if (param.isArray) { + hasArrayParams = true; + break; + } + } + op.vendorExtensions.put("hasArrayParams", hasArrayParams); + } + + // Aggregate security settings from all operations in this API + // Also check if ANY operation actually uses auth (hasAuth flag) + boolean hasApiKeyAuth = false; + boolean hasBearerAuth = false; + boolean hasBasicAuth = false; + boolean hasOAuth2 = false; + boolean anyOperationUsesAuth = false; + List> apiKeyAuthList = new ArrayList<>(); + List> bearerAuthList = new ArrayList<>(); + List> basicAuthList = new ArrayList<>(); + List> oauth2AuthList = new ArrayList<>(); + Set seenApiKeys = new HashSet<>(); + Set seenBearers = new HashSet<>(); + Set seenBasics = new HashSet<>(); + Set seenOAuth2s = new HashSet<>(); + + for (CodegenOperation op : operationList) { + // Check if this operation uses auth + if (Boolean.TRUE.equals(op.vendorExtensions.get("hasAuth"))) { + anyOperationUsesAuth = true; + } + + if (Boolean.TRUE.equals(op.vendorExtensions.get("hasApiKeyAuth"))) { + hasApiKeyAuth = true; + @SuppressWarnings("unchecked") + List> opApiKeys = (List>) op.vendorExtensions.get("apiKeyAuth"); + if (opApiKeys != null) { + for (Map auth : opApiKeys) { + String name = (String) auth.get("name"); + if (name != null && seenApiKeys.add(name)) { + apiKeyAuthList.add(auth); + } + } + } + } + if (Boolean.TRUE.equals(op.vendorExtensions.get("hasBearerAuth"))) { + hasBearerAuth = true; + @SuppressWarnings("unchecked") + List> opBearers = (List>) op.vendorExtensions.get("bearerAuth"); + if (opBearers != null) { + for (Map auth : opBearers) { + String name = (String) auth.get("name"); + if (name != null && seenBearers.add(name)) { + bearerAuthList.add(auth); + } + } + } + } + if (Boolean.TRUE.equals(op.vendorExtensions.get("hasBasicAuth"))) { + hasBasicAuth = true; + @SuppressWarnings("unchecked") + List> opBasics = (List>) op.vendorExtensions.get("basicAuth"); + if (opBasics != null) { + for (Map auth : opBasics) { + String name = (String) auth.get("name"); + if (name != null && seenBasics.add(name)) { + basicAuthList.add(auth); + } + } + } + } + if (Boolean.TRUE.equals(op.vendorExtensions.get("hasOAuth2"))) { + hasOAuth2 = true; + @SuppressWarnings("unchecked") + List> opOAuth2s = (List>) op.vendorExtensions.get("oauth2Auth"); + if (opOAuth2s != null) { + for (Map auth : opOAuth2s) { + String name = (String) auth.get("name"); + if (name != null && seenOAuth2s.add(name)) { + oauth2AuthList.add(auth); + } + } + } + } + } + + // Add aggregated security settings to objs for the API class + // Only add them if at least one operation actually uses authentication + boolean hasAnyAuth = false; + if (anyOperationUsesAuth) { + hasAnyAuth = true; + if (hasApiKeyAuth) { + objs.put("hasApiKeyAuth", true); + objs.put("apiKeyAuth", apiKeyAuthList); + } + if (hasBearerAuth) { + objs.put("hasBearerAuth", true); + objs.put("bearerAuth", bearerAuthList); + } + if (hasBasicAuth) { + objs.put("hasBasicAuth", true); + objs.put("basicAuth", basicAuthList); + } + if (hasOAuth2) { + objs.put("hasOAuth2", true); + objs.put("oauth2Auth", oauth2AuthList); + } + } + // Only set hasAnyAuth if at least one operation actually uses auth + if (hasAnyAuth) { + objs.put("hasAnyAuth", true); + } + + Object objApiStubs = additionalProperties.get(ADD_API_IMPL_STUBS); + boolean addApiImplStubs = false; + if(objApiStubs instanceof Boolean) { + addApiImplStubs = (Boolean) objApiStubs; + } + if(objApiStubs instanceof String) { + addApiImplStubs = Boolean.parseBoolean((String) objApiStubs); + } + LOGGER.debug("Generating Api stubs in the source file:{}.",addApiImplStubs); + if(addApiImplStubs == true) { + objs.put("addApiImplStubs", true); + } + + // Create a map from status code to constant name for easy lookup in templates + Map statusCodeToConstMap = new HashMap<>(); + for (Map item : opStatusCodeConsts) { + String code = item.get("statusCode"); + String constName = item.get("constName"); + // Store the first constant found for each code (prefer spec-defined ones) + if (!statusCodeToConstMap.containsKey(code)) { + statusCodeToConstMap.put(code, constName); + } + } + + // Determine which common status codes are actually needed + boolean needsNoContent = false; // 204 - used for void responses + boolean needsBadRequest = false; // 400 - used for parameter validation + boolean needsUnauthorized = false; // 401 - used for authentication failures + boolean needsInternalError = false; // 500 - used for JSON parsing errors and response handler fallback + + for (CodegenOperation op : operationList) { + // 204 NO_CONTENT: needed if any operation has void response + if (Boolean.TRUE.equals(op.vendorExtensions.get("hasVoidResponse"))) { + needsNoContent = true; + } + // 400 BAD_REQUEST: needed if any operation has request parameters or request body + if (Boolean.TRUE.equals(op.vendorExtensions.get("hasAnyRequestSchema"))) { + needsBadRequest = true; + } + // 401 UNAUTHORIZED: needed if any operation has authentication + if (Boolean.TRUE.equals(op.vendorExtensions.get("hasAuth"))) { + needsUnauthorized = true; + } + // 500 INTERNAL_SERVER_ERROR: needed if any operation has request body (for JSON parsing errors) + // or if any operation has response schema (for response handler fallback) + if (op.vendorExtensions.get("requestModel") != null || + Boolean.TRUE.equals(op.vendorExtensions.get("hasAnyResponseSchema"))) { + needsInternalError = true; + } + } + + // Only add common status codes if they're actually needed + if (needsNoContent && !statusCodeToConstMap.containsKey("204")) { + String constName = HTTP_RESPONSE_PREFIX + "NO_CONTENT"; + statusCodeToConstMap.put("204", constName); + Map item = new HashMap<>(); + item.put("constName", constName); + item.put("statusCode", "204"); + opStatusCodeConsts.add(item); + } + + if (needsBadRequest && !statusCodeToConstMap.containsKey("400")) { + String constName = HTTP_RESPONSE_PREFIX + "BAD_REQUEST"; + statusCodeToConstMap.put("400", constName); + Map item = new HashMap<>(); + item.put("constName", constName); + item.put("statusCode", "400"); + opStatusCodeConsts.add(item); + } + + if (needsUnauthorized && !statusCodeToConstMap.containsKey("401")) { + String constName = HTTP_RESPONSE_PREFIX + "UNAUTHORIZED"; + statusCodeToConstMap.put("401", constName); + Map item = new HashMap<>(); + item.put("constName", constName); + item.put("statusCode", "401"); + opStatusCodeConsts.add(item); + } + + if (needsInternalError && !statusCodeToConstMap.containsKey("500")) { + String constName = HTTP_RESPONSE_PREFIX + "INTERNAL_SERVER_ERROR"; + statusCodeToConstMap.put("500", constName); + Map item = new HashMap<>(); + item.put("constName", constName); + item.put("statusCode", "500"); + opStatusCodeConsts.add(item); + } + + // Pass the map to templates + objs.put("statusCodeToConst", statusCodeToConstMap); + + if (!opStatusCodeConsts.isEmpty()) { + objs.put("statusCodeConsts", opStatusCodeConsts); + } + // Add modelsUsed to objs for header includes + if(modelsUsed != null && !modelsUsed.isEmpty()) { + ArrayList sortedModels = new ArrayList<>(modelsUsed); + Collections.sort(sortedModels); + objs.put("modelsUsed", new ArrayList<>(sortedModels)); + objs.put("includeVariantHeader", INCLUDE_VARIANT); + } + if(includeOptionalHeader) { + objs.put("includeOptionalHeader", INCLUDE_OPTIONAL); + } + return objs; + } + + /** + * Preprocesses the OpenAPI specification to enhance inline schemas with proper titles. + * This method ensures that request and response schemas without explicit titles + * get automatically generated names based on the operation ID. + * + * @param openAPI the OpenAPI specification to preprocess + */ + + /** + * Recursively processes nested schemas within a parent schema to set meaningful titles. + * This handles cases like component responses that have nested inline object schemas. + * + * @param schema the parent schema to process + * @param parentName the name of the parent (used for generating child names) + */ + @SuppressWarnings("rawtypes") + private void processNestedSchemas(Schema schema, String parentName) { + processNestedSchemas(schema, parentName, 0); + } + + private void processNestedSchemas(Schema schema, String parentName, int depth) { + if (schema == null || depth > 10) { + return; + } + + // Process properties of object schemas + if (schema.getProperties() != null) { + for (Map.Entry propEntry : ((Map) schema.getProperties()).entrySet()) { + Schema propSchema = propEntry.getValue(); + String propertyName = propEntry.getKey(); + + // Set title for nested inline schemas + if (propSchema.getTitle() == null && propSchema.get$ref() == null) { + // For nested objects, create a meaningful name + if ("object".equals(propSchema.getType()) || (propSchema.getType() == null && propSchema.getProperties() != null)) { + String title = toPascalCase(parentName + "_" + propertyName); + propSchema.setTitle(title); + + // Recursively process nested properties + processNestedSchemas(propSchema, title, depth + 1); + } + } + } + } + + // Process array items + if (schema.getItems() != null) { + Schema itemSchema = schema.getItems(); + if (itemSchema.getTitle() == null && itemSchema.get$ref() == null) { + if ("object".equals(itemSchema.getType()) || (itemSchema.getType() == null && itemSchema.getProperties() != null)) { + String title = toPascalCase(parentName + "_item"); + itemSchema.setTitle(title); + processNestedSchemas(itemSchema, title, depth + 1); + } + } + } + + // Process additionalProperties + if (schema.getAdditionalProperties() instanceof Schema) { + Schema additionalSchema = (Schema) schema.getAdditionalProperties(); + if (additionalSchema.getTitle() == null && additionalSchema.get$ref() == null) { + if ("object".equals(additionalSchema.getType()) || (additionalSchema.getType() == null && additionalSchema.getProperties() != null)) { + String title = toPascalCase(parentName + "_additional"); + additionalSchema.setTitle(title); + processNestedSchemas(additionalSchema, title, depth + 1); + } + } + } + } + + /** + * Post-processes all models to add C++ specific configurations and namespace handling. + * This method: + * - Computes model namespaces based on class names + * - Filters imports to exclude primitives and standard types + * - Processes model variables for proper C++ typing + * - Sets up proper getter/setter configurations + * + * @param objs map of all models to process + * @return the processed models map + */ + @Override + public Map postProcessAllModels(Map objs) { + + Map processed = super.postProcessAllModels(objs); + + // Compute modelNamespace ONCE and append className + String modelNamespaceBase = (String) additionalProperties.get(MODEL_NAMESPACE); + if (modelNamespaceBase == null || modelNamespaceBase.isEmpty()) { + modelNamespaceBase = MODEL_SUFFIX.toLowerCase(Locale.ROOT); + additionalProperties.put(MODEL_NAMESPACE, modelNamespaceBase); + } + + for (Map.Entry entry : processed.entrySet()) { + ModelsMap modelsMap = entry.getValue(); + + for (ModelMap modelMap : modelsMap.getModels()) { + CodegenModel model = modelMap.getModel(); + if (model != null) { + String modelClassName = model.classname; + // Convert model classname to proper PascalCase + String fixedClassName = toPascalCase(modelClassName); + LOGGER.debug("Model classname: {} -> {}", modelClassName, fixedClassName); + model.classname = fixedClassName; + // Set in vendorExtensions for backward compatibility + model.vendorExtensions.put("modelNamespace", modelNamespaceBase); + model.vendorExtensions.put("modelClassName", model.classname); + + // --- Filter and set imports for mustache --- + Set systemHeaders = new LinkedHashSet<>(); + Set projectHeaders = new LinkedHashSet<>(); + + if (model.imports != null) { + for (String imp : model.imports) { + // Only add if not a primitive, not a mapped type, and not "object", "nlohmann::json", or "Map" + if (!languageSpecificPrimitives.contains(imp) + && !typeMapping.containsKey(imp) + && !"object".equals(imp) + && !"nlohmann::json".equals(imp) + && !"Map".equals(imp)) { + + String headerName = toPascalCase(imp); + projectHeaders.add("#include \"" + headerName + ".h\""); + } + else { + String standardInclude = getStandardIncludeForType(imp); + if (standardInclude != null) { + systemHeaders.add(standardInclude); + } + } + } + } + + // Combine system headers first, then project headers (both sorted) + List filteredImports = new ArrayList<>(); + List sortedSystemHeaders = new ArrayList<>(systemHeaders); + Collections.sort(sortedSystemHeaders); + filteredImports.addAll(sortedSystemHeaders); + + List sortedProjectHeaders = new ArrayList<>(projectHeaders); + Collections.sort(sortedProjectHeaders); + filteredImports.addAll(sortedProjectHeaders); + + // Set the imports for mustache template + model.vendorExtensions.put("filteredImports", filteredImports); + // --- End filter and set imports --- + + if (model.allVars != null) { + for (CodegenProperty var : model.allVars) { + processModelVariable(var, model); + } + } + if (model.vars != null) { + for (CodegenProperty var : model.vars) { + processModelVariable(var, model); + } + } + // Ensure vars is populated from allVars for template access + if ((model.vars == null || model.vars.isEmpty()) && model.allVars != null && !model.allVars.isEmpty()) { + model.vars = new ArrayList<>(model.allVars); + } + + // After processing variables, check if any use optional or variant + // (processModelVariable may wrap types in std::optional) + boolean hasOptional = false; + boolean needsVariant = Boolean.TRUE.equals(model.vendorExtensions.get("hasVariant")); + + List allProperties = new ArrayList<>(); + if (model.vars != null) allProperties.addAll(model.vars); + if (model.allVars != null) { + for (CodegenProperty v : model.allVars) { + if (!allProperties.contains(v)) allProperties.add(v); + } + } + + for (CodegenProperty var : allProperties) { + if (var.dataType != null) { + if (!hasOptional && var.dataType.contains("std::optional<")) { + hasOptional = true; + } + if (!needsVariant && var.dataType.contains("std::variant<")) { + needsVariant = true; + } + } + } + + // Update filtered imports if needed + if (hasOptional && !filteredImports.contains("#include ")) { + filteredImports.add(0, "#include "); + } + if (needsVariant && !filteredImports.contains("#include ")) { + filteredImports.add(0, "#include "); + } + + model.vendorExtensions.put("filteredImports", filteredImports); + } + } + } + + return processed; + } + + /** + * Processes individual model variables to configure C++ specific attributes. + * Handles nullable types, container types, and default values according to C++ conventions. + * + * @param var the model variable to process + * @param model the parent model containing this variable + */ + private void processModelVariable(CodegenProperty var, CodegenModel model) { + // Ensure baseName is set for JSON serialization + if (var.baseName == null || var.baseName.isEmpty()) { + var.baseName = var.name; + } + String modelClassName = model.vendorExtensions.get("modelClassName").toString(); + String varName = toPascalCase(var.name); + + // Convert inline model names in dataType to PascalCase + if (var.dataType != null && !var.isPrimitiveType && !var.isContainer) { + // Check if dataType contains underscore or hyphen (likely inline model) + if (var.dataType.contains("_") || var.dataType.contains("-")) { + // Don't process if it's a C++ standard library type + if (!var.dataType.startsWith("std::")) { + var.dataType = toPascalCase(var.dataType); + } + } + } + if (var.datatypeWithEnum != null && !var.isPrimitiveType && !var.isContainer) { + if (var.datatypeWithEnum.contains("_") || var.datatypeWithEnum.contains("-")) { + if (!var.datatypeWithEnum.startsWith("std::")) { + var.datatypeWithEnum = toPascalCase(var.datatypeWithEnum); + } + } + } + + // Replace oas_any_type_not_mapped placeholder with nlohmann::json + if ("oas_any_type_not_mapped".equals(var.dataType)) { + var.dataType = "nlohmann::json"; + } + if ("oas_any_type_not_mapped".equals(var.datatypeWithEnum)) { + var.datatypeWithEnum = "nlohmann::json"; + } + if (var.items != null && "oas_any_type_not_mapped".equals(var.items.dataType)) { + var.items.dataType = "nlohmann::json"; + } + if (var.items != null && "oas_any_type_not_mapped".equals(var.items.datatypeWithEnum)) { + var.items.datatypeWithEnum = "nlohmann::json"; + } + + // Handle anyOf/oneOf union types (std::variant) + if (var.dataType != null && var.dataType.startsWith("std::variant<")) { + var.vendorExtensions.put("isUnionType", true); + + // Generate union type alias name from property name + String unionTypeName = toPascalCase(var.name); + var.vendorExtensions.put("unionTypeName", unionTypeName); + + // Extract individual types from the variant declaration + String variantContent = var.dataType.substring(13, var.dataType.length() - 1); + List unionTypes = Arrays.asList(variantContent.split(",\\s*")); // Split by comma and optional whitespace + var.vendorExtensions.put("unionTypes", unionTypes); + + // Mark that model needs variant include + model.vendorExtensions.put("hasVariant", true); + } else { + var.vendorExtensions.put("isUnionType", false); + } + + // Handle nullable types + if (var.isNullable) { + var.vendorExtensions.put("isOptional", true); + // Don't wrap again if already wrapped + if (!var.dataType.startsWith("std::optional<")) { + // Store the inner type for the template + var.vendorExtensions.put("innerType", var.dataType); + var.dataType = "std::optional<" + var.dataType + ">"; + } + } else { + var.vendorExtensions.put("isOptional", false); + } + + // Remove namespace prefixes from enum names in array items + // Enums are defined within the class scope and don't need prefixes + if (var.isArray && var.items != null && var.items.isEnum) { + if (var.items.dataType != null && var.items.dataType.contains("::")) { + String[] parts = var.items.dataType.split("::"); + var.items.dataType = parts[parts.length - 1]; + } + if (var.items.datatypeWithEnum != null && var.items.datatypeWithEnum.contains("::")) { + String[] parts = var.items.datatypeWithEnum.split("::"); + var.items.datatypeWithEnum = parts[parts.length - 1]; + } + } + + // Handle container types + if (var.isArray && var.dataType.startsWith("std::vector<")) { + // Use datatypeWithEnum for enums to preserve enum type names before they're stripped + String itemType = var.items != null ? + (var.items.datatypeWithEnum != null ? var.items.datatypeWithEnum : var.items.dataType) : + "std::string"; + + // For inline enums in arrays, qualify with the model class name if not already qualified + if (var.items != null && var.items.isEnum && !itemType.contains("::")) { + itemType = modelClassName + "::" + itemType; + } + + // Use property name and item type for better naming + String arrayTypeName = toPascalCase(var.name) + "VectorOf" + toPascalCase(itemType); + var.vendorExtensions.put("arrayTypeName", arrayTypeName); + var.dataType = "std::vector<" + itemType + ">"; + var.datatypeWithEnum = var.dataType; // Keep them in sync + } + + if (var.isMap && var.dataType.startsWith("std::map<")) { + String itemType = var.items != null ? var.items.dataType : "std::string"; + var.dataType = "std::map"; + } + + if(var.items !=null && "string".equals(var.items.dataType)) { + var.items.dataType = "std::string"; + var.items.isPrimitiveType = true; + } + + // Handle arrays + if (var.isArray) { + model.vendorExtensions.put("hasArrays", true); + setArrayVendorExtensions(var, varName, modelClassName, model); + + // Set default value for arrays - use datatypeWithEnum for correct enum type + if (var.defaultValue == null) { + // Use datatypeWithEnum which has the correct type (including enum types) + var.defaultValue = var.datatypeWithEnum + "()"; + } + } + else { + //Handle enums + if(var.isEnum) { + setEnumVendorExtensions(var, model); + + // Check for explicit default values in schema + // Base generator may auto-generate defaults which should be ignored for enums + boolean hasExplicitDefault = var.defaultValue != null + && !var.defaultValue.equals("\"\"") + && !var.defaultValue.equals("null") + && !var.defaultValue.equals("0"); // Base generator default for integer types + + // Handle enum default values based on required status and schema default + if (!hasExplicitDefault) { + if (!var.required) { + // Optional enum: wrap in std::optional and default to std::nullopt + if (!var.dataType.startsWith("std::optional<")) { + var.dataType = "std::optional<" + var.datatypeWithEnum + ">"; + var.datatypeWithEnum = var.dataType; + } + var.defaultValue = "std::nullopt"; + // Mark that this enum is wrapped in std::optional (for template conditionals) + var.vendorExtensions.put("isOptionalEnum", true); + } else { + // Required enum: Use first value which is always UNSPECIFIED (added by setEnumVendorExtensions) + if (var.allowableValues != null && var.allowableValues.containsKey("values")) { + @SuppressWarnings("unchecked") + List values = (List) var.allowableValues.get("values"); + if (values != null && !values.isEmpty()) { + // First value is always safe (UNSPECIFIED) after setEnumVendorExtensions + String enumIdentifier = values.get(0).toString(); + var.defaultValue = var.datatypeWithEnum + "::" + enumIdentifier; + } + } + } + } else { + // Explicit default value from schema - use qualified enum name + String defaultVal = var.defaultValue.replaceAll("\"", ""); + // Convert numeric enum values (e.g., "100" -> "_100") + if (defaultVal.matches("^[0-9]+$")) { + defaultVal = "_" + defaultVal; + } + // Convert to UPPERCASE to match enum definition + defaultVal = defaultVal.toUpperCase(Locale.ROOT); + var.defaultValue = var.datatypeWithEnum + "::" + defaultVal; + } + } + // Handle Date types + if ("Date".equals(var.baseType) || "DateTime".equals(var.baseType)) { + var.dataType = "std::string"; + var.datatypeWithEnum = "std::string"; + } + // Set default values + if (var.defaultValue == null) { + var.defaultValue = getDefaultValueForType(var.dataType, var.isNullable); + } + // Set primitive flags for mustache + if (var.dataType.equals("int") || var.dataType.equals("int32_t") || var.dataType.equals("int64_t") + || var.dataType.equals("integer")) { + var.vendorExtensions.put("isInt", true); + var.vendorExtensions.put("isPrimitive", true); + } + if (var.dataType.equals("long")) { + var.vendorExtensions.put("isLong", true); + var.vendorExtensions.put("isPrimitive", true); + } + if (var.dataType.equals("float")) { + var.vendorExtensions.put("isFloat", true); + var.vendorExtensions.put("isPrimitive", true); + } + if (var.dataType.equals("double") || var.dataType.equals("number")) { + var.vendorExtensions.put("isDouble", true); + var.vendorExtensions.put("isPrimitive", true); + } + if (var.dataType.equals("bool") || var.dataType.equals("boolean")) { + var.vendorExtensions.put("isBool", true); + var.vendorExtensions.put("isPrimitive", true); + } + if (var.dataType.equals("std::string") || var.dataType.equals("string")) { + var.vendorExtensions.put("isString", true); + var.vendorExtensions.put("isPrimitive", true); + } + if(var.isModel) { + var.vendorExtensions.put("isModel", true); + if(var.defaultValue != null && var.defaultValue.startsWith("std::make_shared<")) { + var.defaultValue = var.datatypeWithEnum + "()" ; + } + } + } + //Handle getters and setters + if (var.getter != null) { + var.vendorExtensions.put("getter", var.getter); + var.vendorExtensions.put("getterType", var.datatypeWithEnum); + } + if (var.setter != null) { + var.vendorExtensions.put("setter", var.setter); + var.vendorExtensions.put("setterType", var.datatypeWithEnum); + } + } + + /** + * Generates appropriate default values for C++ types based on the data type and nullability. + * + * @param dataType the C++ data type + * @param isNullable whether the type is nullable + * @return the appropriate default value string + */ + private String getDefaultValueForType(String dataType, boolean isNullable) { + if (isNullable) { + return "std::nullopt"; + } + + if (dataType.equals("std::string")) { + return "\"\""; + } else if (dataType.equals("bool")) { + return "false"; + } else if (dataType.equals("int") || dataType.equals("int32_t") || dataType.equals("int64_t")) { + return "0"; + } else if (dataType.equals("long")) { + return "0L"; + } else if (dataType.equals("float")) { + return "0.0f"; + } else if (dataType.equals("double")) { + return "0.0"; + } else if (dataType.startsWith("std::vector<")) { + return dataType + "()"; // Explicit construction + } else if (dataType.startsWith("std::map<")) { + return dataType + "()"; // Explicit construction + } else if (dataType.startsWith("std::optional<")) { + return "std::nullopt"; + } else if (dataType.startsWith("std::shared_ptr<")) { + return "nullptr"; // Shared pointers can be null + } + + // For model types, don't set default - let default constructor handle it + // Return null so the template skips this in the initializer list + return null; + } + + /** + * Converts an OpenAPI model name to a C++ class name. + * Handles inline model prefixes and converts to PascalCase. + * + * @param name the original model name + * @return the C++ class name + */ + @Override + public String toModelName(String name) { + if (name == null) { + return "Model"; + } + + // Handle generic object names that need better naming + if (name.equals("object") || name.startsWith("object_") || name.contains("inline_object")) { + // Try to extract a number suffix for uniqueness + if (name.contains("_")) { + String[] parts = name.split("_"); + if (parts.length > 1 && parts[parts.length - 1].matches("\\d+")) { + return "InlineModel" + parts[parts.length - 1]; + } + } + return "InlineModel"; + } + + // Handle inline model names starting with underscore + if (name.startsWith("_")) { + name = name.substring(1); + } + + // Handle inline model names starting with "inline_" + if (name.startsWith("inline_")) { + name = name.substring(7); // Remove "inline_" prefix + } + + // Convert to PascalCase + return toPascalCase(sanitizeName(name)); + } + + /** + * Converts an API name to a C++ API class name. + * Handles default naming and path-based names. + * + * @param name the original API name + * @return the C++ API class name + */ + @Override + public String toApiName(String name) { + String apiName = name; + if ("Default".equals(apiName) || apiName == null || apiName.isEmpty()) { + apiName = addProjectOrDefaultName(apiName, "Default"); + } else { + String[] parts = apiName.split("[/]"); + if (parts.length > 1) { + apiName = toPascalCase(parts[1]); + } else { + apiName = toPascalCase(apiName); + } + } + return apiName; + } + + /** + * Converts an API name to its corresponding filename. + * + * @param name the API name + * @return the filename without extension + */ + @Override + public String toApiFilename(String name) { + String apiFileName = name; + if ("Default".equals(apiFileName) || apiFileName == null || apiFileName.isEmpty()) { + apiFileName = addProjectOrDefaultName(apiFileName, "Default"); + } else { + apiFileName = toPascalCase(name); + } + return apiFileName + toPascalCase(API_SUFFIX); + } + + @Override + @SuppressWarnings({"rawtypes", "unchecked"}) + public String getTypeDeclaration(Schema p) { + if (p.getOneOf() != null && !p.getOneOf().isEmpty()) { + // For oneOf, map to std::variant of possible types + StringBuilder variant = new StringBuilder("std::variant<"); + List schemas = p.getOneOf(); + for (int i = 0; i < schemas.size(); i++) { + if (i > 0) variant.append(", "); + variant.append(getTypeDeclaration(schemas.get(i))); + } + variant.append(">"); + return variant.toString(); + } else if (p.getAnyOf() != null && !p.getAnyOf().isEmpty()) { + // For anyOf, also use std::variant to handle multiple possible types + StringBuilder variant = new StringBuilder("std::variant<"); + List schemas = p.getAnyOf(); + for (int i = 0; i < schemas.size(); i++) { + if (i > 0) variant.append(", "); + variant.append(getTypeDeclaration(schemas.get(i))); + } + variant.append(">"); + return variant.toString(); + } else if (ModelUtils.isArraySchema(p)) { + // Handle arrays with full type declaration + String inner = getTypeDeclaration(Objects.requireNonNull(ModelUtils.getSchemaItems(p))); + return "std::vector<" + inner + ">"; + } else if (ModelUtils.isMapSchema(p)) { + // Handle maps with full type declaration + String inner = getTypeDeclaration(ModelUtils.getAdditionalProperties(p)); + return "std::map"; + } else if (ModelUtils.isComposedSchema(p) && p.getAllOf() != null) { + // allOf is handled by composition in fromModel + return super.getTypeDeclaration(p); + } + String typeDecl = super.getTypeDeclaration(p); + + if (typeDecl != null && typeDecl.contains("oas_any_type_not_mapped")) { + typeDecl = typeDecl.replace("oas_any_type_not_mapped", "nlohmann::json"); + } + return typeDecl; + } + + @Override + @SuppressWarnings({"rawtypes", "unchecked"}) + public CodegenModel fromModel(String name, Schema schema) { + // Use schema title if available for better naming + String modelName = name; + if (schema.getTitle() != null && !schema.getTitle().isEmpty()) { + modelName = schema.getTitle(); + } else if (name != null && (name.startsWith("object") || name.contains("inline_object"))) { + // Try to generate a better name for inline objects + } + + CodegenModel model = super.fromModel(modelName, schema); + + // Ensure the model name is properly set + if (model != null) { + model.name = toModelName(modelName); + model.classname = model.name; + + if (schema.getAllOf() != null && !schema.getAllOf().isEmpty() && this.openAPI != null) { + int refCount = 0; + String parentRef = null; + Set parentPropertyNames = new HashSet<>(); + List mergedVars = new ArrayList<>(); + + for (Schema allOfSchema : (List) schema.getAllOf()) { + if (allOfSchema.get$ref() != null) { + refCount++; + parentRef = ModelUtils.getSimpleRef(allOfSchema.get$ref()); + + // Get parent properties to filter them out from child + Schema parentSchema = ModelUtils.getReferencedSchema(openAPI, allOfSchema); + CodegenModel parentModel = super.fromModel(parentRef, parentSchema); + if (parentModel != null && parentModel.vars != null) { + for (CodegenProperty var : parentModel.vars) { + parentPropertyNames.add(var.name); + } + // Only merge if we have multiple parents + if (schema.getAllOf().size() > 1) { + mergedVars.addAll(parentModel.vars); + } + } + } else { + // Inline schema: merge its properties + CodegenModel inlineModel = super.fromModel(modelName + "_inline", allOfSchema); + if (inlineModel != null && inlineModel.vars != null) { + mergedVars.addAll(inlineModel.vars); + } + } + } + + // Case 1: Single parent with possible inline schema (inheritance) + if (refCount == 1 && parentRef != null) { + model.parent = toModelName(parentRef); + model.parentModel = null; // Don't need to store parent model + + // Filter out inherited properties from child + List childOnlyVars = new ArrayList<>(); + for (CodegenProperty var : model.vars) { + if (!parentPropertyNames.contains(var.name)) { + childOnlyVars.add(var); + } + } + model.vars = childOnlyVars; + } + // Case 2: Multiple parents or complex composition (merge all) + else if (refCount > 1 || mergedVars.size() > 0) { + // Avoid duplicates + Map uniqueVars = new LinkedHashMap<>(); + for (CodegenProperty var : mergedVars) { + uniqueVars.put(var.name, var); + } + for (CodegenProperty var : model.vars) { + uniqueVars.put(var.name, var); + } + model.vars = new ArrayList<>(uniqueVars.values()); + model.parent = null; // No inheritance for multiple parents + } + } + + // Handle oneOf/anyOf schemas - generate std::variant type alias instead of class + if (schema.getOneOf() != null && !schema.getOneOf().isEmpty()) { + model.vendorExtensions.put("isOneOfSchema", true); + model.vendorExtensions.put("hasVariant", true); + List variantTypes = new ArrayList<>(); + for (Schema oneOfSchema : (List) schema.getOneOf()) { + String typeName = getTypeDeclaration(oneOfSchema); + variantTypes.add(typeName); + } + model.vendorExtensions.put("oneOfTypes", variantTypes); + + // Extract discriminator if present + if (schema.getDiscriminator() != null) { + model.vendorExtensions.put("discriminatorProperty", schema.getDiscriminator().getPropertyName()); + if (schema.getDiscriminator().getMapping() != null) { + // Convert Map to List for Mustache iteration + List> mappingList = new ArrayList<>(); + for (Map.Entry entry : schema.getDiscriminator().getMapping().entrySet()) { + Map mappingEntry = new HashMap<>(); + mappingEntry.put("value", entry.getKey()); + // Extract type name from schema reference + String schemaRef = entry.getValue(); + String typeName = schemaRef.substring(schemaRef.lastIndexOf('/') + 1); + mappingEntry.put("key", typeName); + mappingList.add(mappingEntry); + } + model.vendorExtensions.put("discriminatorMapping", mappingList); + } + } + } else if (schema.getAnyOf() != null && !schema.getAnyOf().isEmpty()) { + model.vendorExtensions.put("isAnyOfSchema", true); + model.vendorExtensions.put("hasVariant", true); + List variantTypes = new ArrayList<>(); + for (Schema anyOfSchema : (List) schema.getAnyOf()) { + String typeName = getTypeDeclaration(anyOfSchema); + variantTypes.add(typeName); + } + model.vendorExtensions.put("anyOfTypes", variantTypes); + + // Extract discriminator if present + if (schema.getDiscriminator() != null) { + model.vendorExtensions.put("discriminatorProperty", schema.getDiscriminator().getPropertyName()); + if (schema.getDiscriminator().getMapping() != null) { + // Convert Map to List for Mustache iteration + List> mappingList = new ArrayList<>(); + for (Map.Entry entry : schema.getDiscriminator().getMapping().entrySet()) { + Map mappingEntry = new HashMap<>(); + mappingEntry.put("value", entry.getKey()); + // Extract type name from schema reference + String schemaRef = entry.getValue(); + String typeName = schemaRef.substring(schemaRef.lastIndexOf('/') + 1); + mappingEntry.put("key", typeName); + mappingList.add(mappingEntry); + } + model.vendorExtensions.put("discriminatorMapping", mappingList); + } + } + } + } + return model; + } + + @Override + public void postProcessModelProperty(CodegenModel model, CodegenProperty property) { + super.postProcessModelProperty(model, property); + + // Convert Date/DateTime types to std::string + if ("Date".equals(property.baseType) || "DateTime".equals(property.baseType)) { + property.dataType = "std::string"; + property.datatypeWithEnum = "std::string"; + } + + // Set vendor extensions for array properties + if (property.isArray) { + property.vendorExtensions.put("isArray", true); + + // Check if it's an array of enums + if (property.items != null && property.items.isEnum) { + property.vendorExtensions.put("isArrayOfEnum", true); + + if (property.datatypeWithEnum != null && property.datatypeWithEnum.contains("std::")) { + String enumName = property.items.datatypeWithEnum; + if (enumName != null && !enumName.contains("::")) { + // Replace std::EnumName with ClassName::EnumName + property.datatypeWithEnum = property.datatypeWithEnum.replace( + "std::" + enumName, + model.classname + "::" + enumName + ); + property.dataType = property.datatypeWithEnum; + } + } + } else { + property.vendorExtensions.put("isArrayOfEnum", false); + } + } else { + property.vendorExtensions.put("isArray", false); + property.vendorExtensions.put("isArrayOfEnum", false); + } + + // Set vendor extensions for map properties + if (property.isMap) { + property.vendorExtensions.put("isContainer", true); + } else if (property.isArray) { + property.vendorExtensions.put("isContainer", true); + } else { + property.vendorExtensions.put("isContainer", false); + } + + // Set vendor extensions for enum properties + if (property.isEnum) { + property.vendorExtensions.put("isEnum", true); + // Convert numeric enum values to have underscore prefix + convertNumericEnumValues(property); + } else { + property.vendorExtensions.put("isEnum", false); + } + + // Set vendor extension for nullable/optional properties + if (property.isNullable) { + property.vendorExtensions.put("isOptional", true); + } else { + property.vendorExtensions.put("isOptional", false); + } + } + + @Override + @SuppressWarnings("rawtypes") + public String toDefaultValue(Schema p) { + // Handle byte arrays separately - they are std::vector, not string + if (ModelUtils.isByteArraySchema(p)) { + return null; // Will be initialized as empty vector in constructor + } + + if (ModelUtils.isStringSchema(p) || ModelUtils.isDateSchema(p) || ModelUtils.isDateTimeSchema(p)) { + // For enum types, don't return empty string - it will be handled in processModelVariable + if (p.getEnum() != null && !p.getEnum().isEmpty()) { + return null; // Let processModelVariable handle enum defaults + } + return p.getDefault() != null ? "\"" + p.getDefault().toString() + "\"" : "\"\""; + } + if (ModelUtils.isBooleanSchema(p)) { + return p.getDefault() != null ? p.getDefault().toString() : "false"; + } + if (ModelUtils.isIntegerSchema(p)) { + return p.getDefault() != null ? p.getDefault().toString() : "0"; + } + if (ModelUtils.isNumberSchema(p)) { + if (ModelUtils.isFloatSchema(p)) { + return p.getDefault() != null ? p.getDefault().toString() + "f" : "0.0f"; + } + return p.getDefault() != null ? p.getDefault().toString() : "0.0"; + } + if (ModelUtils.isArraySchema(p)) { + // For arrays, don't generate default value here - let postProcessModelProperty handle it + // This avoids incorrect enum type qualification issues + return null; + } + if (ModelUtils.isMapSchema(p)) { + String inner = getTypeDeclaration(ModelUtils.getAdditionalProperties(p)); + return "std::map()"; + } + if (p.get$ref() != null && !p.get$ref().isEmpty()) { + // Model references as shared pointers - create instance with make_shared + return "std::make_shared<" + toModelName(ModelUtils.getSimpleRef(p.get$ref())) + ">()"; + } + // Unknown type - skip initialization, let default constructor handle it + return null; + } + + /** + * Returns the directory path for generated model files. + * + * @return the model file directory path + */ + @Override + public String modelFileFolder() { + return (outputFolder + "/models").replace("/", File.separator); + } + + /** + * Returns the directory path for generated API files. + * + * @return the API file directory path + */ + @Override + public String apiFileFolder() { + return (outputFolder + "/api").replace("/", File.separator); + } + + + private Map stripPathFromClassName(String path) { + Object stripPathValue = additionalProperties.get("stripPathFromClassName"); + Boolean isStripPath = false; + if (stripPathValue instanceof Boolean) { + isStripPath = (Boolean) stripPathValue; + } else if (stripPathValue instanceof String) { + isStripPath = Boolean.parseBoolean((String) stripPathValue); + } + Map result = new HashMap<>(); + if (isStripPath != null && isStripPath) { + if (path == null || path.isEmpty()) { + result.put("namespace", ""); + result.put("className", "DefaultClass"); + return result; + } + if (path.contains("_error") || path.contains("_Error") || path.contains("error_") + || path.contains("Error_")) { + path = path.replace("_error", "").replace("_Error", "").replace("error_", "").replace("Error_", ""); + } + // Remove leading underscores + String clean = path.replaceAll("^_+", ""); + + // If the path is now empty or whitespace only, return default + if (clean.isEmpty() || clean.trim().isEmpty()) { + result.put("namespace", ""); + result.put("className", "DefaultClass"); + return result; + } + + // Split by "/", "_", "-", " ", camelCase boundary + String[] segments = clean.split("(?<=[a-z0-9])(?=[A-Z])|[^a-zA-Z0-9]"); + List parts = new ArrayList<>(); + for (String seg : segments) { + if (seg != null && !seg.trim().isEmpty()) { + parts.add(seg.trim()); + } + } + + if (parts.size() == 0) { + result.put("namespace", ""); + result.put("className", "DefaultClass"); + return result; + } + if (clean.toLowerCase(Locale.ROOT).contains("error")) { + result.put("namespace", "error"); + result.put("className", toPascalCase(clean)); + return result; + } + + // ClassName is the rest, joined and PascalCased + StringBuilder classNameBuilder = new StringBuilder(); + String namespace = ""; + if (parts.size() > 1) { + // Use first part as namespace only for API class names, not models + namespace = parts.get(0).toLowerCase(Locale.ROOT); + for (int i = 1; i < parts.size(); i++) { + String pascalPart = toPascalCase(parts.get(i)); + if (pascalPart != null && !pascalPart.isEmpty()) { + classNameBuilder.append(pascalPart); + } + } + } else { + // Single part: use as class name + String pascalPart = toPascalCase(parts.get(0)); + if (pascalPart != null && !pascalPart.isEmpty()) { + classNameBuilder.append(pascalPart); + } + } + + // Ensure we have a valid class name + String finalClassName = classNameBuilder.toString(); + if (finalClassName.isEmpty()) { + finalClassName = "DefaultClass"; + } + + result.put("namespace", namespace); + result.put("className", toPascalCase(finalClassName)); + return result; + } else { + result.put("namespace", ""); + result.put("className", toPascalCase(path)); + return result; + } + + } + + /** + * Adds project name to a class name or returns default name if project name is not set. + * + * @param name the base name + * @param defaultName the default name to use if input is null/empty + * @return the project-prefixed name or default name + */ + public String addProjectOrDefaultName(String name, String defaultName) { + String apiName = name; + if (name == null || name.isEmpty()) { + apiName = defaultName; + } + String projectName = (String) additionalProperties.get(PROJECT_NAME); + if (projectName != null && !projectName.isEmpty()) { + apiName = toPascalCase(projectName) + API_SUFFIX; + } + return apiName; + } + + /** + * Converts a model namespace string to proper format. + * + * @param modelNamespace the namespace to convert + * @return the formatted model namespace + */ + public String toModelNamespace(String modelNamespace) { + if (modelNamespace == null || modelNamespace.isEmpty()) { + return toPascalCase(MODEL_SUFFIX); + } + return modelNamespace; + } + + /** + * Converts a string to PascalCase formatting with consistent handling. + * Handles hyphens, underscores, and camelCase boundaries. + * Used for class names, type names, and enum names. + * + * @param name the string to convert + * @return the PascalCase formatted string + */ + public String toPascalCase(String name) { + if (name == null || name.isEmpty()) { + return "DefaultClass"; + } + + // First, insert spaces before uppercase letters to split camelCase + String normalized = name.replaceAll("([a-z])([A-Z])", "$1 $2"); + // Split on delimiters (hyphens, underscores, spaces) + String[] parts = normalized.split("[_\\-\\s]+"); + StringBuilder result = new StringBuilder(); + for (String part : parts) { + if (part != null && !part.isEmpty()) { + // Check if the part starts with a digit + if (Character.isDigit(part.charAt(0))) { + // For parts starting with digit (e.g., "200response"), find where letters start + int firstLetterIndex = 0; + while (firstLetterIndex < part.length() && Character.isDigit(part.charAt(firstLetterIndex))) { + firstLetterIndex++; + } + // Keep digits as-is + result.append(part.substring(0, firstLetterIndex)); + // Capitalize first letter after digits, lowercase the rest + if (firstLetterIndex < part.length()) { + result.append(part.substring(firstLetterIndex, firstLetterIndex + 1).toUpperCase(Locale.ROOT)); + if (firstLetterIndex + 1 < part.length()) { + result.append(part.substring(firstLetterIndex + 1).toLowerCase(Locale.ROOT)); + } + } + } else { + // Check if part is already in PascalCase or camelCase (mixed case) + boolean hasMixedCase = !part.equals(part.toLowerCase(Locale.ROOT)) && + !part.equals(part.toUpperCase(Locale.ROOT)); + + if (hasMixedCase && Character.isUpperCase(part.charAt(0))) { + // Already PascalCase, keep as-is + result.append(part); + } else { + // Convert to PascalCase: Capitalize first letter, lowercase the rest + result.append(part.substring(0, 1).toUpperCase(Locale.ROOT)); + if (part.length() > 1) { + result.append(part.substring(1).toLowerCase(Locale.ROOT)); + } + } + } + } + } + return result.length() > 0 ? result.toString() : "DefaultClass"; + } + + /** + * Converts a string to camelCase formatting. + * Used for variable names and method names. + * + * @param name the string to convert + * @return the camelCase formatted string + */ + public String toCamelCase(String name) { + if (name == null || name.isEmpty()) { + return "defaultVariable"; + } + String result = camelize(name, true); + return result.isEmpty() ? "defaultVariable" : result; + } + + /** + * Converts a string to camelCase or PascalCase with proper case handling. + * Handles uppercase words like "POST" -> "Post" and "GET" -> "Get". + * + * @param name the string to convert + * @param lowercaseFirstLetter whether to lowercase the first letter (camelCase) + * @return the camelized string + */ + public String camelize(String name, boolean lowercaseFirstLetter) { + if (name == null || name.isEmpty()) { + return ""; + } + + // First, try the framework utility + String result; + if (lowercaseFirstLetter) { + result = org.openapitools.codegen.utils.StringUtils.camelize(name, CamelizeOption.LOWERCASE_FIRST_LETTER); + } else { + result = org.openapitools.codegen.utils.StringUtils.camelize(name); + } + + // If the result is the same as input and input is all uppercase, + if (result.equals(name) && name.equals(name.toUpperCase(Locale.ROOT)) && name.matches("[A-Z]+")) { + // Handle all-caps words manually + result = name.substring(0, 1).toUpperCase(Locale.ROOT) + name.substring(1).toLowerCase(Locale.ROOT); + if (lowercaseFirstLetter) { + result = result.substring(0, 1).toLowerCase(Locale.ROOT) + result.substring(1); + } + } + + return result; + } + + /** + * Generates a handler function name from HTTP method and path. + * + * @param httpMethod the HTTP method (GET, POST, etc.) + * @param path the API path + * @return the generated handler function name + */ + public String toHandlerFunctionName(String httpMethod, String path, Boolean prefix) { + String method = toPascalCase(httpMethod); + String className = stripPathFromClassName(path).get("className"); + className = className.replaceAll("[^A-Za-z0-9]",""); + if(prefix) { + return "handle" + method + "For" + toPascalCase(className); + } else { + return toPascalCase(className) + method; + } + } + + /** + * Generates a handler function request type from the API Path + * + * @param path the API path + * @return the generated handler function request + */ + public String toHandlerFunctionRequest(String path, String method) { + String className = stripPathFromClassName(path).get("className"); + className = className.replaceAll("[^A-Za-z0-9]",""); + return toPascalCase(className + toPascalCase(method) + "Request"); + } + + + /** + * Generates a handler function response type from the API path. + * + * @param path the API path + * @return the generated handler function response + */ + public String toHandlerFunctionResponse(String path, String method) { + String className = stripPathFromClassName(path).get("className"); + className = className.replaceAll("[^A-Za-z0-9]",""); + return toPascalCase(className + toPascalCase(method) + "Response"); + } + + /** + * Processes command line options and additional properties. + * Sets up default values for project configuration. + */ + @Override + public void processOpts() { + super.processOpts(); + + // Set default model package if not provided + if (modelPackage == null || modelPackage.isEmpty()) { + modelPackage = DEFAULT_PROJECT_NAME; + } + + // Get project name from additional properties + String projectName = DEFAULT_PROJECT_NAME; + if (additionalProperties.containsKey(PROJECT_NAME)) { + projectName = (String) additionalProperties.get(PROJECT_NAME); + } + + // Make package name available to templates + additionalProperties.put("packageName", modelPackage); + additionalProperties.put("projectName", projectName); + String cmakeProjectName = (String) additionalProperties.get("cmakeProjectName"); + if(cmakeProjectName == null || cmakeProjectName.isEmpty()) { + cmakeProjectName = (String) projectName; + } + additionalProperties.put("cmakeProjectName", StringUtils.underscore(cmakeProjectName)); + + + // Set Enum namespace + String enumNamespace = (String) additionalProperties.get(ENUM_NAMESPACE); + if (enumNamespace == null || enumNamespace.isEmpty()) { + enumNamespace = toPascalCase(ENUM_SUFFIX); + } + additionalProperties.put(ENUM_NAMESPACE, enumNamespace); + + // Set API namespace for templates (needed for AuthenticationManager and other supporting files) + String apiNamespaceValue = (String) additionalProperties.get(API_NAMESPACE); + if (apiNamespaceValue == null || apiNamespaceValue.isEmpty()) { + apiNamespaceValue = toPascalCase(API_SUFFIX); + } + additionalProperties.put(API_NAMESPACE, apiNamespaceValue); + + // Handle addApiImplStubs option + if (additionalProperties.containsKey(ADD_API_IMPL_STUBS)) { + boolean addApiImplStubs = Boolean.parseBoolean(additionalProperties.get(ADD_API_IMPL_STUBS).toString()); + if (addApiImplStubs) { + // Add API implementation stub templates + apiTemplateFiles.put("api-impl-header.mustache", "Impl.h"); + apiTemplateFiles.put("api-impl.mustache", "Impl.cpp"); + // Add main.cpp for executable + supportingFiles.add(new SupportingFile("main.mustache", "", "main.cpp")); + LOGGER.debug("API implementation stubs will be generated"); + } + } + + } + + /** + * Post-processes parameters to set up C++ specific configurations. + * Handles the required flag and parameter type conversions. + * + * @param parameter the parameter to process + */ + @Override + public void postProcessParameter(CodegenParameter parameter) { + super.postProcessParameter(parameter); + + // Set vendor extensions for template usage + parameter.vendorExtensions.put("isRequired", parameter.required); + parameter.vendorExtensions.put("isOptional", !parameter.required); + + // Handle non-required parameters - wrap in std::optional + if (!parameter.required) { + if (!parameter.dataType.startsWith("std::optional<")) { + parameter.dataType = "std::optional<" + parameter.dataType + ">"; + } + } + + // Extract default value from schema if available + if (parameter.defaultValue != null && !parameter.defaultValue.isEmpty()) { + // Correct nullptr default value to std::nullopt for std::optional types + if ("nullptr".equals(parameter.defaultValue) && parameter.dataType.startsWith("std::optional<")) { + parameter.defaultValue = "std::nullopt"; + } + parameter.vendorExtensions.put("hasDefaultValue", true); + parameter.vendorExtensions.put("defaultValue", parameter.defaultValue); + } else { + parameter.vendorExtensions.put("hasDefaultValue", false); + } + } + + /** + * Sets C++ type flags for a parameter for use in Mustache templates. + * Handles arrays, enums, and primitives with proper vendor extensions. + */ + private void setParameterTypeFlags(CodegenParameter param) { + if (param == null) { + return; + } + + // Set parameter style flags for serialization + String style = param.style != null ? param.style : "form"; + param.vendorExtensions.put("isStyleSimple", "simple".equals(style)); + param.vendorExtensions.put("isStyleForm", "form".equals(style)); + param.vendorExtensions.put("isStyleSpaceDelimited", "spaceDelimited".equals(style)); + param.vendorExtensions.put("isStylePipeDelimited", "pipeDelimited".equals(style)); + param.vendorExtensions.put("isStyleDeepObject", "deepObject".equals(style)); + + // Set array flags and helper names + if (param.isArray) { + setArrayVendorExtensions(param, param.nameInPascalCase, param.baseName, null); + } else if (param.isEnum) { + // Handle enum parameters + param.vendorExtensions.put("isEnum", true); + param.vendorExtensions.put("enumType", toPascalCase(param.baseType) + "Enum"); + param.vendorExtensions.put("enumFromStringHelper", param.nameInPascalCase + ENUM_FROM_STRING); + param.vendorExtensions.put("enumToStringHelper", param.nameInPascalCase + ENUM_TO_STRING); + } else { + // Set primitive type flags + setPrimitiveTypes(param); + } + } + + /** + * Helper to set vendorExtensions for array properties and parameters. + */ + private void setArrayVendorExtensions(Object varObj, String varName, String modelBaseName, CodegenModel model) { + if (varObj == null) return; + + Map vendorExtensions; + CodegenProperty items; + boolean isContainer; + + if (varObj instanceof CodegenProperty) { + CodegenProperty var = (CodegenProperty) varObj; + vendorExtensions = var.vendorExtensions; + items = var.items; + isContainer = var.isContainer; + } else if (varObj instanceof CodegenParameter) { + CodegenParameter var = (CodegenParameter) varObj; + vendorExtensions = var.vendorExtensions; + items = var.items; + isContainer = var.isContainer; + } else { + return; + } + + vendorExtensions.put("isArray", true); + String itemType = (items != null && items.dataType != null) ? items.dataType : "std::string"; + // Improved array item type naming + String arrayTypeName = toPascalCase(varName) + "VectorOf" + toPascalCase(itemType); + vendorExtensions.put("arrayTypeName", arrayTypeName); + vendorExtensions.put("arrayItemType", itemType); + if (items != null) { + // ALWAYS set primitive type flags for items (needed for type conversion in templates) + setPrimitiveTypes(items); + + if (items.isEnum) { + // Set up enum vendor extensions for items (needed for enumCases and conversion helpers) + // Only call if model is available (not for parameters) + if (model != null) { + setEnumVendorExtensions(items, model); + } + + vendorExtensions.put("isArrayOfEnum", true); + vendorExtensions.put("enumFromStringHelper", varName + "EnumFromString"); + vendorExtensions.put("enumToStringHelper", varName + "EnumToString"); + if (modelBaseName != null && !modelBaseName.isEmpty()) { + vendorExtensions.put("enumModelClass", modelBaseName); + } + // Remove namespace prefixes from enum datatypes in array items + // Enums are defined inside the class, so namespace qualifiers are not needed + if (items.datatypeWithEnum != null && items.datatypeWithEnum.contains("::")) { + // Remove any namespace prefix (like "std::" or "ModelClass::") + String[] parts = items.datatypeWithEnum.split("::"); + items.datatypeWithEnum = parts[parts.length - 1]; + } + // Also fix items.dataType which is used to construct parent's datatypeWithEnum for arrays + if (items.dataType != null && items.dataType.contains("::")) { + String[] parts = items.dataType.split("::"); + items.dataType = parts[parts.length - 1]; + } + } else if (items.isModel) { + vendorExtensions.put("isArrayOfModel", true); + vendorExtensions.put("vectorFromJsonHelper", varName + "VectorFromJson"); + vendorExtensions.put("vectorToJsonHelper", varName + "VectorToJson"); + } else if (items.isPrimitiveType) { + vendorExtensions.put("isArrayOfPrimitive", true); + vendorExtensions.put("vectorFromStringHelper", varName + "VectorFromString"); + vendorExtensions.put("vectorToStringHelper", varName + "VectorToString"); + } else if(items.isContainer) { + vendorExtensions.put("isArrayOfContainer", true); + vendorExtensions.put("vectorFromStringHelper", varName + "VectorFromString"); + vendorExtensions.put("vectorToStringHelper", varName + "VectorToString"); + } else { + // Default to primitive if type is unknown but items are present + vendorExtensions.put("isArrayOfPrimitive", true); + } + } else { + // If items are not defined, default to a simple array of primitives (strings) + vendorExtensions.put("isArrayOfPrimitive", true); + } + } + private void setPrimitiveTypes(Object varObj) { + if (varObj == null) return; + + String type; + Map vendorExtensions; + boolean isObject = false; + + if (varObj instanceof CodegenProperty) { + CodegenProperty prop = (CodegenProperty) varObj; + type = (prop.dataType != null) ? prop.dataType : ""; + vendorExtensions = prop.vendorExtensions; + isObject = prop.isModel || (!prop.isPrimitiveType && !prop.isArray && !prop.isEnum); + } else if (varObj instanceof CodegenParameter) { + CodegenParameter param = (CodegenParameter) varObj; + type = (param.dataType != null) ? param.dataType : ""; + vendorExtensions = param.vendorExtensions; + isObject = param.isModel || (!param.isPrimitiveType && !param.isArray && !param.isEnum); + } else { + return; // Unsupported type + } + + // Extract inner type from containers like std::optional, std::shared_ptr + String innerType = type; + if (type.contains("<")) { + int startIdx = type.indexOf('<') + 1; + int endIdx = type.lastIndexOf('>'); + if (startIdx > 0 && endIdx > startIdx) { + innerType = type.substring(startIdx, endIdx).trim(); + } + } + + // Normalize some aliases + if ("string".equals(innerType)) innerType = "std::string"; + if ("integer".equals(innerType)) innerType = "int"; + if ("number".equals(innerType)) innerType = "double"; // treat generic number as double + + boolean isLong = innerType.equals("long") || innerType.equals("int64_t"); + boolean isFloat = innerType.equals("float"); + boolean isString = innerType.equals("std::string") || innerType.equals("string"); + boolean isInt = innerType.equals("int") || innerType.equals("int32_t") || innerType.equals("int64_t") || innerType.equals("integer"); + boolean isBool = innerType.equals("bool") || innerType.equals("boolean"); + boolean isDouble = innerType.equals("double") || innerType.equals("number"); + + // Handle overlaps: int64_t should be treated as long, not int + if (innerType.equals("int64_t")) { + isInt = false; + isLong = true; + } + + boolean isPrimitive = isInt || isLong || isFloat || isBool || isDouble || isString; + + vendorExtensions.put("isObject", isObject); + vendorExtensions.put("isString", isString); + vendorExtensions.put("isInt", isInt); + vendorExtensions.put("isLong", isLong); + vendorExtensions.put("isFloat", isFloat); + vendorExtensions.put("isBool", isBool); + vendorExtensions.put("isDouble", isDouble); + vendorExtensions.put("isPrimitive", isPrimitive); + } + + /** + * Converts numeric enum values to valid C++ enum names by prefixing with underscore. + * This is needed because C++ enum identifiers cannot start with digits. + * This method processes enum values in a CodegenProperty and prefixes any purely numeric + * enum values with an underscore. This is necessary because in C++, enum identifiers cannot + * start with a digit, so numeric enum values must be transformed to valid C++ identifiers. + * + * For example: + * - "200" becomes "_200" + * - "404" becomes "_404" + * - "OK" remains "OK" + * + * The method retrieves enum values from either the property's {@code _enum} field or from + * the {@code allowableValues} map, then updates all three locations with the converted values + * to maintain consistency across the property's internal state. + * + * @param property the CodegenProperty containing enum values to convert + */ + private void convertNumericEnumValues(CodegenProperty property) { + // Get enum values from property._enum or allowableValues + List enumValues = property._enum; + if ((enumValues == null || enumValues.isEmpty()) && property.allowableValues != null) { + Object valuesObj = property.allowableValues.get("values"); + if (valuesObj instanceof List) { + enumValues = (List) valuesObj; + } + } + + if (enumValues != null && !enumValues.isEmpty()) { + List convertedValues = new ArrayList<>(); + for (Object enumVal : enumValues) { + String enumValStr = enumVal != null ? enumVal.toString() : ""; + String convertedVal = enumValStr; + // Convert numeric values to have underscore prefix + if (enumValStr.matches("^[0-9]+$")) { + convertedVal = "_" + enumValStr; + } + // Convert to UPPERCASE for C++ enum standards (clang style) + convertedVal = convertedVal.toUpperCase(Locale.ROOT); + convertedValues.add(convertedVal); + } + // Update the property with converted values + property._enum = convertedValues; + property.vendorExtensions.put("values", convertedValues); + if (property.allowableValues != null) { + property.allowableValues.put("values", convertedValues); + } + } + } + + /** + * Helper to set vendorExtensions for enum properties and parameters. + * Handles enum value conversion and helper function naming. + */ + private void setEnumVendorExtensions(Object varObj, CodegenModel model) { + if (varObj == null) { + return; + } + + CodegenProperty var; + if (varObj instanceof CodegenProperty) { + var = (CodegenProperty) varObj; + } else { + return; + } + + var.vendorExtensions.put("isEnum", true); + var.vendorExtensions.put("enumType", toPascalCase(var.baseType) + "Enum"); + + // Use SHORT enum name that will be scoped to the class + // e.g., "CardTypeEnum" not "CreditCardCardTypeEnum" + // Use centralized toPascalCase for consistent naming + String shortEnumName = toPascalCase(var.baseName) + "Enum"; + var.vendorExtensions.put("enumName", shortEnumName); + var.enumName = shortEnumName; // Also set the direct property + var.vendorExtensions.put("enumToStringHelper", var.name + ENUM_TO_STRING); + + // Convert numeric enum values to valid C++ enum names + List convertedValues = new ArrayList<>(); + + // Try to get enum values from var._enum, allowableValues, or var.allowableValues + List enumValues = var._enum; + if ((enumValues == null || enumValues.isEmpty()) && var.allowableValues != null) { + enumValues = new ArrayList<>(); + for (Object val : var.allowableValues.values()) { + enumValues.add(val != null ? val.toString() : ""); + } + } + + LOGGER.debug("Processing enum for variable {}: isEnum={}, _enum={}, allowableValues={}", + var.name, var.isEnum, var._enum, var.allowableValues); + + // Check if enum has UNKNOWN/UNSPECIFIED value, if not add it at the beginning + boolean hasUnknownValue = false; + if (enumValues != null && !enumValues.isEmpty()) { + for (String enumVal : enumValues) { + String upperVal = enumVal.toUpperCase(Locale.ROOT); + if (upperVal.equals("UNKNOWN") || upperVal.equals("UNSPECIFIED") || + upperVal.equals("NONE") || upperVal.equals("UNDEFINED")) { + hasUnknownValue = true; + break; + } + } + } + + if (!hasUnknownValue) { + if (enumValues == null) { + enumValues = new ArrayList<>(); + } + enumValues.add(0, "UNSPECIFIED"); + LOGGER.debug("Added UNSPECIFIED value to enum {} (needed for safe initialization)", var.name); + } + + if (enumValues != null && !enumValues.isEmpty()) { + for (String enumVal : enumValues) { + // Convert numeric values to words or keep string values as-is + String convertedVal = enumVal; + if (enumVal.matches("^[0-9]+$")) { + // Convert number to enum name + convertedVal = "_" + enumVal; // Prefix with underscore for numeric values + } + convertedValues.add(convertedVal); + } + } else { + LOGGER.warn("No enum values found for variable {} in model {}", var.name, model.classname); + } + + var.vendorExtensions.put("values", convertedValues); + var._enum = convertedValues; // Also set it on the var itself for Mustache access + var.allowableValues.put("values", convertedValues); // Also update allowableValues for template + + // Create enumCases for use in helper functions + List> enumCases = new ArrayList<>(); + // Iterate through original enum values to maintain mapping between C++ identifiers and original JSON values + if (enumValues != null) { + for (int i = 0; i < enumValues.size(); i++) { + String originalVal = enumValues.get(i); // Original value (e.g., "200") + String convertedVal = convertedValues.get(i); // Converted C++ identifier (e.g., "_200") + Map caseMap = new HashMap<>(); + caseMap.put("name", convertedVal); // C++ enum identifier + caseMap.put("value", originalVal); // Original JSON value + caseMap.put("enumName", shortEnumName); // Use short name + enumCases.add(caseMap); + } + } + var.vendorExtensions.put("enumCases", enumCases); + + LOGGER.debug("Set enum values for {}: {}", var.name, convertedValues); + var.vendorExtensions.put("enumFromStringHelper", var.name + ENUM_FROM_STRING); + // Use the short enum name (e.g., "CardTypeEnum") for the datatype + // When used in containers, it will be scoped to the class (e.g., "CreditCard::CardTypeEnum") + var.vendorExtensions.put("shortEnumName", shortEnumName); + var.datatypeWithEnum = shortEnumName; + } + + /** + * Process security requirements for an operation. + * Adds vendor extensions for different authentication types. + */ + private void processSecurityRequirements(CodegenOperation op) { + if (op.authMethods == null || op.authMethods.isEmpty()) { + op.vendorExtensions.put("hasAuth", false); + return; + } + + op.vendorExtensions.put("hasAuth", true); + + List> apiKeyAuth = new ArrayList<>(); + List> bearerAuth = new ArrayList<>(); + List> basicAuth = new ArrayList<>(); + List> oauth2Auth = new ArrayList<>(); + + for (org.openapitools.codegen.CodegenSecurity auth : op.authMethods) { + Map authInfo = new HashMap<>(); + authInfo.put("name", auth.name); + authInfo.put("keyParamName", auth.keyParamName); + + if (auth.isApiKey) { + authInfo.put("isKeyInHeader", auth.isKeyInHeader); + authInfo.put("isKeyInQuery", auth.isKeyInQuery); + authInfo.put("isKeyInCookie", auth.isKeyInCookie); + apiKeyAuth.add(authInfo); + } else if (auth.isBasicBearer) { + if (auth.name != null && auth.name.toLowerCase(Locale.ROOT).contains("bearer")) { + bearerAuth.add(authInfo); + } else { + basicAuth.add(authInfo); + } + } else if (auth.isBasic || auth.isBasicBasic) { + basicAuth.add(authInfo); + } else if (auth.isOAuth) { + authInfo.put("scopes", auth.scopes); + oauth2Auth.add(authInfo); + } + } + + if (!apiKeyAuth.isEmpty()) { + op.vendorExtensions.put("hasApiKeyAuth", true); + op.vendorExtensions.put("apiKeyAuth", apiKeyAuth); + } + if (!bearerAuth.isEmpty()) { + op.vendorExtensions.put("hasBearerAuth", true); + op.vendorExtensions.put("bearerAuth", bearerAuth); + } + if (!basicAuth.isEmpty()) { + op.vendorExtensions.put("hasBasicAuth", true); + op.vendorExtensions.put("basicAuth", basicAuth); + } + if (!oauth2Auth.isEmpty()) { + op.vendorExtensions.put("hasOAuth2", true); + op.vendorExtensions.put("oauth2Auth", oauth2Auth); + } + } + + /** + * Post-processes supporting file data to conditionally add files based on API features. + * This is called after preprocessOpenAPI, so hasAuthMethods is properly set. + * + * @param objs the supporting file data + * @return the processed supporting file data + */ + @Override + public Map postProcessSupportingFileData(Map objs) { + // Conditionally add AuthenticationManager file if security is defined + if (additionalProperties.containsKey("hasAuthMethods") + && Boolean.TRUE.equals(additionalProperties.get("hasAuthMethods"))) { + supportingFiles.add(new SupportingFile("AuthenticationManager.mustache", "api", "AuthenticationManager.h")); + } + return super.postProcessSupportingFileData(objs); + } +} diff --git a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig index 345f9b2543b7..8e7f3b9423f2 100644 --- a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig +++ b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig @@ -12,6 +12,7 @@ org.openapitools.codegen.languages.CrystalClientCodegen org.openapitools.codegen.languages.CLibcurlClientCodegen org.openapitools.codegen.languages.ClojureClientCodegen org.openapitools.codegen.languages.ConfluenceWikiCodegen +org.openapitools.codegen.languages.CppHttplibServerCodegen org.openapitools.codegen.languages.CppOatppClientCodegen org.openapitools.codegen.languages.CppQtClientCodegen org.openapitools.codegen.languages.CppQtQHttpEngineServerCodegen diff --git a/modules/openapi-generator/src/main/resources/cpp-httplib-server/AuthenticationManager.mustache b/modules/openapi-generator/src/main/resources/cpp-httplib-server/AuthenticationManager.mustache new file mode 100644 index 000000000000..40b3cb7784f1 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/cpp-httplib-server/AuthenticationManager.mustache @@ -0,0 +1,75 @@ +{{>License}} + +#pragma once + +#include +#include +#include + +namespace {{apiNamespace}} { + +/** + * @brief Authentication Manager Interface + * + * This interface defines the contract for authentication validation. + * Users must implement this interface to provide their own authentication logic. + * + * Example implementation: + * @code + * class MyAuthManager : public AuthenticationManager { + * public: + * bool validateApiKey(const std::string& key) override { + * return database.checkApiKey(key); + * } + * + * bool validateBearerToken(const std::string& token) override { + * return jwt::verify(token, secret); + * } + * + * bool validateBasicAuth(const std::string& username, const std::string& password) override { + * return bcrypt::verify(password, database.getPasswordHash(username)); + * } + * + * bool validateOAuth2(const std::string& token, const std::vector& scopes) override { + * auto introspection = oauthProvider.introspect(token); + * return introspection.active && hasRequiredScopes(introspection, scopes); + * } + * }; + * @endcode + */ +class AuthenticationManager { +public: + virtual ~AuthenticationManager() = default; + + /** + * @brief Validate an API key + * @param key The API key to validate + * @return true if the API key is valid, false otherwise + */ + virtual bool validateApiKey(const std::string& key) = 0; + + /** + * @brief Validate a Bearer token (e.g., JWT) + * @param token The bearer token to validate + * @return true if the token is valid, false otherwise + */ + virtual bool validateBearerToken(const std::string& token) = 0; + + /** + * @brief Validate Basic authentication credentials + * @param username The username + * @param password The password + * @return true if the credentials are valid, false otherwise + */ + virtual bool validateBasicAuth(const std::string& username, const std::string& password) = 0; + + /** + * @brief Validate an OAuth2 token with required scopes + * @param token The OAuth2 access token + * @param scopes The required scopes for this operation + * @return true if the token is valid and has required scopes, false otherwise + */ + virtual bool validateOAuth2(const std::string& token, const std::vector& scopes) = 0; +}; + +} // namespace {{apiNamespace}} diff --git a/modules/openapi-generator/src/main/resources/cpp-httplib-server/CMakeLists.txt.mustache b/modules/openapi-generator/src/main/resources/cpp-httplib-server/CMakeLists.txt.mustache new file mode 100644 index 000000000000..45ec4d39f669 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/cpp-httplib-server/CMakeLists.txt.mustache @@ -0,0 +1,62 @@ +cmake_minimum_required(VERSION 3.14) +project({{cmakeProjectName}} LANGUAGES CXX) + +include(FetchContent) + +# Fetch nlohmann_json +FetchContent_Declare( + nlohmann_json + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_TAG v3.11.3 +) +FetchContent_MakeAvailable(nlohmann_json) + +# Fetch cpp-httplib +FetchContent_Declare( + httplib + GIT_REPOSITORY https://github.com/yhirose/cpp-httplib.git + GIT_TAG v0.15.3 +) +FetchContent_MakeAvailable(httplib) + +# System libraries - install with: sudo apt-get install libssl-dev zlib1g-dev +find_package(OpenSSL REQUIRED) +find_package(ZLIB REQUIRED) + +set(TARGET_NAME {{cmakeProjectName}}_openapi_lib) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +file(GLOB API_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/api/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/api/*.cpp +) +file(GLOB MODEL_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/models/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/models/*.cpp +) +add_library(${TARGET_NAME} ${API_SRCS} ${MODEL_SRCS}) +target_include_directories (${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +# Make sure these libraries/headers are available in the build environment before linking +# Required libraries/headers are httplib,ssl,nlohmann::json,zlib +target_link_libraries(${TARGET_NAME} + PRIVATE + httplib::httplib + OpenSSL::SSL + OpenSSL::Crypto + nlohmann_json::nlohmann_json + ZLIB::ZLIB) + +{{#addApiImplStubs}} +# Build executable server with stub implementation +add_executable({{cmakeProjectName}}_server main.cpp) +target_link_libraries({{cmakeProjectName}}_server + PRIVATE + ${TARGET_NAME} + httplib::httplib + OpenSSL::SSL + OpenSSL::Crypto + nlohmann_json::nlohmann_json + ZLIB::ZLIB) +target_include_directories({{cmakeProjectName}}_server PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +{{/addApiImplStubs}} diff --git a/modules/openapi-generator/src/main/resources/cpp-httplib-server/License.mustache b/modules/openapi-generator/src/main/resources/cpp-httplib-server/License.mustache new file mode 100644 index 000000000000..286685933869 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/cpp-httplib-server/License.mustache @@ -0,0 +1,5 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/cpp-httplib-server/README.mustache b/modules/openapi-generator/src/main/resources/cpp-httplib-server/README.mustache new file mode 100644 index 000000000000..979519ce5c71 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/cpp-httplib-server/README.mustache @@ -0,0 +1,437 @@ +# {{projectName}} - C++ Server + +## Overview + +This server was generated using the [OpenAPI Generator](https://openapi-generator.tech) project. +It uses the [cpp-httplib](https://github.com/yhirose/cpp-httplib) library to implement a lightweight HTTP server +with JSON request/response handling via [nlohmann/json](https://github.com/nlohmann/json). + +## Requirements + +- C++17 compatible compiler +- CMake (3.14 or higher) +- OpenSSL (for HTTPS support) +- ZLIB (for compression support) + +**Note:** The following libraries are automatically downloaded via CMake FetchContent: +- [cpp-httplib](https://github.com/yhirose/cpp-httplib) v0.15.3 +- [nlohmann/json](https://github.com/nlohmann/json) v3.11.3 + +### Platform-Specific Installation + +**Linux (Ubuntu/Debian):** +```bash +sudo apt-get update +sudo apt-get install -y libssl-dev zlib1g-dev cmake build-essential +``` + +**macOS:** +```bash +brew install openssl zlib cmake +``` + +**Windows:** +```powershell +# Using vcpkg +vcpkg install openssl:x64-windows zlib:x64-windows + +# Then configure CMake with vcpkg toolchain: +cmake -B build -DCMAKE_TOOLCHAIN_FILE=[vcpkg_root]/scripts/buildsystems/vcpkg.cmake +``` + +## Project Structure + +``` +├── CMakeLists.txt # Project build configuration +├── README.md # This file +├── models/ # Generated model classes +└── api/ # Generated API handler classes +``` + +## Building the Project + +```bash +mkdir build +cd build +cmake .. +make +``` + +{{#addApiImplStubs}} +### Quick Start with Generated Stubs + +This project was generated with implementation stubs enabled. You can build and run the server immediately: + +```bash +mkdir build && cd build +cmake .. +make +./{{cmakeProjectName}}_server +``` + +The server will start on `http://0.0.0.0:8080` with: +- All API endpoints registered with stub implementations +- Health check endpoint at `/health` +{{#hasAuthMethods}} +- Example authentication manager (remember to implement real authentication logic!) +{{/hasAuthMethods}} + +**Implementation files to customize:** +{{#apiInfo}} +{{#apis}} +{{#operations}} +- `api/{{classFilename}}{{apiSuffix}}Impl.h` - API interface implementation +- `api/{{classFilename}}{{apiSuffix}}Impl.cpp` - Business logic stubs +{{/operations}} +{{/apis}} +{{/apiInfo}} +- `main.cpp` - Server configuration and startup + +{{/addApiImplStubs}} +## Working with Models + +### Model Classes + +{{#models}} +{{#model}} +#### {{vendorExtensions.modelNamespace}}::{{vendorExtensions.modelClassName}} + +```cpp +// Create a model +auto model = {{vendorExtensions.modelNamespace}}::{{vendorExtensions.modelClassName}}(); +{{#vars}} +model.{{vendorExtensions.setter}}(/* value */); // Set {{baseName}} +{{/vars}} + +// Serialize to JSON +nlohmann::json json = {{vendorExtensions.modelNamespace}}::{{vendorExtensions.modelClassName}}::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = {{vendorExtensions.modelNamespace}}::{{vendorExtensions.modelClassName}}::fromJson(nlohmann::json::parse(jsonString)); +``` +{{/model}} +{{/models}} + +## Implementing API Handlers + +### API Classes + +Each API is generated as an abstract base class with pure virtual methods that you must implement. + +{{#apiInfo}} +{{#apis}} +{{#operations}} +#### {{classname}} + +Create a class that inherits from the generated base class: + +```cpp +#include "api/{{classFilename}}{{apiSuffix}}.h" + +class {{classname}}Impl : public {{apiNamespace}}::{{classname}} { +public: + {{#operation}} + {{#vendorExtensions}} + {{#hasAnyResponseSchema}} + {{responseType}} {{handlerFunctionName}}({{#hasAnyRequestSchema}}const {{requestType}}& params{{/hasAnyRequestSchema}}) override { + {{#hasAnyRequestSchema}} + // Access request parameters: + {{#pathParams}} + // Path: params.m_{{paramName}} + {{/pathParams}} + {{#queryParams}} + // Query: params.m_{{paramName}}{{^vendorExtensions.isRequired}} (optional){{/vendorExtensions.isRequired}} + {{/queryParams}} + {{#headerParams}} + // Header: params.m_{{paramName}}{{^vendorExtensions.isRequired}} (optional){{/vendorExtensions.isRequired}} + {{/headerParams}} + {{#requestModel}} + // Body: params.m_request (std::optional<{{requestModelNamespace}}::{{requestModel}}>) + {{/requestModel}} + {{/hasAnyRequestSchema}} + + // Implement your business logic here + + {{#successCodeToTypes}} + // Return success response (HTTP {{successConstName}}): + {{successType}} successResponse; + // ... populate response ... + return successResponse; + {{/successCodeToTypes}} + {{#errorCodeToTypes}} + + // Or return error response (HTTP {{errorConstName}}): + // {{errorType}} errorResponse; + // return errorResponse; + {{/errorCodeToTypes}} + } + {{/hasAnyResponseSchema}} + {{^hasAnyResponseSchema}} + void {{handlerFunctionName}}({{#hasAnyRequestSchema}}const {{requestType}}& params{{/hasAnyRequestSchema}}) override { + {{#hasAnyRequestSchema}} + // Access request parameters from params struct + {{/hasAnyRequestSchema}} + // Implement your logic here + } + {{/hasAnyResponseSchema}} + {{/vendorExtensions}} + + {{/operation}} +}; +``` +{{/operations}} +{{/apis}} +{{/apiInfo}} + +## Running the Server + +Here's a complete example of setting up and running the server: + +```cpp +#include +#include +{{#apiInfo}}{{#apis}}{{#operations}} +#include "api/{{classFilename}}{{apiSuffix}}.h" +{{/operations}}{{/apis}}{{/apiInfo}} +{{#hasAuthMethods}} +#include "api/AuthenticationManager.h" +{{/hasAuthMethods}} + +int main() { + httplib::Server server; + +{{#hasAuthMethods}} + // Create authentication manager (required for this API) + auto authMgr = std::make_shared(); + +{{/hasAuthMethods}} + // Create API implementations +{{#apiInfo}}{{#apis}}{{#operations}} + {{classname}}Impl {{classVarName}}; +{{/operations}}{{/apis}}{{/apiInfo}} + + // Register routes +{{#apiInfo}}{{#apis}}{{#operations}} + {{classVarName}}.registerRoutes(server{{#hasAuthMethods}}, authMgr{{/hasAuthMethods}}); +{{/operations}}{{/apis}}{{/apiInfo}} + + // Start server + std::cout << "Server starting on http://localhost:8080" << std::endl; + server.listen("localhost", 8080); + + return 0; +} +``` + +{{#hasAuthMethods}} +### With Authentication + +When authentication is required, you must: +1. Implement the `AuthenticationManager` interface (see Authentication section below) +2. Pass the authentication manager to `registerRoutes()` + +{{/hasAuthMethods}} +{{^hasAuthMethods}} +### Without Authentication + +This API does not require authentication. Simply create your API implementations and register them with the server. + +{{/hasAuthMethods}} + +## Authentication + +{{#hasAuthMethods}} +This API requires authentication. Implement the `AuthenticationManager` interface to provide your authentication logic: + +```cpp +#include "api/AuthenticationManager.h" + +class MyAuthManager : public {{apiNamespace}}::AuthenticationManager { +public: + bool validateApiKey(const std::string& key) override { + // Validate API key from header, query, or cookie + // Example: check against database or cache + return checkApiKeyInDatabase(key); + } + + bool validateBearerToken(const std::string& token) override { + // Validate JWT or other bearer tokens + // Example: verify signature and expiration + return jwt::verify(token, secret_key); + } + + bool validateBasicAuth(const std::string& username, const std::string& password) override { + // Validate username/password credentials + // Example: check against user database with hashed passwords + auto user = findUser(username); + return user && bcrypt::verify(password, user->passwordHash); + } + + bool validateOAuth2(const std::string& token, const std::vector& scopes) override { + // Validate OAuth2 token and check required scopes + // Example: introspect token and verify scopes + auto introspection = oauthProvider.introspect(token); + return introspection.active && hasAllScopes(introspection.scopes, scopes); + } +}; +``` + +### Authentication Flow + +1. The server automatically extracts credentials from requests (headers, query params, cookies) +2. Before calling your handler, it validates credentials using your `AuthenticationManager` +3. If validation fails, the server returns HTTP 401 Unauthorized automatically +4. If validation succeeds, your handler is called + +### Security Schemes + +The generated code supports: +- **API Key**: Header, query parameter, or cookie-based authentication +- **Bearer Token**: Authorization header with "Bearer" scheme (e.g., JWT) +- **Basic Auth**: HTTP Basic authentication (username:password) +- **OAuth2**: OAuth 2.0 token-based authentication with scope validation + +{{/hasAuthMethods}} +{{^hasAuthMethods}} +This API does not require authentication. + +{{/hasAuthMethods}} + +## Error Handling + +### Response Variants + +Each API endpoint that returns data uses `std::variant` to represent multiple possible response types (success and errors): + +```cpp +// Example: endpoint returns success (User) or errors (NotFound, ServerError) +using GetUserResponse = std::variant; + +GetUserResponse handleGetUser(const GetUserRequest& params) override { + if (userExists(params.m_userId)) { + User user = fetchUser(params.m_userId); + return user; // Automatically sets HTTP 200 + } else { + NotFound error; + error.setMessage("User not found"); + return error; // Automatically sets HTTP 404 + } +} +``` + +The server automatically: +- Detects which type is returned from the variant +- Sets the appropriate HTTP status code +- Serializes the response to JSON + +### HTTP Status Codes + +Status codes are automatically set based on the response type you return. Each model type is associated with a specific HTTP status code defined in your OpenAPI specification. + +**Optimized Status Code Constants:** +The generator only creates HTTP status code constants (e.g., `HTTP_RESPONSE_CODE_200`, `HTTP_RESPONSE_CODE_404`) for codes actually used by your API operations. This reduces code bloat and compilation time compared to generating all possible HTTP status codes. + +### Parameter Validation + +The generated code automatically validates: +- **Required parameters**: Returns HTTP 400 if missing +- **Type conversion**: Returns HTTP 400 if parameter cannot be converted to expected type +- **JSON parsing**: Returns HTTP 400 if request body is invalid JSON + +Custom validation logic should be implemented in your handler methods. + +### Working with Optional Parameters + +Optional parameters and model fields use `std::optional`: + +```cpp +void handleRequest(const RequestParams& params) override { + // Check if optional query parameter is present + if (params.m_optionalParam) { + auto value = *params.m_optionalParam; // Dereference to get value + // Use value... + } + + // Check if optional request body is present + if (params.m_request) { + auto body = *params.m_request; // Dereference to get body + // Use body... + } +} +``` + +## Advanced Features + +### Parameter Serialization Styles + +The generator supports various parameter serialization styles as defined in OpenAPI: + +- **simple**: Comma-separated values (default for path/header) +- **form**: Ampersand-separated values (default for query) +- **spaceDelimited**: Space-separated values +- **pipeDelimited**: Pipe-separated values +- **deepObject**: Nested object notation for query parameters + +These are automatically handled during parameter parsing. + +### Enum Handling + +All generated enums automatically include an `UNSPECIFIED` value as the first enum entry for safe initialization: + +```cpp +enum class Status { + UNSPECIFIED = 0, // Added automatically for safety + PENDING, + APPROVED, + REJECTED +}; + +// Safe default initialization +Status status; // Defaults to UNSPECIFIED (0) + +// Explicit initialization +Status activeStatus = Status::APPROVED; + +// Enum serialization/deserialization +// UNSPECIFIED is not a valid API value and indicates uninitialized state +``` + +**Why UNSPECIFIED?** +- Provides a safe default value for uninitialized enums +- Prevents undefined behavior from using uninitialized enum values +- Makes it clear when an enum hasn't been set vs. having a valid API value +- Does not appear in OpenAPI spec - internal C++ implementation detail + +### Union Types (anyOf/oneOf) + +When your OpenAPI spec uses `anyOf` or `oneOf`, the generated code uses `std::variant`: + +```cpp +// OpenAPI: { "anyOf": [{"type": "string"}, {"type": "number"}] } +using MyUnionType = std::variant; + +// In your model: +MyUnionType value; + +// Use std::visit to handle different types: +std::visit([](const auto& v) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + std::cout << "String: " << v << std::endl; + } else if constexpr (std::is_same_v) { + std::cout << "Number: " << v << std::endl; + } +}, value); +``` + +## Additional Resources + +- [cpp-httplib Documentation](https://github.com/yhirose/cpp-httplib) +- [nlohmann/json Documentation](https://github.com/nlohmann/json) +- [OpenAPI Generator Documentation](https://openapi-generator.tech/docs/generators/cpp-httplib-server) +- [OpenAPI Specification](https://swagger.io/specification/) + +- [cpp-httplib Documentation](https://github.com/yhirose/cpp-httplib) +- [nlohmann/json Documentation](https://github.com/nlohmann/json) +- [OpenAPI Generator Documentation](https://openapi-generator.tech/docs/generators/) diff --git a/modules/openapi-generator/src/main/resources/cpp-httplib-server/api-header.mustache b/modules/openapi-generator/src/main/resources/cpp-httplib-server/api-header.mustache new file mode 100644 index 000000000000..7d3bd0b4a42a --- /dev/null +++ b/modules/openapi-generator/src/main/resources/cpp-httplib-server/api-header.mustache @@ -0,0 +1,128 @@ +{{>License}} + +#pragma once + +// System headers +#include {{#hasAuthMethods}} +#include {{/hasAuthMethods}}{{#includeVariantHeader}} +{{{includeVariantHeader}}}{{/includeVariantHeader}}{{#includeOptionalHeader}} +{{{includeOptionalHeader}}}{{/includeOptionalHeader}} + +// Project headers +{{#modelsUsed}} +#include "models/{{{.}}}.h" +{{/modelsUsed}} + +namespace {{apiNamespace}} { +{{#hasAuthMethods}} + class AuthenticationManager; +{{/hasAuthMethods}} +class {{apiClassnameInPascalCase}} { +public: + {{apiClassnameInPascalCase}}() = default; + virtual ~{{apiClassnameInPascalCase}}() = default; + /** + * @brief Register all routes for this API + * @param svr The httplib::Server instance to register routes on +{{#hasAnyAuth}} + * @param auth The AuthenticationManager for authentication (optional, defaults to nullptr) +{{/hasAnyAuth}} + */ + void registerRoutes(httplib::Server& svr{{#hasAnyAuth}}, std::shared_ptr auth = nullptr{{/hasAnyAuth}}); +{{#operations}} +{{#operation}} +{{#vendorExtensions}} +{{#hasAnyRequestSchema}} +{{#-first}} + // ========================= + // ===== Request types ===== + // ========================= +{{/-first}} + + /** + * @brief Request type for {{handlerFunctionName}}. + */ + struct {{requestType}} + { + {{#requestModel}} + {{{bodyParam.dataType}}} m_request; //Request Body{{#bodyParam.vendorExtensions.isRequired}} (required){{/bodyParam.vendorExtensions.isRequired}}{{^bodyParam.vendorExtensions.isRequired}} (optional){{/bodyParam.vendorExtensions.isRequired}}{{/requestModel}}{{#queryParams}} + {{{dataType}}} m_{{paramName}}; //Query Params{{#vendorExtensions.isRequired}} (required){{/vendorExtensions.isRequired}}{{^vendorExtensions.isRequired}} (optional){{/vendorExtensions.isRequired}}{{/queryParams}}{{#headerParams}} + {{{dataType}}} m_{{paramName}}; //HeaderParams{{#vendorExtensions.isRequired}} (required){{/vendorExtensions.isRequired}}{{^vendorExtensions.isRequired}} (optional){{/vendorExtensions.isRequired}}{{/headerParams}}{{#pathParams}} + {{{dataType}}} m_{{paramName}}; //PathParams (always required){{/pathParams}}{{#cookieParams}} + {{{dataType}}} m_{{paramName}}; //Cookies{{#vendorExtensions.isRequired}} (required){{/vendorExtensions.isRequired}}{{^vendorExtensions.isRequired}} (optional){{/vendorExtensions.isRequired}}{{/cookieParams}} + }; +{{/hasAnyRequestSchema}} +{{/vendorExtensions}} +{{/operation}} +{{/operations}} + +{{#operations}} +{{#operation}} +{{#vendorExtensions}} +{{#hasAnyResponseSchema}} +{{#-first}} + // ========================== + // ===== Response types ===== + // ========================== +{{/-first}} + + /** + * @brief Response type for {{handlerFunctionName}}. + */ +{{#hasSingleResponseType}} + using {{responseType}} = {{singleResponseType}}; +{{/hasSingleResponseType}} +{{^hasSingleResponseType}} + using {{responseType}} = std::variant<{{#successCodeToTypes}}{{#successType}} + {{successType}}{{/successType}}{{#errorCodeToTypes}}{{#-first}} ,{{/-first}}{{/errorCodeToTypes}}{{/successCodeToTypes}}{{^errorCodeToTypes}}>;{{/errorCodeToTypes}}{{#errorCodeToTypes}} + {{#errorType}}{{errorType}}{{/errorType}}{{^-last}} ,{{/-last}}{{#-last}} >;{{/-last}}{{/errorCodeToTypes}} +{{/hasSingleResponseType}} +{{/hasAnyResponseSchema}} +{{/vendorExtensions}} +{{/operation}} +{{/operations}} + // ============================================================ + // ===== Pure virtual functions to be handled by the user ===== + // ============================================================ +{{#operations}} +{{#operation}} +{{#vendorExtensions}} + /** + {{#hasAnyRequestSchema}} + * {{requestType}} - struct containing all the query parameters and headers and schemas as available. + {{/hasAnyRequestSchema}} + {{#hasAnyResponseSchema}} + * @return {{responseType}} The response type returned by the handler. + {{/hasAnyResponseSchema}} + */ + virtual {{#hasAnyResponseSchema}}{{responseType}}{{/hasAnyResponseSchema}}{{^hasAnyResponseSchema}}void{{/hasAnyResponseSchema}} {{handlerFunctionName}}({{#hasAnyRequestSchema}}const {{requestType}}& params{{/hasAnyRequestSchema}})=0; + +{{/vendorExtensions}} +{{/operation}} +{{/operations}} +private: + // ======================================== + // ===== Helper function declarations ===== + // ======================================== +{{#operations}} +{{#operation}} +{{#vendorExtensions}} +{{#hasAnyRequestSchema}} + static bool parse{{operationIdPascalCase}}Params(const httplib::Request& req, {{requestType}}& params, std::vector& paramErrors); +{{/hasAnyRequestSchema}} + void handle{{operationIdPascalCase}}Request(const httplib::Request& req, httplib::Response& res{{#hasAuth}}, std::shared_ptr auth{{/hasAuth}}); +{{#hasAnyResponseSchema}} + static void handle{{responseType}}(const {{responseType}}& result, httplib::Response& res); +{{/hasAnyResponseSchema}} +{{/vendorExtensions}} +{{/operation}} +{{/operations}} +{{#hasAnyAuth}} + static bool performAuthentication( + const httplib::Request& req, + std::shared_ptr auth, + httplib::Response& res); +{{/hasAnyAuth}} +}; + +} // namespace {{apiNamespace}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/cpp-httplib-server/api-impl-header.mustache b/modules/openapi-generator/src/main/resources/cpp-httplib-server/api-impl-header.mustache new file mode 100644 index 000000000000..a0c54ae42549 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/cpp-httplib-server/api-impl-header.mustache @@ -0,0 +1,33 @@ +{{>License}} + +#pragma once + +#include "{{{apiHeaderFileName}}}" + +namespace {{apiNamespace}} { + +/** + * @brief Implementation class for {{apiClassnameInPascalCase}} + * + * This is a stub implementation that you can use as a starting point. + * Override the methods to implement your business logic. + */ +class {{apiClassnameInPascalCase}}Impl : public {{apiClassnameInPascalCase}} { +public: + {{apiClassnameInPascalCase}}Impl() = default; + virtual ~{{apiClassnameInPascalCase}}Impl() = default; + +{{#operations}} +{{#operation}} +{{#vendorExtensions}} + /** + * @brief Implementation stub for {{handlerFunctionName}} + */ + {{#hasAnyResponseSchema}}{{responseType}}{{/hasAnyResponseSchema}}{{^hasAnyResponseSchema}}void{{/hasAnyResponseSchema}} {{handlerFunctionName}}({{#hasAnyRequestSchema}}const {{requestType}}& params{{/hasAnyRequestSchema}}) override; + +{{/vendorExtensions}} +{{/operation}} +{{/operations}} +}; + +} // namespace {{apiNamespace}} diff --git a/modules/openapi-generator/src/main/resources/cpp-httplib-server/api-impl.mustache b/modules/openapi-generator/src/main/resources/cpp-httplib-server/api-impl.mustache new file mode 100644 index 000000000000..7ffdcd8209c3 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/cpp-httplib-server/api-impl.mustache @@ -0,0 +1,40 @@ +{{>License}} + +#include "{{{apiClassnameInPascalCase}}}ApiImpl.h" +#include + +namespace {{apiNamespace}} { + +{{#operations}} +{{#operation}} +{{#vendorExtensions}} +/** + * Implementation stub for {{handlerFunctionName}} + * TODO: Implement your business logic here + */ +{{#hasAnyResponseSchema}}{{classname}}::{{responseType}}{{/hasAnyResponseSchema}}{{^hasAnyResponseSchema}}void{{/hasAnyResponseSchema}} {{classname}}::{{handlerFunctionName}}({{#hasAnyRequestSchema}}const {{classname}}::{{requestType}}& params{{/hasAnyRequestSchema}}) +{ + // TODO: Implement your business logic here + {{#hasAnyResponseSchema}} + {{#hasSingleResponseType}} + // Return a default/stub response + {{responseType}} response; + // Initialize response fields as needed + return response; + {{/hasSingleResponseType}} + {{^hasSingleResponseType}} + // Return first success type as default + {{#successCodeToTypes}}{{#-first}} + {{successType}} response; + // Initialize response fields as needed + return response; + {{/-first}}{{/successCodeToTypes}} + {{/hasSingleResponseType}} + {{/hasAnyResponseSchema}} +} + +{{/vendorExtensions}} +{{/operation}} +{{/operations}} + +} // namespace {{apiNamespace}} diff --git a/modules/openapi-generator/src/main/resources/cpp-httplib-server/api-source.mustache b/modules/openapi-generator/src/main/resources/cpp-httplib-server/api-source.mustache new file mode 100644 index 000000000000..a2663ab91ab7 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/cpp-httplib-server/api-source.mustache @@ -0,0 +1,756 @@ +{{>License}} + +// System headers +#include +#include +#include {{#operations}}{{#operation}}{{#vendorExtensions}}{{#hasAnyRequestSchema}}{{#hasArrayParams}}{{#-first}} +#include {{/-first}}{{/hasArrayParams}}{{/hasAnyRequestSchema}}{{/vendorExtensions}}{{/operation}}{{/operations}} + +// Project headers +#include "{{{apiHeaderFileName}}}"{{#hasAnyAuth}} +#include "AuthenticationManager.h"{{/hasAnyAuth}} + +{{#statusCodeConsts}} +constexpr int {{constName}} = {{statusCode}}; +{{/statusCodeConsts}} + +namespace {{apiNamespace}} { + +using namespace {{modelNamespace}}; + +{{#operations}} +{{#operation}} +{{#vendorExtensions}} +{{#hasAnyRequestSchema}} +bool {{apiClassnameInPascalCase}}::parse{{operationIdPascalCase}}Params(const httplib::Request& req, {{apiClassnameInPascalCase}}::{{requestType}}& params, std::vector& paramErrors) +{ + std::vector errors; +{{#requestModel}} + if (!req.body.empty()) + { + try + { + nlohmann::json json = nlohmann::json::parse(req.body); +{{#bodyParam.vendorExtensions.isOptional}} + {{{bodyParam.baseType}}} temp; + from_json(json, temp); + params.m_request = temp; +{{/bodyParam.vendorExtensions.isOptional}} +{{^bodyParam.vendorExtensions.isOptional}} + from_json(json, params.m_request); +{{/bodyParam.vendorExtensions.isOptional}} + } + catch (const std::exception& e) + { + errors.push_back("Invalid request body: " + std::string(e.what())); + } + }{{#bodyParam.vendorExtensions.isRequired}} + else + { + errors.push_back("Missing required request body"); + }{{/bodyParam.vendorExtensions.isRequired}} +{{/requestModel}} +{{#queryParams}} +{{#-first}} + +{{/-first}} + // Query Parameters - {{baseName}} + if (req.has_param("{{baseName}}")) + { + {{#vendorExtensions.isObject}}try + { + {{#vendorExtensions.isDeepObject}}// deepObject: parse as JSON object from multiple keys + nlohmann::json obj; + for (const auto& [k, v] : req.params) + { + if (k.find("{{baseName}}[") == 0) + { + std::string field = k.substr(std::string("{{baseName}}[").size(), k.size() - std::string("{{baseName}}[").size() - 1); + obj[field] = v; + } + } + params.m_{{paramName}} = obj.get<{{{vendorExtensions.unwrappedDataType}}}>();{{/vendorExtensions.isDeepObject}}{{^vendorExtensions.isDeepObject}}// Parse JSON object from query + auto val = req.get_param_value("{{baseName}}", 0); + params.m_{{paramName}} = nlohmann::json::parse(val).get<{{{vendorExtensions.unwrappedDataType}}}>();{{/vendorExtensions.isDeepObject}} + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isObject}}{{#vendorExtensions.isArray}}try + { + {{#vendorExtensions.isSpaceDelimited}}// spaceDelimited: split by space + auto val = req.get_param_value("{{baseName}}", 0); + std::stringstream ss(val); + std::string item;{{#vendorExtensions.isOptional}} + if (!params.m_{{paramName}}.has_value()) + { + params.m_{{paramName}} = std::vector<{{{items.dataType}}}>{}; + }{{/vendorExtensions.isOptional}} + while (std::getline(ss, item, ' ')) + { + if (!item.empty()) + { +{{#vendorExtensions.isOptional}} + params.m_{{paramName}}->emplace_back(item); +{{/vendorExtensions.isOptional}} +{{^vendorExtensions.isOptional}} + params.m_{{paramName}}.emplace_back(item); +{{/vendorExtensions.isOptional}} + } + }{{/vendorExtensions.isSpaceDelimited}}{{#vendorExtensions.isPipeDelimited}}// pipeDelimited: split by | + auto val = req.get_param_value("{{baseName}}", 0); + std::stringstream ss(val); + std::string item;{{#vendorExtensions.isOptional}} + if (!params.m_{{paramName}}.has_value()) + { + params.m_{{paramName}} = std::vector<{{{items.dataType}}}>{}; + }{{/vendorExtensions.isOptional}} + while (std::getline(ss, item, '|')) + { + if (!item.empty()) + { +{{#vendorExtensions.isOptional}} + params.m_{{paramName}}->emplace_back(item); +{{/vendorExtensions.isOptional}} +{{^vendorExtensions.isOptional}} + params.m_{{paramName}}.emplace_back(item); +{{/vendorExtensions.isOptional}} + } + }{{/vendorExtensions.isPipeDelimited}}{{^vendorExtensions.isSpaceDelimited}}{{^vendorExtensions.isPipeDelimited}}// form/simple: multi-param or comma-separated + size_t count = req.get_param_value_count("{{baseName}}");{{#vendorExtensions.isOptional}} + if (!params.m_{{paramName}}.has_value()) + { + params.m_{{paramName}} = std::vector<{{{items.dataType}}}>{}; + }{{/vendorExtensions.isOptional}} + if (count > 1) + { + for (size_t i = 0; i < count; ++i) + { + auto val = req.get_param_value("{{baseName}}", i); +{{#items.vendorExtensions.isInt}} +{{#vendorExtensions.isOptional}} + params.m_{{paramName}}->emplace_back(std::stoi(val)); +{{/vendorExtensions.isOptional}} +{{^vendorExtensions.isOptional}} + params.m_{{paramName}}.emplace_back(std::stoi(val)); +{{/vendorExtensions.isOptional}} +{{/items.vendorExtensions.isInt}} +{{#items.vendorExtensions.isLong}} +{{#vendorExtensions.isOptional}} + params.m_{{paramName}}->emplace_back(std::stol(val)); +{{/vendorExtensions.isOptional}} +{{^vendorExtensions.isOptional}} + params.m_{{paramName}}.emplace_back(std::stol(val)); +{{/vendorExtensions.isOptional}} +{{/items.vendorExtensions.isLong}} +{{#items.vendorExtensions.isDouble}} +{{#vendorExtensions.isOptional}} + params.m_{{paramName}}->emplace_back(std::stod(val)); +{{/vendorExtensions.isOptional}} +{{^vendorExtensions.isOptional}} + params.m_{{paramName}}.emplace_back(std::stod(val)); +{{/vendorExtensions.isOptional}} +{{/items.vendorExtensions.isDouble}} +{{#items.vendorExtensions.isFloat}} +{{#vendorExtensions.isOptional}} + params.m_{{paramName}}->emplace_back(std::stof(val)); +{{/vendorExtensions.isOptional}} +{{^vendorExtensions.isOptional}} + params.m_{{paramName}}.emplace_back(std::stof(val)); +{{/vendorExtensions.isOptional}} +{{/items.vendorExtensions.isFloat}} +{{^items.vendorExtensions.isInt}}{{^items.vendorExtensions.isLong}}{{^items.vendorExtensions.isDouble}}{{^items.vendorExtensions.isFloat}} +{{#vendorExtensions.isOptional}} + params.m_{{paramName}}->emplace_back(val); +{{/vendorExtensions.isOptional}} +{{^vendorExtensions.isOptional}} + params.m_{{paramName}}.emplace_back(val); +{{/vendorExtensions.isOptional}} +{{/items.vendorExtensions.isFloat}}{{/items.vendorExtensions.isDouble}}{{/items.vendorExtensions.isLong}}{{/items.vendorExtensions.isInt}} + } + } + else if (count == 1) + { + auto val = req.get_param_value("{{baseName}}", 0); + std::stringstream ss(val); + std::string item; + while (std::getline(ss, item, ',')) + { + if (!item.empty()) + { +{{#items.vendorExtensions.isInt}} +{{#vendorExtensions.isOptional}} + params.m_{{paramName}}->emplace_back(std::stoi(item)); +{{/vendorExtensions.isOptional}} +{{^vendorExtensions.isOptional}} + params.m_{{paramName}}.emplace_back(std::stoi(item)); +{{/vendorExtensions.isOptional}} +{{/items.vendorExtensions.isInt}} +{{#items.vendorExtensions.isLong}} +{{#vendorExtensions.isOptional}} + params.m_{{paramName}}->emplace_back(std::stol(item)); +{{/vendorExtensions.isOptional}} +{{^vendorExtensions.isOptional}} + params.m_{{paramName}}.emplace_back(std::stol(item)); +{{/vendorExtensions.isOptional}} +{{/items.vendorExtensions.isLong}} +{{#items.vendorExtensions.isDouble}} +{{#vendorExtensions.isOptional}} + params.m_{{paramName}}->emplace_back(std::stod(item)); +{{/vendorExtensions.isOptional}} +{{^vendorExtensions.isOptional}} + params.m_{{paramName}}.emplace_back(std::stod(item)); +{{/vendorExtensions.isOptional}} +{{/items.vendorExtensions.isDouble}} +{{#items.vendorExtensions.isFloat}} +{{#vendorExtensions.isOptional}} + params.m_{{paramName}}->emplace_back(std::stof(item)); +{{/vendorExtensions.isOptional}} +{{^vendorExtensions.isOptional}} + params.m_{{paramName}}.emplace_back(std::stof(item)); +{{/vendorExtensions.isOptional}} +{{/items.vendorExtensions.isFloat}} +{{^items.vendorExtensions.isInt}}{{^items.vendorExtensions.isLong}}{{^items.vendorExtensions.isDouble}}{{^items.vendorExtensions.isFloat}} +{{#vendorExtensions.isOptional}} + params.m_{{paramName}}->emplace_back(item); +{{/vendorExtensions.isOptional}} +{{^vendorExtensions.isOptional}} + params.m_{{paramName}}.emplace_back(item); +{{/vendorExtensions.isOptional}} +{{/items.vendorExtensions.isFloat}}{{/items.vendorExtensions.isDouble}}{{/items.vendorExtensions.isLong}}{{/items.vendorExtensions.isInt}} + } + } + }{{/vendorExtensions.isPipeDelimited}}{{/vendorExtensions.isSpaceDelimited}} + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isArray}}{{#vendorExtensions.isEnum}}try + { + params.m_{{paramName}} = {{enumFromStringHelper}}(req.get_param_value("{{baseName}}")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isEnum}}{{#vendorExtensions.isString}}params.m_{{paramName}} = req.get_param_value("{{baseName}}"){{#vendorExtensions.isMatrix}}.substr(1){{/vendorExtensions.isMatrix}}{{#vendorExtensions.isLabel}}.substr(1){{/vendorExtensions.isLabel}};{{/vendorExtensions.isString}}{{#vendorExtensions.isInt}}try + { + params.m_{{paramName}} = std::stoi(req.get_param_value("{{baseName}}")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isInt}}{{#vendorExtensions.isLong}}try + { + params.m_{{paramName}} = std::stoll(req.get_param_value("{{baseName}}")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isLong}}{{#vendorExtensions.isBool}}try + { + params.m_{{paramName}} = (req.get_param_value("{{baseName}}") == "true"); + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isBool}}{{#vendorExtensions.isDouble}}try + { + params.m_{{paramName}} = std::stod(req.get_param_value("{{baseName}}")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isDouble}}{{#vendorExtensions.isFloat}}try + { + params.m_{{paramName}} = std::stof(req.get_param_value("{{baseName}}")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isFloat}}{{^vendorExtensions.isObject}}{{^vendorExtensions.isArray}}{{^vendorExtensions.isEnum}}{{^vendorExtensions.isString}}{{^vendorExtensions.isInt}}{{^vendorExtensions.isLong}}{{^vendorExtensions.isBool}}{{^vendorExtensions.isDouble}}{{^vendorExtensions.isFloat}}// Fallback: direct assignment + params.m_{{paramName}} = req.get_param_value("{{baseName}}");{{/vendorExtensions.isFloat}}{{/vendorExtensions.isDouble}}{{/vendorExtensions.isBool}}{{/vendorExtensions.isLong}}{{/vendorExtensions.isInt}}{{/vendorExtensions.isString}}{{/vendorExtensions.isEnum}}{{/vendorExtensions.isArray}}{{/vendorExtensions.isObject}} + }{{^vendorExtensions.isRequired}}{{#vendorExtensions.hasDefaultValue}} + else + { + // Use default value for optional parameter + params.m_{{paramName}} = {{{vendorExtensions.defaultValue}}}; + }{{/vendorExtensions.hasDefaultValue}}{{/vendorExtensions.isRequired}} +{{/queryParams}} +{{#headerParams}} +{{#-first}} + +{{/-first}} + // Header Parameters - {{baseName}} + if (!req.get_header_value("{{baseName}}").empty()) + { + {{#vendorExtensions.isObject}}try + { + // Parse JSON object from header + auto val = req.get_header_value("{{baseName}}"); + params.m_{{paramName}} = nlohmann::json::parse(val); + } + catch (const std::exception& e) + { + errors.push_back("Invalid header parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isObject}}{{#vendorExtensions.isArray}}try + { + // Header arrays may be comma-separated + auto val = req.get_header_value("{{baseName}}"); + std::stringstream ss(val); + std::string item;{{#vendorExtensions.isOptional}} + if (!params.m_{{paramName}}.has_value()) + { + params.m_{{paramName}} = std::vector<{{{items.dataType}}}>{}; + }{{/vendorExtensions.isOptional}} + while (std::getline(ss, item, ',')) + { + if (!item.empty()) + { +{{#vendorExtensions.isOptional}} + params.m_{{paramName}}->emplace_back(item); +{{/vendorExtensions.isOptional}} +{{^vendorExtensions.isOptional}} + params.m_{{paramName}}.emplace_back(item); +{{/vendorExtensions.isOptional}} + } + } + } + catch (const std::exception& e) + { + errors.push_back("Invalid header parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isArray}}{{#vendorExtensions.isEnum}}try + { + params.m_{{paramName}} = {{enumFromStringHelper}}(req.get_header_value("{{baseName}}")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid header parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isEnum}}{{#vendorExtensions.isString}}params.m_{{paramName}} = req.get_header_value("{{baseName}}");{{/vendorExtensions.isString}}{{#vendorExtensions.isInt}}try + { + params.m_{{paramName}} = std::stoi(req.get_header_value("{{baseName}}")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid header parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isInt}}{{#vendorExtensions.isLong}}try + { + params.m_{{paramName}} = std::stoll(req.get_header_value("{{baseName}}")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid header parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isLong}}{{#vendorExtensions.isBool}}try + { + params.m_{{paramName}} = (req.get_header_value("{{baseName}}") == "true"); + } + catch (const std::exception& e) + { + errors.push_back("Invalid header parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isBool}}{{#vendorExtensions.isDouble}}try + { + params.m_{{paramName}} = std::stod(req.get_header_value("{{baseName}}")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid header parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isDouble}}{{#vendorExtensions.isFloat}}try + { + params.m_{{paramName}} = std::stof(req.get_header_value("{{baseName}}")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid header parameter '{{baseName}}': " + std::string(e.what())); + }{{/vendorExtensions.isFloat}}{{^vendorExtensions.isObject}}{{^vendorExtensions.isArray}}{{^vendorExtensions.isEnum}}{{^vendorExtensions.isString}}{{^vendorExtensions.isInt}}{{^vendorExtensions.isLong}}{{^vendorExtensions.isBool}}{{^vendorExtensions.isDouble}}{{^vendorExtensions.isFloat}}// Fallback: direct assignment + params.m_{{paramName}} = req.get_header_value("{{baseName}}");{{/vendorExtensions.isFloat}}{{/vendorExtensions.isDouble}}{{/vendorExtensions.isBool}}{{/vendorExtensions.isLong}}{{/vendorExtensions.isInt}}{{/vendorExtensions.isString}}{{/vendorExtensions.isEnum}}{{/vendorExtensions.isArray}}{{/vendorExtensions.isObject}} + }{{^vendorExtensions.isRequired}}{{#vendorExtensions.hasDefaultValue}} + else + { + // Use default value for optional parameter + params.m_{{paramName}} = {{{vendorExtensions.defaultValue}}}; + }{{/vendorExtensions.hasDefaultValue}}{{/vendorExtensions.isRequired}} +{{/headerParams}} +{{#pathParams}} +{{#-first}} + +{{/-first}} + // Path Parameters - {{baseName}} (index: {{vendorExtensions.pathIndex}}) + if (req.matches.size() < {{vendorExtensions.pathIndex}} + 1) + { + errors.push_back("Missing path parameter '{{baseName}}'"); + } + else + { + try + { + {{#vendorExtensions.isObject}} + // Parse JSON object from path param (rare) + auto val = req.matches[{{vendorExtensions.pathIndex}}]; + params.m_{{paramName}} = nlohmann::json::parse(val); + {{/vendorExtensions.isObject}} + {{#vendorExtensions.isArray}} + // Path arrays may be delimited (e.g., comma, pipe, etc.) + auto val = req.matches[{{vendorExtensions.pathIndex}}]; + std::stringstream ss(val); + std::string item;{{#vendorExtensions.isOptional}} + if (!params.m_{{paramName}}.has_value()) + { + params.m_{{paramName}} = std::vector<{{{items.dataType}}}>{}; + }{{/vendorExtensions.isOptional}} + while (std::getline(ss, item, ',')) + { + if (!item.empty()) + { +{{#vendorExtensions.isOptional}} + params.m_{{paramName}}->emplace_back(item); +{{/vendorExtensions.isOptional}} +{{^vendorExtensions.isOptional}} + params.m_{{paramName}}.emplace_back(item); +{{/vendorExtensions.isOptional}} + } + } + {{/vendorExtensions.isArray}} + {{#vendorExtensions.isEnum}} + params.m_{{paramName}} = {{enumFromStringHelper}}(req.matches[{{vendorExtensions.pathIndex}}]); + {{/vendorExtensions.isEnum}} + {{#vendorExtensions.isString}} + params.m_{{paramName}} = req.matches[{{vendorExtensions.pathIndex}}]; + {{/vendorExtensions.isString}} + {{#vendorExtensions.isInt}} + params.m_{{paramName}} = std::stoi(req.matches[{{vendorExtensions.pathIndex}}]); + {{/vendorExtensions.isInt}} + {{#vendorExtensions.isLong}} + params.m_{{paramName}} = std::stoll(req.matches[{{vendorExtensions.pathIndex}}]); + {{/vendorExtensions.isLong}} + {{#vendorExtensions.isBool}} + params.m_{{paramName}} = (req.matches[{{vendorExtensions.pathIndex}}] == "true"); + {{/vendorExtensions.isBool}} + {{#vendorExtensions.isDouble}} + params.m_{{paramName}} = std::stod(req.matches[{{vendorExtensions.pathIndex}}]); + {{/vendorExtensions.isDouble}} + {{#vendorExtensions.isFloat}} + params.m_{{paramName}} = std::stof(req.matches[{{vendorExtensions.pathIndex}}]); + {{/vendorExtensions.isFloat}} + } + catch (const std::exception& e) + { + errors.push_back("Invalid path parameter '{{baseName}}': " + std::string(e.what())); + } + } +{{/pathParams}} +{{#cookieParams}} +{{#-first}} + +{{/-first}} + // Cookie Parameters - {{baseName}} + try + { + auto cookieHeader = req.get_header_value("Cookie"); + if (!cookieHeader.empty()) + { + std::string cookieValue; + std::string key = "{{baseName}}="; + size_t start = cookieHeader.find(key); + if (start != std::string::npos) + { + start += key.length(); + size_t end = cookieHeader.find(";", start); + if (end == std::string::npos) end = cookieHeader.length(); + cookieValue = cookieHeader.substr(start, end - start); + {{#vendorExtensions.isObject}}params.m_{{paramName}} = nlohmann::json::parse(cookieValue);{{/vendorExtensions.isObject}}{{#vendorExtensions.isArray}}{{#vendorExtensions.isOptional}} + if (!params.m_{{paramName}}.has_value()) + { + params.m_{{paramName}} = std::vector<{{{items.dataType}}}>{}; + }{{/vendorExtensions.isOptional}} + std::stringstream ss(cookieValue); + std::string item; + while (std::getline(ss, item, ',')) + { + if (!item.empty()) + { +{{#vendorExtensions.isOptional}} + params.m_{{paramName}}->emplace_back(item); +{{/vendorExtensions.isOptional}} +{{^vendorExtensions.isOptional}} + params.m_{{paramName}}.emplace_back(item); +{{/vendorExtensions.isOptional}} + } + }{{/vendorExtensions.isArray}}{{#vendorExtensions.isEnum}}params.m_{{paramName}} = {{enumFromStringHelper}}(cookieValue);{{/vendorExtensions.isEnum}}{{#vendorExtensions.isString}}params.m_{{paramName}} = cookieValue;{{/vendorExtensions.isString}}{{#vendorExtensions.isInt}}params.m_{{paramName}} = std::stoi(cookieValue);{{/vendorExtensions.isInt}}{{#vendorExtensions.isLong}}params.m_{{paramName}} = std::stoll(cookieValue);{{/vendorExtensions.isLong}}{{#vendorExtensions.isBool}}params.m_{{paramName}} = (cookieValue == "true");{{/vendorExtensions.isBool}}{{#vendorExtensions.isDouble}}params.m_{{paramName}} = std::stod(cookieValue);{{/vendorExtensions.isDouble}}{{#vendorExtensions.isFloat}}params.m_{{paramName}} = std::stof(cookieValue);{{/vendorExtensions.isFloat}}{{^vendorExtensions.isObject}}{{^vendorExtensions.isArray}}{{^vendorExtensions.isEnum}}{{^vendorExtensions.isString}}{{^vendorExtensions.isInt}}{{^vendorExtensions.isLong}}{{^vendorExtensions.isBool}}{{^vendorExtensions.isDouble}}{{^vendorExtensions.isFloat}}params.m_{{paramName}} = cookieValue;{{/vendorExtensions.isFloat}}{{/vendorExtensions.isDouble}}{{/vendorExtensions.isBool}}{{/vendorExtensions.isLong}}{{/vendorExtensions.isInt}}{{/vendorExtensions.isString}}{{/vendorExtensions.isEnum}}{{/vendorExtensions.isArray}}{{/vendorExtensions.isObject}} + }{{^vendorExtensions.isRequired}}{{#vendorExtensions.hasDefaultValue}} + else + { + // Use default value for optional parameter + params.m_{{paramName}} = {{{vendorExtensions.defaultValue}}}; + }{{/vendorExtensions.hasDefaultValue}}{{/vendorExtensions.isRequired}} + }{{^vendorExtensions.isRequired}}{{#vendorExtensions.hasDefaultValue}} + else + { + // Use default value for optional parameter + params.m_{{paramName}} = {{{vendorExtensions.defaultValue}}}; + }{{/vendorExtensions.hasDefaultValue}}{{/vendorExtensions.isRequired}} + } + catch (const std::exception& e) + { + errors.push_back("Invalid cookie parameter '{{baseName}}': " + std::string(e.what())); + } +{{/cookieParams}} + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +{{/hasAnyRequestSchema}} +{{#hasAnyResponseSchema}} +void {{apiClassnameInPascalCase}}::handle{{responseType}}(const {{responseType}}& result, httplib::Response& res) +{ +{{#hasSingleResponseType}} + // Single response type + res.status = {{#successCodeToTypes}}{{successConstName}}{{/successCodeToTypes}}{{#errorCodeToTypes}}{{errorConstName}}{{/errorCodeToTypes}}; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +{{/hasSingleResponseType}} +{{^hasSingleResponseType}} + std::visit([&](const auto& value) + { + using T = std::decay_t; +{{#successCodeToTypes}}{{#-first}} + // Success types + {{/-first}}{{^-first}}else {{/-first}}if constexpr (std::is_same_v) + { + res.status = {{successConstName}}; + nlohmann::json responseJson; + to_json(responseJson, value); + res.set_content(responseJson.dump(), "application/json"); + }{{/successCodeToTypes}}{{#errorCodeToTypes}}{{#-first}} + // Error types{{/-first}} + else if constexpr (std::is_same_v) + { + res.status = {{errorConstName}}; + nlohmann::json errorJson = value; + res.set_content(errorJson.dump(), "application/json"); + }{{/errorCodeToTypes}}{{^successCodeToTypes}}{{^errorCodeToTypes}} + // No response types defined + res.status = {{statusCodeToConst.500}}; + res.set_content("{\"error\": \"No response handler defined\"}", "application/json"); +{{/errorCodeToTypes}}{{/successCodeToTypes}} + }, result); +{{/hasSingleResponseType}} +} +{{/hasAnyResponseSchema}} +{{/vendorExtensions}} +{{/operation}} +{{/operations}} + +{{#hasAnyAuth}} +bool {{apiClassnameInPascalCase}}::performAuthentication( + const httplib::Request& req, + std::shared_ptr auth, + httplib::Response& res) +{ + if (!auth) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "AuthenticationManager not configured"; + res.status = {{statusCodeToConst.500}}; + res.set_content(errorJson.dump(), "application/json"); + return false; + } + + {{#hasApiKeyAuth}} + {{#apiKeyAuth}} + {{#isKeyInHeader}} + if (req.has_header("{{keyParamName}}")) + { + if (auth->validateApiKey(req.get_header_value("{{keyParamName}}"))) return true; + } + {{/isKeyInHeader}} + {{#isKeyInQuery}} + if (req.has_param("{{keyParamName}}")) + { + if (auth->validateApiKey(req.get_param_value("{{keyParamName}}"))) return true; + } + {{/isKeyInQuery}} + {{#isKeyInCookie}} + { + auto cookieHeader = req.get_header_value("Cookie"); + std::string key = "{{keyParamName}}="; + size_t start = cookieHeader.find(key); + if (start != std::string::npos) + { + start += key.length(); + size_t end = cookieHeader.find(";", start); + if (end == std::string::npos) end = cookieHeader.length(); + std::string cookieValue = cookieHeader.substr(start, end - start); + if (auth->validateApiKey(cookieValue)) return true; + } + } + {{/isKeyInCookie}} + {{/apiKeyAuth}} + {{/hasApiKeyAuth}} + + {{#hasBasicAuth}} + if (req.has_header("Authorization")) + { + auto authHeader = req.get_header_value("Authorization"); + if (authHeader.find("Basic ") == 0) + { + std::string credentials = authHeader.substr(6); + if (auth->validateBasicAuth(credentials, "")) return true; + } + } + {{/hasBasicAuth}} + + {{#hasBearerAuth}} + if (req.has_header("Authorization")) + { + auto authHeader = req.get_header_value("Authorization"); + if (authHeader.find("Bearer ") == 0) + { + std::string token = authHeader.substr(7); + if (auth->validateBearerToken(token)) return true; + } + } + {{/hasBearerAuth}} + + {{#hasOAuth2}} + if (req.has_header("Authorization")) + { + auto authHeader = req.get_header_value("Authorization"); + if (authHeader.find("Bearer ") == 0) + { + std::string token = authHeader.substr(7); + {{#oauth2Auth}} + std::vector requiredScopes = { {{#scopes}}"{{scope}}"{{^-last}}, {{/-last}}{{/scopes}} }; + if (auth->validateOAuth2(token, requiredScopes)) return true; + {{/oauth2Auth}} + } + } + {{/hasOAuth2}} + + return false; +} +{{/hasAnyAuth}} + +{{#operations}} +{{#operation}} +{{#vendorExtensions}} +void {{apiClassnameInPascalCase}}::handle{{operationIdPascalCase}}Request([[maybe_unused]] const httplib::Request& req, httplib::Response& res{{#hasAuth}}, std::shared_ptr auth{{/hasAuth}}) +{ + try + { +{{#hasAuth}} + if (!performAuthentication(req, auth, res)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Authentication required"; + res.status = {{statusCodeToConst.401}}; + res.set_content(errorJson.dump(), "application/json"); + return; + } +{{/hasAuth}}{{#hasAnyRequestSchema}} + {{requestType}} params; + std::vector paramErrors; + if (!parse{{operationIdPascalCase}}Params(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = {{statusCodeToConst.400}}; + res.set_content(errorJson.dump(), "application/json"); + return; + } +{{#hasAnyResponseSchema}} + auto result = {{handlerFunctionName}}(params); + handle{{responseType}}(result, res); +{{/hasAnyResponseSchema}}{{^hasAnyResponseSchema}} + {{handlerFunctionName}}(params); + res.status = {{statusCodeToConst.204}}; +{{/hasAnyResponseSchema}}{{/hasAnyRequestSchema}}{{^hasAnyRequestSchema}}{{#hasAnyResponseSchema}} + auto result = {{handlerFunctionName}}(); + handle{{responseType}}(result, res); +{{/hasAnyResponseSchema}}{{^hasAnyResponseSchema}} + {{handlerFunctionName}}(); + res.status = {{statusCodeToConst.204}}; +{{/hasAnyResponseSchema}}{{/hasAnyRequestSchema}} + }{{#requestModel}} + catch (const nlohmann::json::parse_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = {{statusCodeToConst.400}}; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::invalid_iterator& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = {{statusCodeToConst.400}}; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::type_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = {{statusCodeToConst.400}}; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = {{statusCodeToConst.400}}; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::other_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = {{statusCodeToConst.400}}; + res.set_content(errorJson.dump(), "application/json"); + }{{/requestModel}}{{#vendorExtensions.hasPrimitiveParams}} + catch (const std::invalid_argument& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameter: " + std::string(e.what()); + res.status = {{statusCodeToConst.400}}; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const std::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameter: " + std::string(e.what()); + res.status = {{statusCodeToConst.400}}; + res.set_content(errorJson.dump(), "application/json"); + }{{/vendorExtensions.hasPrimitiveParams}}{{^requestModel}}{{^vendorExtensions.hasPrimitiveParams}} + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = {{statusCodeToConst.500}}; + res.set_content(errorJson.dump(), "application/json"); + }{{/vendorExtensions.hasPrimitiveParams}}{{/requestModel}} +} + +{{/vendorExtensions}} +{{/operation}} +{{/operations}} + +void {{apiClassnameInPascalCase}}::registerRoutes(httplib::Server& svr{{#hasAnyAuth}}, std::shared_ptr auth{{/hasAnyAuth}}) +{ + {{#operations}} + {{#operation}} + {{#vendorExtensions}} + svr.{{httpMethod}}("{{path}}", [this{{#hasAuth}}, auth{{/hasAuth}}]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handle{{operationIdPascalCase}}Request(req, res{{#hasAuth}}, auth{{/hasAuth}}); + }); + {{/vendorExtensions}} + {{/operation}} + {{/operations}} +} + +} // namespace {{apiNamespace}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/cpp-httplib-server/main.mustache b/modules/openapi-generator/src/main/resources/cpp-httplib-server/main.mustache new file mode 100644 index 000000000000..c3b12ffc5640 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/cpp-httplib-server/main.mustache @@ -0,0 +1,94 @@ +{{>License}} + +#include +#include +#include +{{#apiInfo}} +{{#apis}} +{{#operations}} +#include "api/{{apiClassnameInPascalCase}}Impl.h" +{{/operations}} +{{/apis}} +{{/apiInfo}} +{{#hasAuthMethods}} +#include "api/AuthenticationManager.h" + +// Example AuthenticationManager implementation +class SimpleAuthManager : public {{#apiInfo}}{{#apis}}{{#-first}}{{apiNamespace}}{{/-first}}{{/apis}}{{/apiInfo}}::AuthenticationManager { +public: + bool validateApiKey(const std::string& key) override { + // TODO: Implement your API key validation logic + return key == "your-api-key"; // Replace with actual validation + } + + bool validateBearerToken(const std::string& token) override { + // TODO: Implement your Bearer token validation logic + return !token.empty(); // Replace with actual validation + } + + bool validateBasicAuth(const std::string& username, const std::string& password) override { + // TODO: Implement your Basic auth validation logic + return username == "admin" && password == "admin"; // Replace with actual validation + } + + bool validateOAuth2(const std::string& token, const std::vector& scopes) override { + // TODO: Implement your OAuth2 validation logic + return !token.empty(); // Replace with actual validation + } +}; +{{/hasAuthMethods}} + +int main() { + httplib::Server svr; + + std::cout << "Starting {{projectName}} server..." << std::endl; + +{{#hasAuthMethods}} + // Create authentication manager + auto authManager = std::make_shared(); +{{/hasAuthMethods}} + +{{#apiInfo}} +{{#apis}} +{{#operations}} + // Register {{apiClassnameInPascalCase}} routes + auto {{#lambda.camelcase}}{{apiClassnameInPascalCase}}{{/lambda.camelcase}}Impl = std::make_shared<{{apiNamespace}}::{{apiClassnameInPascalCase}}Impl>(); + {{#lambda.camelcase}}{{apiClassnameInPascalCase}}{{/lambda.camelcase}}Impl->registerRoutes(svr{{#hasAnyAuth}}, authManager{{/hasAnyAuth}}); +{{/operations}} +{{/apis}} +{{/apiInfo}} + + // Health check endpoint + svr.Get("/health", [](const httplib::Request&, httplib::Response& res) { + res.set_content("{\"status\": \"ok\"}", "application/json"); + }); + + // Configure server + const char* host = "0.0.0.0"; + int port = 8080; + + // Get port from environment variable if available + const char* portEnv = std::getenv("PORT"); + if (portEnv != nullptr) + { + try + { + port = std::stoi(portEnv); + } + catch (...) + { + std::cerr << "Invalid PORT environment variable, using default: " << port << std::endl; + } + } + + std::cout << "Server listening on " << host << ":" << port << std::endl; + std::cout << "Health check available at: http://" << host << ":" << port << "/health" << std::endl; + + // Start server + if (!svr.listen(host, port)) { + std::cerr << "Failed to start server on " << host << ":" << port << std::endl; + return 1; + } + + return 0; +} diff --git a/modules/openapi-generator/src/main/resources/cpp-httplib-server/model-header.mustache b/modules/openapi-generator/src/main/resources/cpp-httplib-server/model-header.mustache new file mode 100644 index 000000000000..c109c8ec073c --- /dev/null +++ b/modules/openapi-generator/src/main/resources/cpp-httplib-server/model-header.mustache @@ -0,0 +1,249 @@ +{{>License}} + +#pragma once +{{#models}} +{{#model}} +// System headers +#include +{{#vendorExtensions.filteredImports}} +{{{.}}} +{{/vendorExtensions.filteredImports}} + + +{{#parent}}{{#-first}}// Project headers{{/-first}} +#include "{{parent}}.h" +{{/parent}} + +namespace {{vendorExtensions.modelNamespace}} { + +{{#vendorExtensions.isOneOfSchema}} +// oneOf schema - type alias for std::variant +using {{vendorExtensions.modelClassName}} = std::variant< + {{#vendorExtensions.oneOfTypes}}{{.}}{{^-last}}, + {{/-last}}{{/vendorExtensions.oneOfTypes}}>; + +// JSON serialization functions (inline for header-only) +{{#vendorExtensions.discriminatorProperty}} +inline void from_json(const nlohmann::json& j, {{vendorExtensions.modelClassName}}& obj) { + if (!j.contains("{{vendorExtensions.discriminatorProperty}}")) { + throw nlohmann::json::type_error::create(302, "Discriminator property '{{vendorExtensions.discriminatorProperty}}' not found in JSON", &j); + } + std::string discriminatorValue = j["{{vendorExtensions.discriminatorProperty}}"].get(); + {{#vendorExtensions.discriminatorMapping}} + if (discriminatorValue == "{{value}}") { + obj = j.get<{{key}}>(); + return; + } + {{/vendorExtensions.discriminatorMapping}} + throw nlohmann::json::type_error::create(302, "Unknown discriminator value: " + discriminatorValue, &j); +} +{{/vendorExtensions.discriminatorProperty}} +{{^vendorExtensions.discriminatorProperty}} +inline void from_json(const nlohmann::json& j, {{vendorExtensions.modelClassName}}& obj) +{ + {{#vendorExtensions.oneOfTypes}} + try + { + obj = j.get<{{.}}>(); + return; + } + catch (const nlohmann::json::exception&) + { + // Type mismatch, try next variant alternative + } + {{/vendorExtensions.oneOfTypes}} + throw nlohmann::json::type_error::create(302, "Could not deserialize into any variant type of {{vendorExtensions.modelClassName}}", &j); +} +{{/vendorExtensions.discriminatorProperty}} + +inline void to_json(nlohmann::json& j, const {{vendorExtensions.modelClassName}}& obj) +{ + std::visit([&j](const auto& val) { j = nlohmann::json(val); }, obj); +} + +{{/vendorExtensions.isOneOfSchema}} +{{#vendorExtensions.isAnyOfSchema}} +// anyOf schema - type alias for std::variant +using {{vendorExtensions.modelClassName}} = std::variant< +{{#vendorExtensions.anyOfTypes}} {{.}}{{^-last}}, +{{/-last}}{{/vendorExtensions.anyOfTypes}} >; + +// JSON serialization functions (inline for header-only) +{{#vendorExtensions.discriminatorProperty}} +inline void from_json(const nlohmann::json& j, {{vendorExtensions.modelClassName}}& obj) { + if (!j.contains("{{vendorExtensions.discriminatorProperty}}")) { + throw nlohmann::json::type_error::create(302, "Discriminator property '{{vendorExtensions.discriminatorProperty}}' not found in JSON", &j); + } + std::string discriminatorValue = j["{{vendorExtensions.discriminatorProperty}}"].get(); + {{#vendorExtensions.discriminatorMapping}} + if (discriminatorValue == "{{value}}") { + obj = j.get<{{key}}>(); + return; + } + {{/vendorExtensions.discriminatorMapping}} + throw nlohmann::json::type_error::create(302, "Unknown discriminator value: " + discriminatorValue, &j); +} +{{/vendorExtensions.discriminatorProperty}} +{{^vendorExtensions.discriminatorProperty}} +inline void from_json(const nlohmann::json& j, {{vendorExtensions.modelClassName}}& obj) +{ + {{#vendorExtensions.anyOfTypes}} + try + { + obj = j.get<{{.}}>(); + return; + } + catch (const nlohmann::json::exception&) + { + // Type mismatch, try next variant alternative + } + {{/vendorExtensions.anyOfTypes}} + throw nlohmann::json::type_error::create(302, "Could not deserialize into any variant type of {{vendorExtensions.modelClassName}}", &j); +} +{{/vendorExtensions.discriminatorProperty}} + +inline void to_json(nlohmann::json& j, const {{vendorExtensions.modelClassName}}& obj) +{ + std::visit([&j](const auto& val) { j = nlohmann::json(val); }, obj); +} + +{{/vendorExtensions.isAnyOfSchema}} +{{^vendorExtensions.isOneOfSchema}} +{{^vendorExtensions.isAnyOfSchema}} +{{#vars}} +{{#isUnionType}} +// Union type for anyOf/oneOf property +using {{unionTypeName}} = std::variant< +{{#unionTypes}} {{.}}{{^-last}},{{/-last}} +{{/unionTypes}}>; + +// Inline serialization for union type +inline void to_json(nlohmann::json& j, const {{unionTypeName}}& v) +{ + std::visit([&j](const auto& val) { j = nlohmann::json(val); }, v); +} + +inline void from_json(const nlohmann::json& j, {{unionTypeName}}& v) +{ + {{#unionTypes}} + try + { + v = j.get<{{.}}>(); + return; + } + catch (...) + { + // Try next type + } + {{/unionTypes}} + throw nlohmann::json::type_error::create(302, "Could not deserialize into any variant type of {{unionTypeName}}", &j); +} + +{{/isUnionType}} +{{/vars}} + +class {{vendorExtensions.modelClassName}}{{#parent}} : public {{parent}}{{/parent}} +{ +public: + {{#vars}} + {{#isEnum}} + {{#-first}} + // =================== + // ===== Enums ======= + // =================== + {{/-first}} + enum class {{enumName}} { + {{#allowableValues.values}} + {{.}}{{^-last}},{{/-last}} + {{/allowableValues.values}} + }; + + // Enum conversion functions (definitions in .cpp) + static std::string {{enumName}}ToString({{enumName}} value); + static {{enumName}} {{enumName}}FromString(const std::string& str); + + {{/isEnum}} + {{/vars}} + + {{vendorExtensions.modelClassName}}(); + virtual ~{{vendorExtensions.modelClassName}}() = default; + + // Getters and setters + {{#vars}} + [[nodiscard]] {{#isUnionType}}{{unionTypeName}}{{/isUnionType}}{{^isUnionType}}{{{datatypeWithEnum}}}{{/isUnionType}} {{getter}}() const; + void {{setter}}(const {{#isUnionType}}{{unionTypeName}}{{/isUnionType}}{{^isUnionType}}{{{datatypeWithEnum}}}{{/isUnionType}}& {{nameInCamelCase}}); + {{/vars}} +{{#vars}}{{#isEnum}}{{^isArray}}{{#-first}} + // ============================================================================= + // Friend Enum Serialization Helpers (Required for NLOHMANN JSON serialization) + // ============================================================================= + // These friend functions must be declared inside the class because: + // 1. The enum types are nested and don't exist before the class is defined + // 2. NLOHMANN macros need custom serialization for enum types (uses ToString/FromString) + // 3. The 'friend' keyword makes them free functions in the namespace (not member functions) + // so ADL (Argument-Dependent Lookup) can find them during JSON serialization + // ============================================================================= + +{{/-first}}{{^vendorExtensions.isOptionalEnum}} + // Serialization helpers for {{enumName}} + friend inline void to_json(nlohmann::json& j, const {{enumName}}& e) + { + j = {{enumName}}ToString(e); + } + + friend inline void from_json(const nlohmann::json& j, {{enumName}}& e) + { + e = {{enumName}}FromString(j.get()); + } +{{/vendorExtensions.isOptionalEnum}} +{{#vendorExtensions.isOptionalEnum}} + // Serialization helpers for std::optional<{{enumName}}> + friend inline void to_json(nlohmann::json& j, const std::optional<{{enumName}}>& opt) + { + if (opt.has_value()) + { + j = {{enumName}}ToString(opt.value()); + } + else + { + j = nullptr; + } + } + + friend inline void from_json(const nlohmann::json& j, std::optional<{{enumName}}>& opt) + { + if (j.is_null()) + { + opt = std::nullopt; + } + else + { + opt = {{enumName}}FromString(j.get()); + } + } +{{/vendorExtensions.isOptionalEnum}} + +{{/isArray}}{{/isEnum}}{{/vars}} + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE({{vendorExtensions.modelClassName}}, + {{#vars}} {{nameInCamelCase}}{{^-last}},{{/-last}}{{/vars}}) + +private: + {{#vars}} + {{#isUnionType}} + {{unionTypeName}} {{nameInCamelCase}}; + {{/isUnionType}} + {{^isUnionType}} + {{{datatypeWithEnum}}} {{nameInCamelCase}}; + {{/isUnionType}} + {{/vars}} +}; + +{{/vendorExtensions.isAnyOfSchema}} +{{/vendorExtensions.isOneOfSchema}} + +} // namespace {{vendorExtensions.modelNamespace}} + +{{/model}} +{{/models}} diff --git a/modules/openapi-generator/src/main/resources/cpp-httplib-server/model-source.mustache b/modules/openapi-generator/src/main/resources/cpp-httplib-server/model-source.mustache new file mode 100644 index 000000000000..414becd4a421 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/cpp-httplib-server/model-source.mustache @@ -0,0 +1,83 @@ + +{{>License}} + +{{#models}} +{{#model}} +{{^vendorExtensions.isOneOfSchema}} +{{^vendorExtensions.isAnyOfSchema}} +#include "{{vendorExtensions.modelClassName}}.h" + +namespace {{vendorExtensions.modelNamespace}} { + +{{vendorExtensions.modelClassName}}::{{vendorExtensions.modelClassName}}() +{{#vars}} +{{#defaultValue}} +{{#-first}}:{{/-first}}{{^-first}},{{/-first}} {{nameInCamelCase}}({{{defaultValue}}}) +{{/defaultValue}} +{{/vars}} +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +{{#vars}} +{{#-first}} +// =================== +// ===== Getters ===== +// =================== +{{/-first}} +{{! For enums, construct return type with proper class qualification }} +{{#isEnum}}{{#isContainer}}std::vector<{{model.vendorExtensions.modelClassName}}::{{enumName}}>{{/isContainer}}{{^isContainer}}{{#vendorExtensions.isOptionalEnum}}std::optional<{{model.vendorExtensions.modelClassName}}::{{enumName}}>{{/vendorExtensions.isOptionalEnum}}{{^vendorExtensions.isOptionalEnum}}{{model.vendorExtensions.modelClassName}}::{{enumName}}{{/vendorExtensions.isOptionalEnum}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{datatypeWithEnum}}}{{/isEnum}} {{model.vendorExtensions.modelClassName}}::{{getter}}() const +{ + return {{nameInCamelCase}}; +} +{{/vars}} + +{{#vars}} +{{#-first}} +// =================== +// ===== Setters ===== +// =================== +{{/-first}} +void {{model.vendorExtensions.modelClassName}}::{{setter}}(const {{{datatypeWithEnum}}}& {{nameInCamelCase}}Obj) +{ + {{nameInCamelCase}} = {{nameInCamelCase}}Obj; +} +{{/vars}} + +{{#vars}}{{#isEnum}}{{^isArray}} +// ========================================= +// ===== Enum {{enumName}} Conversions ===== +// ========================================= +std::string {{classname}}::{{enumName}}ToString({{classname}}::{{enumName}} value) +{ + switch (value) + { + {{#vendorExtensions.enumCases}} + case {{enumName}}::{{name}}: return "{{value}}"; + {{/vendorExtensions.enumCases}} + default: return {}; + } +} + +{{classname}}::{{enumName}} {{classname}}::{{enumName}}FromString(const std::string& str) +{ + {{#vendorExtensions.enumCases}} + if (str == "{{value}}") + { + return {{enumName}}::{{name}}; + } + {{/vendorExtensions.enumCases}} + throw std::invalid_argument("Invalid enum value"); +} +{{/isArray}}{{/isEnum}}{{/vars}} + + + +{{/vendorExtensions.isAnyOfSchema}} +{{/vendorExtensions.isOneOfSchema}} +{{^vendorExtensions.isOneOfSchema}}{{^vendorExtensions.isAnyOfSchema}} +} // namespace {{vendorExtensions.modelNamespace}} +{{/vendorExtensions.isAnyOfSchema}}{{/vendorExtensions.isOneOfSchema}} +{{/model}} +{{/models}} \ No newline at end of file diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/cpphttplibserver/CppHttplibServerCodegenModelTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/cpphttplibserver/CppHttplibServerCodegenModelTest.java new file mode 100644 index 000000000000..72d9e5cb5a5c --- /dev/null +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/cpphttplibserver/CppHttplibServerCodegenModelTest.java @@ -0,0 +1,301 @@ +/* + * Copyright 2026 OpenAPI-Generator Contributors (https://openapi-generator.tech) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openapitools.codegen.cpphttplib; + +import org.openapitools.codegen.*; +import org.openapitools.codegen.languages.CppHttplibServerCodegen; +import io.swagger.v3.oas.models.media.*; +import org.testng.Assert; +import org.testng.annotations.Test; + +@SuppressWarnings("static-method") +public class CppHttplibServerCodegenModelTest { + @Test(description = "convert model with enum property") + public void enumPropertyTest() { + final CppHttplibServerCodegen codegen = new CppHttplibServerCodegen(); + codegen.processOpts(); + + ObjectSchema schema = new ObjectSchema(); + StringSchema statusSchema = new StringSchema(); + statusSchema.setEnum(java.util.Arrays.asList("available", "pending", "sold")); + schema.addProperty("status", statusSchema); + + final CodegenModel model = codegen.fromModel("PetStatus", schema); + + Assert.assertEquals(model.name, "PetStatus"); + Assert.assertNotNull(model.vars); + Assert.assertEquals(model.vars.size(), 1); + + CodegenProperty statusProp = model.vars.get(0); + // Check that isEnum flag is set + Assert.assertTrue(statusProp.isEnum, "isEnum flag should be true for enum properties"); + // Check vendor extensions for enum handling + Assert.assertNotNull(statusProp.vendorExtensions, "vendorExtensions should not be null"); + Assert.assertTrue((boolean) statusProp.vendorExtensions.getOrDefault("isEnum", false), + "isEnum vendor extension should be true"); + // Check enum values + java.util.List enumValues = (java.util.List) statusProp.vendorExtensions.getOrDefault("values", statusProp._enum); + Assert.assertNotNull(enumValues, "enum values should be present"); + Assert.assertEquals(enumValues.size(), 3); + } + + @Test(description = "convert a simple model with properties") + public void simpleModelTest() { + final CppHttplibServerCodegen codegen = new CppHttplibServerCodegen(); + codegen.processOpts(); + + // Create a simple schema with properties + ObjectSchema schema = new ObjectSchema(); + schema.description("a sample model"); + schema.addProperty("id", new IntegerSchema().format("int64")); + schema.addProperty("name", new StringSchema()); + schema.addProperty("isActive", new BooleanSchema()); + schema.setRequired(java.util.Arrays.asList("id", "name")); + + final CodegenModel model = codegen.fromModel("User", schema); + + Assert.assertEquals(model.name, "User"); + Assert.assertEquals(model.classname, "User"); + Assert.assertNotNull(model.vars); + Assert.assertEquals(model.vars.size(), 3); + + // Check id property + CodegenProperty idProp = model.vars.get(0); + Assert.assertEquals(idProp.name, "Id"); + Assert.assertEquals(idProp.baseName, "id"); + Assert.assertEquals(idProp.dataType, "long"); + Assert.assertTrue(idProp.required); + + // Check name property + CodegenProperty nameProp = model.vars.get(1); + Assert.assertEquals(nameProp.name, "Name"); + Assert.assertEquals(nameProp.baseName, "name"); + Assert.assertEquals(nameProp.dataType, "std::string"); + Assert.assertTrue(nameProp.required); + + // Check isActive property + CodegenProperty activeProp = model.vars.get(2); + Assert.assertEquals(activeProp.name, "IsActive"); + Assert.assertEquals(activeProp.baseName, "isActive"); + Assert.assertEquals(activeProp.dataType, "bool"); + Assert.assertFalse(activeProp.required); + } + + @Test(description = "convert model with array property") + public void arrayPropertyTest() { + final CppHttplibServerCodegen codegen = new CppHttplibServerCodegen(); + codegen.processOpts(); + + ObjectSchema schema = new ObjectSchema(); + schema.addProperty("tags", new ArraySchema().items(new StringSchema())); + + final CodegenModel model = codegen.fromModel("ModelWithArray", schema); + + Assert.assertEquals(model.vars.size(), 1); + CodegenProperty arrayProp = model.vars.get(0); + Assert.assertEquals(arrayProp.baseName, "tags"); + Assert.assertEquals(arrayProp.dataType, "std::vector"); + Assert.assertTrue(arrayProp.isArray); + // Verify array vendor extensions are set + Assert.assertTrue((boolean) arrayProp.vendorExtensions.getOrDefault("isArray", false), + "isArray vendor extension should be true"); + } + + @Test(description = "convert model with array of enums") + public void arrayOfEnumsPropertyTest() { + final CppHttplibServerCodegen codegen = new CppHttplibServerCodegen(); + codegen.processOpts(); + + ObjectSchema schema = new ObjectSchema(); + StringSchema enumItemSchema = new StringSchema(); + enumItemSchema.setEnum(java.util.Arrays.asList("ACTIVE", "INACTIVE", "PENDING")); + schema.addProperty("statuses", new ArraySchema().items(enumItemSchema)); + + final CodegenModel model = codegen.fromModel("ModelWithEnumArray", schema); + + Assert.assertEquals(model.vars.size(), 1); + CodegenProperty arrayProp = model.vars.get(0); + Assert.assertTrue(arrayProp.isArray); + Assert.assertTrue((boolean) arrayProp.vendorExtensions.getOrDefault("isArray", false)); + // Verify it detects array of enums + Assert.assertTrue((boolean) arrayProp.vendorExtensions.getOrDefault("isArrayOfEnum", false), + "isArrayOfEnum vendor extension should be true"); + } + + @Test(description = "convert model with map property") + public void mapPropertyTest() { + final CppHttplibServerCodegen codegen = new CppHttplibServerCodegen(); + codegen.processOpts(); + + ObjectSchema schema = new ObjectSchema(); + schema.addProperty("metadata", new MapSchema().additionalProperties(new StringSchema())); + + final CodegenModel model = codegen.fromModel("ModelWithMap", schema); + + Assert.assertEquals(model.vars.size(), 1); + CodegenProperty mapProp = model.vars.get(0); + Assert.assertEquals(mapProp.name, "Metadata"); + Assert.assertEquals(mapProp.dataType, "std::map"); + Assert.assertTrue(mapProp.isMap); + // Verify map container flag + Assert.assertTrue((boolean) mapProp.vendorExtensions.getOrDefault("isContainer", false), + "isContainer vendor extension should be true for maps"); + } + + @Test(description = "convert model with numeric enum property") + public void numericEnumPropertyTest() { + final CppHttplibServerCodegen codegen = new CppHttplibServerCodegen(); + codegen.processOpts(); + + ObjectSchema schema = new ObjectSchema(); + IntegerSchema statusSchema = new IntegerSchema(); + statusSchema.setEnum(java.util.Arrays.asList(0, 1, 2)); + schema.addProperty("userStatus", statusSchema); + + final CodegenModel model = codegen.fromModel("UserStatusModel", schema); + + Assert.assertEquals(model.vars.size(), 1); + CodegenProperty statusProp = model.vars.get(0); + Assert.assertTrue(statusProp.isEnum); + Assert.assertTrue((boolean) statusProp.vendorExtensions.getOrDefault("isEnum", false)); + // Numeric enum values should be converted to valid C++ names (prefixed with underscore) + java.util.List enumValues = (java.util.List) statusProp.vendorExtensions.getOrDefault("values", statusProp._enum); + Assert.assertNotNull(enumValues); + // Check that numeric values are properly converted + Assert.assertTrue(enumValues.stream().anyMatch(v -> v.toString().startsWith("_")), + "Numeric enum values should be prefixed with underscore"); + } + + @Test(description = "convert enum model") + public void enumModelTest() { + final CppHttplibServerCodegen codegen = new CppHttplibServerCodegen(); + codegen.processOpts(); + + StringSchema enumSchema = new StringSchema(); + enumSchema.setEnum(java.util.Arrays.asList("ACTIVE", "INACTIVE", "PENDING")); + + final CodegenModel model = codegen.fromModel("Status", enumSchema); + + // Note: The C++ httplib server generator may not process enum-only models + // in the same way as regular object models. The model might be null or empty. + if (model != null) { + Assert.assertEquals(model.name, "Status"); + // Check if it's marked as an enum in vendor extensions + if (model.vendorExtensions.containsKey("x-is-enum")) { + Assert.assertEquals(model.vendorExtensions.get("x-is-enum"), true); + } + } + } + + @Test(description = "convert model with nullable property") + public void nullablePropertyTest() { + final CppHttplibServerCodegen codegen = new CppHttplibServerCodegen(); + codegen.processOpts(); + + StringSchema nullableStringSchema = new StringSchema(); + nullableStringSchema.setNullable(true); + + ObjectSchema schema = new ObjectSchema(); + schema.addProperty("optionalField", nullableStringSchema); + + final CodegenModel model = codegen.fromModel("ModelWithNullable", schema); + + Assert.assertEquals(model.vars.size(), 1); + CodegenProperty nullableProp = model.vars.get(0); + Assert.assertEquals(nullableProp.name, "OptionalField"); + Assert.assertTrue(nullableProp.isNullable); + // Check that isOptional vendor extension is set + Assert.assertTrue((boolean) nullableProp.vendorExtensions.getOrDefault("isOptional", false), + "isOptional vendor extension should be true for nullable fields"); + } + + @Test(description = "convert model with nested object property") + public void nestedObjectPropertyTest() { + final CppHttplibServerCodegen codegen = new CppHttplibServerCodegen(); + codegen.processOpts(); + + ObjectSchema nestedSchema = new ObjectSchema(); + nestedSchema.addProperty("id", new IntegerSchema()); + nestedSchema.addProperty("name", new StringSchema()); + + ObjectSchema schema = new ObjectSchema(); + schema.addProperty("user", nestedSchema); + + final CodegenModel model = codegen.fromModel("ModelWithNested", schema); + + Assert.assertEquals(model.vars.size(), 1); + CodegenProperty nestedProp = model.vars.get(0); + Assert.assertEquals(nestedProp.name, "User"); + Assert.assertTrue(nestedProp.isModel); + } + + @Test(description = "convert model with composed schema (allOf)") + public void composedSchemaTest() { + final CppHttplibServerCodegen codegen = new CppHttplibServerCodegen(); + codegen.processOpts(); + + // Create base schema + ObjectSchema baseSchema = new ObjectSchema(); + baseSchema.addProperty("id", new IntegerSchema()); + baseSchema.addProperty("name", new StringSchema()); + + // Create allOf with additional properties + io.swagger.v3.oas.models.media.ComposedSchema composedSchema = new io.swagger.v3.oas.models.media.ComposedSchema(); + composedSchema.addAllOfItem(new Schema<>().$ref("#/components/schemas/Base")); + composedSchema.addProperty("email", new StringSchema()); + + final CodegenModel model = codegen.fromModel("ExtendedUser", composedSchema); + + Assert.assertNotNull(model); + Assert.assertEquals(model.name, "ExtendedUser"); + } + + @Test(description = "convert model with complex types") + public void complexTypesTest() { + final CppHttplibServerCodegen codegen = new CppHttplibServerCodegen(); + codegen.processOpts(); + + ObjectSchema schema = new ObjectSchema(); + + // Add various property types + schema.addProperty("intValue", new IntegerSchema()); + schema.addProperty("longValue", new IntegerSchema().format("int64")); + schema.addProperty("doubleValue", new NumberSchema()); + schema.addProperty("floatValue", new NumberSchema().format("float")); + schema.addProperty("boolValue", new BooleanSchema()); + schema.addProperty("dateValue", new DateSchema()); + schema.addProperty("dateTimeValue", new DateTimeSchema()); + + final CodegenModel model = codegen.fromModel("ComplexModel", schema); + + Assert.assertEquals(model.vars.size(), 7); + + // Verify type mappings + java.util.Map dataTypeMap = new java.util.HashMap<>(); + for (CodegenProperty var : model.vars) { + dataTypeMap.put(var.baseName, var.dataType); + } + + Assert.assertEquals(dataTypeMap.get("intValue"), "int"); + Assert.assertEquals(dataTypeMap.get("longValue"), "long"); + Assert.assertEquals(dataTypeMap.get("doubleValue"), "double"); + Assert.assertEquals(dataTypeMap.get("floatValue"), "float"); + Assert.assertEquals(dataTypeMap.get("boolValue"), "bool"); + Assert.assertEquals(dataTypeMap.get("dateValue"), "std::string"); + Assert.assertEquals(dataTypeMap.get("dateTimeValue"), "std::string"); + } +} + diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/cpphttplibserver/CppHttplibServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/cpphttplibserver/CppHttplibServerCodegenTest.java new file mode 100644 index 000000000000..1496f6e9d582 --- /dev/null +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/cpphttplibserver/CppHttplibServerCodegenTest.java @@ -0,0 +1,147 @@ +/* + * Copyright 2026 OpenAPI-Generator Contributors (https://openapi-generator.tech) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openapitools.codegen.cpphttplib; + +import static org.openapitools.codegen.utils.StringUtils.underscore; + +import org.openapitools.codegen.*; +import org.openapitools.codegen.languages.CppHttplibServerCodegen; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class CppHttplibServerCodegenTest { + + CppHttplibServerCodegen codegen = new CppHttplibServerCodegen(); + + @Test + public void testInitialConfigValues() throws Exception { + codegen.processOpts(); + + Assert.assertEquals(codegen.additionalProperties().get("projectName"), "cpp-httplib-server"); + Assert.assertEquals(codegen.modelPackage(), "cpp-httplib-server"); + Assert.assertEquals(codegen.additionalProperties().get("cmakeProjectName"), "cpp_httplib_server"); + } + + @Test + public void testSettersForConfigValues() throws Exception { + codegen.additionalProperties().put("projectName", "TestProject"); + codegen.additionalProperties().put("modelNamespace", "test::models"); + codegen.additionalProperties().put("apiNamespace", "test::apis"); + codegen.processOpts(); + + Assert.assertEquals(codegen.additionalProperties().get("projectName"), "TestProject"); + Assert.assertEquals(codegen.additionalProperties().get("modelNamespace"), "test::models"); + Assert.assertEquals(codegen.additionalProperties().get("apiNamespace"), "test::apis"); + } + + @Test + public void testToModelName() { + Assert.assertEquals(codegen.toModelName("User"), "User"); + Assert.assertEquals(codegen.toModelName("user"), "User"); + Assert.assertEquals(codegen.toModelName("user_model"), "UserModel"); + Assert.assertEquals(codegen.toModelName("object"), "InlineModel"); + Assert.assertEquals(codegen.toModelName("object_1"), "InlineModel1"); + Assert.assertEquals(codegen.toModelName("inline_object_1"), "InlineModel1"); + Assert.assertEquals(codegen.toModelName("_inline_model"), "Model"); + } + + @Test + public void testToApiName() { + Assert.assertEquals(codegen.toApiName("users"), "Users"); + Assert.assertEquals(codegen.toApiName("testproject"), "Testproject"); + } + + @Test + public void testGetTypeDeclaration() { + Assert.assertEquals(codegen.getTypeDeclaration(new io.swagger.v3.oas.models.media.StringSchema()), "std::string"); + Assert.assertEquals(codegen.getTypeDeclaration(new io.swagger.v3.oas.models.media.IntegerSchema()), "int"); + Assert.assertEquals(codegen.getTypeDeclaration(new io.swagger.v3.oas.models.media.BooleanSchema()), "bool"); + + io.swagger.v3.oas.models.media.ArraySchema arraySchema = new io.swagger.v3.oas.models.media.ArraySchema(); + arraySchema.setItems(new io.swagger.v3.oas.models.media.StringSchema()); + Assert.assertEquals(codegen.getTypeDeclaration(arraySchema), "std::vector"); + } + + @Test + public void testStringUtilityMethods() { + Assert.assertEquals(codegen.toPascalCase("user_name"), "UserName"); + Assert.assertEquals(codegen.toPascalCase("userName"), "UserName"); + Assert.assertEquals(codegen.toCamelCase("user_name"), "userName"); + Assert.assertEquals(codegen.toPascalCase("UserName"), "UserName"); + Assert.assertEquals(codegen.toCamelCase("UserName"), "userName"); + Assert.assertEquals(underscore("UserName"), "user_name"); + } + + @Test + public void testInlineObjectNaming() { + // Test the enhanced inline object naming that we implemented + Assert.assertEquals(codegen.toModelName("object"), "InlineModel"); + Assert.assertEquals(codegen.toModelName("object_1"), "InlineModel1"); + Assert.assertEquals(codegen.toModelName("object_123"), "InlineModel123"); + Assert.assertEquals(codegen.toModelName("inline_object"), "InlineModel"); + Assert.assertEquals(codegen.toModelName("inline_object_5"), "InlineModel5"); + } + + @Test + public void testModelFilename() { + Assert.assertEquals(codegen.toModelFilename("User"), "User"); + Assert.assertEquals(codegen.toModelFilename("UserModel"), "UserModel"); + Assert.assertEquals(codegen.toModelFilename("object"), "Object"); + Assert.assertEquals(codegen.toModelFilename("usermodel"), "Usermodel"); + } + + @Test + public void testApiFilename() { + Assert.assertEquals(codegen.toApiFilename("User"), "UserApi"); + Assert.assertEquals(codegen.toApiFilename("Default"), "DefaultApi"); + } + + @Test + public void testTypeDeclarationWithAnyOf() { + io.swagger.v3.oas.models.media.ComposedSchema anyOfSchema = new io.swagger.v3.oas.models.media.ComposedSchema(); + anyOfSchema.addAnyOfItem(new io.swagger.v3.oas.models.media.StringSchema()); + anyOfSchema.addAnyOfItem(new io.swagger.v3.oas.models.media.IntegerSchema()); + + String result = codegen.getTypeDeclaration(anyOfSchema); + Assert.assertTrue(result.contains("std::variant"), "anyOf should generate std::variant"); + } + + @Test + public void testTypeDeclarationWithOneOf() { + io.swagger.v3.oas.models.media.ComposedSchema oneOfSchema = new io.swagger.v3.oas.models.media.ComposedSchema(); + oneOfSchema.addOneOfItem(new io.swagger.v3.oas.models.media.StringSchema()); + oneOfSchema.addOneOfItem(new io.swagger.v3.oas.models.media.NumberSchema()); + + String result = codegen.getTypeDeclaration(oneOfSchema); + Assert.assertTrue(result.contains("std::variant"), "oneOf should generate std::variant"); + } + + @Test + public void testModelNamespaceHandling() { + codegen.additionalProperties().put("modelNamespace", "myapp::models"); + codegen.processOpts(); + + Assert.assertEquals(codegen.additionalProperties().get("modelNamespace"), "myapp::models"); + } + + @Test + public void testApiNamespaceHandling() { + codegen.additionalProperties().put("apiNamespace", "myapp::api"); + codegen.processOpts(); + + Assert.assertEquals(codegen.additionalProperties().get("apiNamespace"), "myapp::api"); + } +} diff --git a/modules/openapi-generator/src/test/resources/3_0/cpp-httplib-server/feature-test.json b/modules/openapi-generator/src/test/resources/3_0/cpp-httplib-server/feature-test.json new file mode 100644 index 000000000000..2ffb304ceb53 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/cpp-httplib-server/feature-test.json @@ -0,0 +1,1279 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "C++ httplib Server Feature Test API", + "description": "Comprehensive test specification for all cpp-httplib-server generator features", + "version": "1.0.0" + }, + "servers": [ + { + "url": "http://localhost:8080/api/v1" + } + ], + "tags": [ + { + "name": "datatypes", + "description": "Test all data types" + }, + { + "name": "parameters", + "description": "Test parameter types and styles" + }, + { + "name": "composition", + "description": "Test schema composition (allOf, anyOf, oneOf)" + }, + { + "name": "security", + "description": "Test security schemes" + } + ], + "paths": { + "/datatypes/primitives": { + "post": { + "tags": ["datatypes"], + "operationId": "testPrimitiveTypes", + "summary": "Test all primitive data types", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrimitiveTypes" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrimitiveTypes" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/datatypes/arrays": { + "post": { + "tags": ["datatypes"], + "operationId": "testArrayTypes", + "summary": "Test array data types", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArrayTypes" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArrayTypes" + } + } + } + } + } + } + }, + "/datatypes/enums": { + "post": { + "tags": ["datatypes"], + "operationId": "testEnumTypes", + "summary": "Test enum types including numeric enums", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnumTypes" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnumTypes" + } + } + } + } + } + } + }, + "/parameters/query/{pathId}": { + "get": { + "tags": ["parameters"], + "operationId": "testQueryParameters", + "summary": "Test all query parameter types and styles", + "parameters": [ + { + "name": "pathId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "stringParam", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "intParam", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 42 + } + }, + { + "name": "boolParam", + "in": "query", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "arrayParam", + "in": "query", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "spaceDelimited", + "in": "query", + "required": false, + "style": "spaceDelimited", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "pipeDelimited", + "in": "query", + "required": false, + "style": "pipeDelimited", + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + { + "name": "deepObject", + "in": "query", + "required": false, + "style": "deepObject", + "explode": true, + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "age": { + "type": "integer" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/parameters/headers": { + "get": { + "tags": ["parameters"], + "operationId": "testHeaderParameters", + "summary": "Test header parameters", + "parameters": [ + { + "name": "X-Api-Version", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Request-Id", + "in": "header", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "X-Rate-Limit", + "in": "header", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "X-Tags", + "in": "header", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "NoSuccess", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/parameters/cookies": { + "get": { + "tags": ["parameters"], + "operationId": "testCookieParameters", + "summary": "Test cookie parameters", + "parameters": [ + { + "name": "sessionId", + "in": "cookie", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "cookie", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "preferences", + "in": "cookie", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/parameters/combined/{resourceId}": { + "post": { + "tags": ["parameters"], + "operationId": "testAllParameterTypes", + "summary": "Test all parameter types combined (path + query + header + cookie + body)", + "parameters": [ + { + "name": "resourceId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "filter", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 10 + } + }, + { + "name": "X-Correlation-Id", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Client-Version", + "in": "header", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "authToken", + "in": "cookie", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "userPrefs", + "in": "cookie", + "required": false, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SimpleObject" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "resourceId": { + "type": "integer" + }, + "filter": { + "type": "string" + }, + "correlationId": { + "type": "string" + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/composition/allof": { + "post": { + "tags": ["composition"], + "operationId": "testAllOfComposition", + "summary": "Test allOf schema composition", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Dog" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Dog" + } + } + } + } + } + } + }, + "/composition/anyof": { + "post": { + "tags": ["composition"], + "operationId": "testAnyOfComposition", + "summary": "Test anyOf schema composition", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StringOrNumber" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StringOrNumber" + } + } + } + } + } + } + }, + "/composition/oneof": { + "post": { + "tags": ["composition"], + "operationId": "testOneOfComposition", + "summary": "Test oneOf schema composition", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentMethod" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentMethod" + } + } + } + } + } + } + }, + "/security/apikey": { + "get": { + "tags": ["security"], + "operationId": "testApiKeySecurity", + "summary": "Test API Key authentication", + "security": [ + { + "ApiKeyAuth": [] + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/security/bearer": { + "get": { + "tags": ["security"], + "operationId": "testBearerSecurity", + "summary": "Test Bearer token authentication", + "security": [ + { + "BearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/security/basic": { + "get": { + "tags": ["security"], + "operationId": "testBasicSecurity", + "summary": "Test Basic authentication", + "security": [ + { + "BasicAuth": [] + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/security/oauth2": { + "get": { + "tags": ["security"], + "operationId": "testOAuth2Security", + "summary": "Test OAuth2 authentication", + "security": [ + { + "OAuth2": ["read:users", "write:users"] + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/responses/multiple": { + "get": { + "tags": ["datatypes"], + "operationId": "testMultipleResponses", + "summary": "Test multiple response status codes", + "parameters": [ + { + "name": "scenario", + "in": "query", + "required": true, + "schema": { + "type": "string", + "enum": ["success", "created", "notfound", "error"] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatedResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/responses/nocontent": { + "delete": { + "tags": ["datatypes"], + "operationId": "testNoContentResponse", + "summary": "Test 204 No Content response", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "No Content - successful deletion" + } + } + } + }, + "/nullable/optional": { + "post": { + "tags": ["datatypes"], + "operationId": "testNullableOptional", + "summary": "Test nullable and optional fields", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NullableOptionalTypes" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NullableOptionalTypes" + } + } + } + } + } + } + }, + "/nested/objects": { + "post": { + "tags": ["datatypes"], + "operationId": "testNestedObjects", + "summary": "Test deeply nested object structures", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Company" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Company" + } + } + } + } + } + } + } + }, + "components": { + "securitySchemes": { + "ApiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "X-API-Key" + }, + "BearerAuth": { + "type": "http", + "scheme": "bearer" + }, + "BasicAuth": { + "type": "http", + "scheme": "basic" + }, + "OAuth2": { + "type": "oauth2", + "flows": { + "authorizationCode": { + "authorizationUrl": "https://example.com/oauth/authorize", + "tokenUrl": "https://example.com/oauth/token", + "scopes": { + "read:users": "Read user data", + "write:users": "Write user data" + } + } + } + } + }, + "schemas": { + "PrimitiveTypes": { + "type": "object", + "required": ["stringField", "intField", "boolField"], + "properties": { + "stringField": { + "type": "string", + "description": "A string field" + }, + "intField": { + "type": "integer", + "description": "An integer field" + }, + "longField": { + "type": "integer", + "format": "int64", + "description": "A long field" + }, + "floatField": { + "type": "number", + "format": "float", + "description": "A float field" + }, + "doubleField": { + "type": "number", + "format": "double", + "description": "A double field" + }, + "boolField": { + "type": "boolean", + "description": "A boolean field" + }, + "byteField": { + "type": "string", + "format": "byte", + "description": "A byte field" + }, + "binaryField": { + "type": "string", + "format": "binary", + "description": "A binary field" + }, + "dateField": { + "type": "string", + "format": "date", + "description": "A date field" + }, + "dateTimeField": { + "type": "string", + "format": "date-time", + "description": "A datetime field" + }, + "passwordField": { + "type": "string", + "format": "password", + "description": "A password field" + } + } + }, + "ArrayTypes": { + "type": "object", + "properties": { + "stringArray": { + "type": "array", + "items": { + "type": "string" + } + }, + "intArray": { + "type": "array", + "items": { + "type": "integer" + } + }, + "objectArray": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SimpleObject" + } + }, + "enumArray": { + "type": "array", + "items": { + "type": "string", + "enum": ["red", "green", "blue"] + } + }, + "nestedArray": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "integer" + } + } + } + } + }, + "EnumTypes": { + "type": "object", + "properties": { + "stringEnum": { + "type": "string", + "enum": ["pending", "approved", "rejected"] + }, + "numericEnum": { + "type": "integer", + "enum": [100, 200, 300, 404, 500] + }, + "statusCode": { + "type": "string", + "enum": ["200", "404", "500"] + } + } + }, + "SimpleObject": { + "type": "object", + "required": ["id", "name"], + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "Animal": { + "type": "object", + "required": ["name", "type"], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "Dog": { + "allOf": [ + { + "$ref": "#/components/schemas/Animal" + }, + { + "type": "object", + "required": ["breed"], + "properties": { + "breed": { + "type": "string" + }, + "barkVolume": { + "type": "integer" + } + } + } + ] + }, + "StringOrNumber": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "CreditCard": { + "type": "object", + "required": ["paymentType", "cardNumber", "cardType"], + "properties": { + "paymentType": { + "type": "string" + }, + "cardNumber": { + "type": "string" + }, + "cardType": { + "type": "string", + "enum": ["visa", "mastercard", "amex"] + } + } + }, + "BankAccount": { + "type": "object", + "required": ["paymentType", "accountNumber", "bankName"], + "properties": { + "paymentType": { + "type": "string" + }, + "accountNumber": { + "type": "string" + }, + "bankName": { + "type": "string" + } + } + }, + "PaymentMethod": { + "oneOf": [ + { + "$ref": "#/components/schemas/CreditCard" + }, + { + "$ref": "#/components/schemas/BankAccount" + } + ], + "discriminator": { + "propertyName": "paymentType", + "mapping": { + "credit_card": "#/components/schemas/CreditCard", + "bank_account": "#/components/schemas/BankAccount" + } + } + }, + "NullableOptionalTypes": { + "type": "object", + "required": ["requiredField"], + "properties": { + "requiredField": { + "type": "string" + }, + "optionalField": { + "type": "string" + }, + "nullableField": { + "type": "string", + "nullable": true + }, + "optionalNullableField": { + "type": "string", + "nullable": true + }, + "fieldWithDefault": { + "type": "integer", + "default": 42 + } + } + }, + "Address": { + "type": "object", + "required": ["street", "city"], + "properties": { + "street": { + "type": "string" + }, + "city": { + "type": "string" + }, + "zipCode": { + "type": "string" + }, + "country": { + "type": "string", + "default": "USA" + } + } + }, + "Employee": { + "type": "object", + "required": ["id", "name", "email"], + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "address": { + "$ref": "#/components/schemas/Address" + }, + "skills": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "Department": { + "type": "object", + "required": ["name", "manager"], + "properties": { + "name": { + "type": "string" + }, + "manager": { + "$ref": "#/components/schemas/Employee" + }, + "employees": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Employee" + } + } + } + }, + "Company": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string" + }, + "headquarters": { + "$ref": "#/components/schemas/Address" + }, + "departments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Department" + } + }, + "metadata": { + "type": "object", + "additionalProperties": true + } + } + }, + "SuccessResponse": { + "type": "object", + "required": ["status", "data"], + "properties": { + "status": { + "type": "string" + }, + "data": { + "type": "object" + } + } + }, + "CreatedResponse": { + "type": "object", + "required": ["status", "id"], + "properties": { + "status": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "location": { + "type": "string" + } + } + }, + "NotFoundResponse": { + "type": "object", + "required": ["error"], + "properties": { + "error": { + "type": "string" + }, + "resource": { + "type": "string" + } + } + }, + "ErrorResponse": { + "type": "object", + "required": ["message"], + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": "integer" + }, + "details": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } +} diff --git a/modules/openapi-generator/src/test/resources/3_0/cpp-httplib-server/petstore.json b/modules/openapi-generator/src/test/resources/3_0/cpp-httplib-server/petstore.json new file mode 100644 index 000000000000..cd38233806cc --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/cpp-httplib-server/petstore.json @@ -0,0 +1,316 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Petstore API", + "version": "1.0.0" + }, + "servers": [ + { "url": "http://petstore.swagger.io/v2" } + ], + "paths": { + "/pet/{petId}": { + "get": { + "tags": ["pet"], + "summary": "Get pet by ID", + "operationId": "getPetById", + "parameters": [ + { "name": "petId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" } }, + { "name": "customHeader", "in": "header", "required": false, "schema": { "type": "string" } }, + { "name": "cookieParam", "in": "cookie", "required": false, "schema": { "type": "string" } } + ], + "responses": { + "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Pet" } } } }, + "400": { "description": "Invalid ID", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponse" } } } }, + "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponse" } } } } + } + }, + "delete": { + "tags": ["pet"], + "summary": "Delete pet by ID", + "operationId": "deletePetById", + "parameters": [ + { "name": "petId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" } }, + { "name": "api_key", "in": "query", "required": false, "schema": { "type": "string" } } + ], + "responses": { + "200": { "description": "Pet deleted" }, + "400": { "description": "Invalid ID" } + } + } + }, + "/pet": { + "post": { + "tags": ["pet"], + "summary": "Add a new pet", + "operationId": "addPet", + "requestBody": { + "required": true, + "content": { + "application/json": { "schema": { "$ref": "#/components/schemas/Pet" } } + } + }, + "responses": { + "201": { "description": "Pet created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Pet" } } } }, + "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponse" } } } } + } + }, + "put": { + "tags": ["pet"], + "summary": "Update an existing pet", + "operationId": "updatePet", + "requestBody": { + "required": true, + "content": { + "application/json": { "schema": { "$ref": "#/components/schemas/Pet" } } + } + }, + "responses": { + "200": { "description": "Pet updated" }, + "400": { "description": "Invalid input" } + } + } + }, + "/pet/findByStatus": { + "get": { + "tags": ["pet"], + "summary": "Find pets by status (enum, array)", + "operationId": "findPetsByStatus", + "parameters": [ + { "name": "status", "in": "query", "required": true, "schema": { "type": "string", "enum": ["available", "pending", "sold"] } } + ], + "responses": { + "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Pet" } } } } }, + "400": { "description": "Invalid status" } + } + } + }, + "/pet/findByTags": { + "get": { + "tags": ["pet"], + "summary": "Find pets by tags", + "operationId": "findPetsByTags", + "parameters": [ + { "name": "tags", "in": "query", "required": true, "style": "form", "explode": false, "schema": { "type": "array", "items": { "type": "string" } } } + ], + "responses": { + "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Pet" } } } } } + } + } + }, + "/pet/complex": { + "get": { + "tags": ["pet"], + "summary": "Test nested object, enum, array, header, cookie", + "operationId": "complexParamTest", + "parameters": [ + { "name": "deepObj", "in": "query", "required": false, "style": "deepObject", "explode": true, "schema": { "$ref": "#/components/schemas/DeepObj" } }, + { "name": "enumParam", "in": "query", "required": false, "schema": { "type": "string", "enum": ["A", "B", "C"] } }, + { "name": "pipeArr", "in": "query", "required": false, "style": "pipeDelimited", "explode": false, "schema": { "type": "array", "items": { "type": "string" } } }, + { "name": "spaceArr", "in": "query", "required": false, "style": "spaceDelimited", "explode": false, "schema": { "type": "array", "items": { "type": "integer" } } }, + { "name": "x-enum-header", "in": "header", "required": false, "schema": { "type": "string", "enum": ["X", "Y", "Z"] } }, + { "name": "cookieEnum", "in": "cookie", "required": false, "schema": { "type": "string", "enum": ["cookieA", "cookieB"] } } + ], + "responses": { + "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ComplexParamsResponse" } } } } + } + } + }, + "/store/order": { + "post": { + "tags": ["store"], + "summary": "Place an order", + "operationId": "placeOrder", + "requestBody": { + "required": true, + "content": { + "application/json": { "schema": { "$ref": "#/components/schemas/Order" } } + } + }, + "responses": { + "200": { "description": "Order placed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Order" } } } } + } + } + }, + "/store/order/{orderId}": { + "get": { + "tags": ["store"], + "summary": "Get order by ID", + "operationId": "getOrderById", + "parameters": [ + { "name": "orderId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" } } + ], + "responses": { + "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Order" } } } } + } + }, + "delete": { + "tags": ["store"], + "summary": "Delete order", + "operationId": "deleteOrder", + "parameters": [ + { "name": "orderId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" } } + ], + "responses": { + "200": { "description": "Order deleted" } + } + } + }, + "/user": { + "post": { + "tags": ["user"], + "summary": "Create user", + "operationId": "createUser", + "requestBody": { + "required": true, + "content": { + "application/json": { "schema": { "$ref": "#/components/schemas/User" } } + } + }, + "responses": { + "200": { "description": "User created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } } + } + } + }, + "/user/{username}": { + "get": { + "tags": ["user"], + "summary": "Get user by name", + "operationId": "getUserByName", + "parameters": [ + { "name": "username", "in": "path", "required": true, "schema": { "type": "string" } } + ], + "responses": { + "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } } + } + }, + "put": { + "tags": ["user"], + "summary": "Update user", + "operationId": "updateUser", + "parameters": [ + { "name": "username", "in": "path", "required": true, "schema": { "type": "string" } } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { "schema": { "$ref": "#/components/schemas/User" } } + } + }, + "responses": { + "200": { "description": "User updated" } + } + }, + "delete": { + "tags": ["user"], + "summary": "Delete user", + "operationId": "deleteUser", + "parameters": [ + { "name": "username", "in": "path", "required": true, "schema": { "type": "string" } } + ], + "responses": { + "200": { "description": "User deleted" } + } + } + } + }, + "components": { + "schemas": { + "Pet": { + "type": "object", + "required": ["name", "photoUrls"], + "properties": { + "id": { "type": "integer", "format": "int64" }, + "name": { "type": "string" }, + "photoUrls": { "type": "array", "items": { "type": "string" } }, + "status": { "type": "string", "enum": ["available", "pending", "sold"], "description": "Pet status in store" }, + "category": { "$ref": "#/components/schemas/Category" }, + "tags": { "type": "array", "items": { "$ref": "#/components/schemas/Tag" } } + } + }, + "Category": { + "type": "object", + "properties": { + "id": { "type": "integer", "format": "int64" }, + "name": { "type": "string" } + } + }, + "Tag": { + "type": "object", + "properties": { + "id": { "type": "integer", "format": "int64" }, + "name": { "type": "string" } + } + }, + "Order": { + "type": "object", + "properties": { + "id": { "type": "integer", "format": "int64" }, + "petId": { "type": "integer", "format": "int64" }, + "quantity": { "type": "integer", "format": "int32" }, + "shipDate": { "type": "string", "format": "date-time" }, + "status": { "type": "string", "enum": ["placed", "approved", "delivered"], "description": "Order status" }, + "complete": { "type": "boolean" } + } + }, + "User": { + "type": "object", + "properties": { + "id": { "type": "integer", "format": "int64" }, + "username": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "email": { "type": "string", "format": "email" }, + "password": { "type": "string" }, + "phone": { "type": "string" }, + "userStatus": { "type": "integer", "format": "int32", "enum": [0, 1, 2], "description": "User status (0=inactive, 1=active, 2=admin)" } + } + }, + "ApiResponse": { + "type": "object", + "properties": { + "code": { "type": "integer", "format": "int32" }, + "type": { "type": "string" }, + "message": { "type": "string" } + } + }, + "DeepObj": { + "type": "object", + "properties": { + "foo": { "type": "string" }, + "bar": { "type": "integer" }, + "baz": { + "type": "object", + "properties": { + "x": { "type": "string" }, + "y": { "type": "integer" } + } + } + } + }, + "ComplexParamsResponse": { + "type": "object", + "properties": { + "deepObj": { "$ref": "#/components/schemas/DeepObj" }, + "enumParam": { "type": "string", "enum": ["A", "B", "C"] }, + "pipeArr": { "type": "array", "items": { "type": "string" } }, + "spaceArr": { "type": "array", "items": { "type": "integer" } }, + "x-enum-header": { "type": "string", "enum": ["X", "Y", "Z"] }, + "cookieEnum": { "type": "string", "enum": ["cookieA", "cookieB"] } + } + }, + "PetOrCategory": { + "oneOf": [ + { "$ref": "#/components/schemas/Pet" }, + { "$ref": "#/components/schemas/Category" } + ], + "description": "Polymorphic type: Pet or Category" + }, + "NullableExample": { + "type": "object", + "properties": { + "maybeString": { "type": "string", "nullable": true, "description": "A nullable string property" } + } + } + } + } +} diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/.openapi-generator-ignore b/samples/server/petstore/cpp-httplib-server/feature-test/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/.openapi-generator/FILES b/samples/server/petstore/cpp-httplib-server/feature-test/.openapi-generator/FILES new file mode 100644 index 000000000000..05151c84f82a --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/.openapi-generator/FILES @@ -0,0 +1,70 @@ +CMakeLists.txt +LICENSE +README.md +api/AuthenticationManager.h +api/CompositionApi.cpp +api/CompositionApi.h +api/DatatypesApi.cpp +api/DatatypesApi.h +api/ParametersApi.cpp +api/ParametersApi.h +api/SecurityApi.cpp +api/SecurityApi.h +models/Address.cpp +models/Address.h +models/Animal.cpp +models/Animal.h +models/ArrayTypes.cpp +models/ArrayTypes.h +models/BankAccount.cpp +models/BankAccount.h +models/Company.cpp +models/Company.h +models/CreatedResponse.cpp +models/CreatedResponse.h +models/CreditCard.cpp +models/CreditCard.h +models/Department.cpp +models/Department.h +models/Dog.cpp +models/Dog.h +models/Employee.cpp +models/Employee.h +models/EnumTypes.cpp +models/EnumTypes.h +models/ErrorResponse.cpp +models/ErrorResponse.h +models/NotFoundResponse.cpp +models/NotFoundResponse.h +models/NullableOptionalTypes.cpp +models/NullableOptionalTypes.h +models/PaymentMethod.cpp +models/PaymentMethod.h +models/PrimitiveTypes.cpp +models/PrimitiveTypes.h +models/SimpleObject.cpp +models/SimpleObject.h +models/StringOrNumber.cpp +models/StringOrNumber.h +models/SuccessResponse.cpp +models/SuccessResponse.h +models/TestAllParameterTypes200Response.cpp +models/TestAllParameterTypes200Response.h +models/TestApiKeySecurity200Response.cpp +models/TestApiKeySecurity200Response.h +models/TestBasicSecurity200Response.cpp +models/TestBasicSecurity200Response.h +models/TestBearerSecurity200Response.cpp +models/TestBearerSecurity200Response.h +models/TestCookieParameters200Response.cpp +models/TestCookieParameters200Response.h +models/TestHeaderParameters200Response.cpp +models/TestHeaderParameters200Response.h +models/TestHeaderParameters401Response.cpp +models/TestHeaderParameters401Response.h +models/TestOAuth2Security200Response.cpp +models/TestOAuth2Security200Response.h +models/TestQueryParameters200Response.cpp +models/TestQueryParameters200Response.h +models/TestQueryParametersDeepObjectParameter.cpp +models/TestQueryParametersDeepObjectParameter.h diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/.openapi-generator/VERSION b/samples/server/petstore/cpp-httplib-server/feature-test/.openapi-generator/VERSION new file mode 100644 index 000000000000..5e5282953086 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.16.0-SNAPSHOT diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/CMakeLists.txt b/samples/server/petstore/cpp-httplib-server/feature-test/CMakeLists.txt new file mode 100644 index 000000000000..ef3f87c8c1d0 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.14) +project(cpp_httplib_server_feature_test LANGUAGES CXX) + +include(FetchContent) + +# Fetch nlohmann_json +FetchContent_Declare( + nlohmann_json + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_TAG v3.11.3 +) +FetchContent_MakeAvailable(nlohmann_json) + +# Fetch cpp-httplib +FetchContent_Declare( + httplib + GIT_REPOSITORY https://github.com/yhirose/cpp-httplib.git + GIT_TAG v0.15.3 +) +FetchContent_MakeAvailable(httplib) + +# System libraries - install with: sudo apt-get install libssl-dev zlib1g-dev +find_package(OpenSSL REQUIRED) +find_package(ZLIB REQUIRED) + +set(TARGET_NAME cpp_httplib_server_feature_test_openapi_lib) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +file(GLOB API_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/api/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/api/*.cpp +) +file(GLOB MODEL_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/models/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/models/*.cpp +) +add_library(${TARGET_NAME} ${API_SRCS} ${MODEL_SRCS}) +target_include_directories (${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +# Make sure these libraries/headers are available in the build environment before linking +# Required libraries/headers are httplib,ssl,nlohmann::json,zlib +target_link_libraries(${TARGET_NAME} + PRIVATE + httplib::httplib + OpenSSL::SSL + OpenSSL::Crypto + nlohmann_json::nlohmann_json + ZLIB::ZLIB) + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/LICENSE b/samples/server/petstore/cpp-httplib-server/feature-test/LICENSE new file mode 100644 index 000000000000..286685933869 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/LICENSE @@ -0,0 +1,5 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/README.md b/samples/server/petstore/cpp-httplib-server/feature-test/README.md new file mode 100644 index 000000000000..8889a4d4cb6f --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/README.md @@ -0,0 +1,1080 @@ +# cpp-httplib-server-feature-test - C++ Server + +## Overview + +This server was generated using the [OpenAPI Generator](https://openapi-generator.tech) project. +It uses the [cpp-httplib](https://github.com/yhirose/cpp-httplib) library to implement a lightweight HTTP server +with JSON request/response handling via [nlohmann/json](https://github.com/nlohmann/json). + +## Requirements + +- C++17 compatible compiler +- CMake (3.14 or higher) +- OpenSSL (for HTTPS support) +- ZLIB (for compression support) + +**Note:** The following libraries are automatically downloaded via CMake FetchContent: +- [cpp-httplib](https://github.com/yhirose/cpp-httplib) v0.15.3 +- [nlohmann/json](https://github.com/nlohmann/json) v3.11.3 + +### Platform-Specific Installation + +**Linux (Ubuntu/Debian):** +```bash +sudo apt-get update +sudo apt-get install -y libssl-dev zlib1g-dev cmake build-essential +``` + +**macOS:** +```bash +brew install openssl zlib cmake +``` + +**Windows:** +```powershell +# Using vcpkg +vcpkg install openssl:x64-windows zlib:x64-windows + +# Then configure CMake with vcpkg toolchain: +cmake -B build -DCMAKE_TOOLCHAIN_FILE=[vcpkg_root]/scripts/buildsystems/vcpkg.cmake +``` + +## Project Structure + +``` +├── CMakeLists.txt # Project build configuration +├── README.md # This file +├── models/ # Generated model classes +└── api/ # Generated API handler classes +``` + +## Building the Project + +```bash +mkdir build +cd build +cmake .. +make +``` + +## Working with Models + +### Model Classes + +#### models::Address + +```cpp +// Create a model +auto model = models::Address(); +model.setStreet(/* value */); // Set street +model.setCity(/* value */); // Set city +model.setZipCode(/* value */); // Set zipCode +model.setCountry(/* value */); // Set country + +// Serialize to JSON +nlohmann::json json = models::Address::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::Address::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::Animal + +```cpp +// Create a model +auto model = models::Animal(); +model.setName(/* value */); // Set name +model.setType(/* value */); // Set type + +// Serialize to JSON +nlohmann::json json = models::Animal::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::Animal::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::ArrayTypes + +```cpp +// Create a model +auto model = models::ArrayTypes(); +model.setStringArray(/* value */); // Set stringArray +model.setIntArray(/* value */); // Set intArray +model.setObjectArray(/* value */); // Set objectArray +model.setEnumArray(/* value */); // Set enumArray +model.setNestedArray(/* value */); // Set nestedArray + +// Serialize to JSON +nlohmann::json json = models::ArrayTypes::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::ArrayTypes::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::BankAccount + +```cpp +// Create a model +auto model = models::BankAccount(); +model.setPaymentType(/* value */); // Set paymentType +model.setAccountNumber(/* value */); // Set accountNumber +model.setBankName(/* value */); // Set bankName + +// Serialize to JSON +nlohmann::json json = models::BankAccount::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::BankAccount::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::Company + +```cpp +// Create a model +auto model = models::Company(); +model.setName(/* value */); // Set name +model.setHeadquarters(/* value */); // Set headquarters +model.setDepartments(/* value */); // Set departments +model.setMetadata(/* value */); // Set metadata + +// Serialize to JSON +nlohmann::json json = models::Company::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::Company::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::CreatedResponse + +```cpp +// Create a model +auto model = models::CreatedResponse(); +model.setStatus(/* value */); // Set status +model.setId(/* value */); // Set id +model.setLocation(/* value */); // Set location + +// Serialize to JSON +nlohmann::json json = models::CreatedResponse::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::CreatedResponse::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::CreditCard + +```cpp +// Create a model +auto model = models::CreditCard(); +model.setPaymentType(/* value */); // Set paymentType +model.setCardNumber(/* value */); // Set cardNumber +model.setCardType(/* value */); // Set cardType + +// Serialize to JSON +nlohmann::json json = models::CreditCard::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::CreditCard::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::Department + +```cpp +// Create a model +auto model = models::Department(); +model.setName(/* value */); // Set name +model.setManager(/* value */); // Set manager +model.setEmployees(/* value */); // Set employees + +// Serialize to JSON +nlohmann::json json = models::Department::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::Department::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::Dog + +```cpp +// Create a model +auto model = models::Dog(); +model.setBreed(/* value */); // Set breed +model.setBarkVolume(/* value */); // Set barkVolume + +// Serialize to JSON +nlohmann::json json = models::Dog::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::Dog::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::Employee + +```cpp +// Create a model +auto model = models::Employee(); +model.setId(/* value */); // Set id +model.setName(/* value */); // Set name +model.setEmail(/* value */); // Set email +model.setAddress(/* value */); // Set address +model.setSkills(/* value */); // Set skills + +// Serialize to JSON +nlohmann::json json = models::Employee::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::Employee::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::EnumTypes + +```cpp +// Create a model +auto model = models::EnumTypes(); +model.setStringEnum(/* value */); // Set stringEnum +model.setNumericEnum(/* value */); // Set numericEnum +model.setStatusCode(/* value */); // Set statusCode + +// Serialize to JSON +nlohmann::json json = models::EnumTypes::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::EnumTypes::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::ErrorResponse + +```cpp +// Create a model +auto model = models::ErrorResponse(); +model.setMessage(/* value */); // Set message +model.setCode(/* value */); // Set code +model.setDetails(/* value */); // Set details + +// Serialize to JSON +nlohmann::json json = models::ErrorResponse::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::ErrorResponse::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::NotFoundResponse + +```cpp +// Create a model +auto model = models::NotFoundResponse(); +model.setError(/* value */); // Set error +model.setResource(/* value */); // Set resource + +// Serialize to JSON +nlohmann::json json = models::NotFoundResponse::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::NotFoundResponse::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::NullableOptionalTypes + +```cpp +// Create a model +auto model = models::NullableOptionalTypes(); +model.setRequiredField(/* value */); // Set requiredField +model.setOptionalField(/* value */); // Set optionalField +model.setNullableField(/* value */); // Set nullableField +model.setOptionalNullableField(/* value */); // Set optionalNullableField +model.setFieldWithDefault(/* value */); // Set fieldWithDefault + +// Serialize to JSON +nlohmann::json json = models::NullableOptionalTypes::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::NullableOptionalTypes::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::PaymentMethod + +```cpp +// Create a model +auto model = models::PaymentMethod(); +model.setPaymentType(/* value */); // Set paymentType +model.setCardNumber(/* value */); // Set cardNumber +model.setCardType(/* value */); // Set cardType +model.setAccountNumber(/* value */); // Set accountNumber +model.setBankName(/* value */); // Set bankName + +// Serialize to JSON +nlohmann::json json = models::PaymentMethod::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::PaymentMethod::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::PrimitiveTypes + +```cpp +// Create a model +auto model = models::PrimitiveTypes(); +model.setStringField(/* value */); // Set stringField +model.setIntField(/* value */); // Set intField +model.setLongField(/* value */); // Set longField +model.setFloatField(/* value */); // Set floatField +model.setDoubleField(/* value */); // Set doubleField +model.setBoolField(/* value */); // Set boolField +model.setByteField(/* value */); // Set byteField +model.setBinaryField(/* value */); // Set binaryField +model.setDateField(/* value */); // Set dateField +model.setDateTimeField(/* value */); // Set dateTimeField +model.setPasswordField(/* value */); // Set passwordField + +// Serialize to JSON +nlohmann::json json = models::PrimitiveTypes::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::PrimitiveTypes::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::SimpleObject + +```cpp +// Create a model +auto model = models::SimpleObject(); +model.setId(/* value */); // Set id +model.setName(/* value */); // Set name +model.setDescription(/* value */); // Set description + +// Serialize to JSON +nlohmann::json json = models::SimpleObject::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::SimpleObject::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::StringOrNumber + +```cpp +// Create a model +auto model = models::StringOrNumber(); + +// Serialize to JSON +nlohmann::json json = models::StringOrNumber::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::StringOrNumber::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::SuccessResponse + +```cpp +// Create a model +auto model = models::SuccessResponse(); +model.setStatus(/* value */); // Set status +model.setData(/* value */); // Set data + +// Serialize to JSON +nlohmann::json json = models::SuccessResponse::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::SuccessResponse::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::TestAllParameterTypes200Response + +```cpp +// Create a model +auto model = models::TestAllParameterTypes200Response(); +model.setMessage(/* value */); // Set message +model.setResourceId(/* value */); // Set resourceId +model.setFilter(/* value */); // Set filter +model.setCorrelationId(/* value */); // Set correlationId + +// Serialize to JSON +nlohmann::json json = models::TestAllParameterTypes200Response::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::TestAllParameterTypes200Response::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::TestApiKeySecurity200Response + +```cpp +// Create a model +auto model = models::TestApiKeySecurity200Response(); +model.setMessage(/* value */); // Set message + +// Serialize to JSON +nlohmann::json json = models::TestApiKeySecurity200Response::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::TestApiKeySecurity200Response::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::TestBasicSecurity200Response + +```cpp +// Create a model +auto model = models::TestBasicSecurity200Response(); +model.setMessage(/* value */); // Set message + +// Serialize to JSON +nlohmann::json json = models::TestBasicSecurity200Response::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::TestBasicSecurity200Response::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::TestBearerSecurity200Response + +```cpp +// Create a model +auto model = models::TestBearerSecurity200Response(); +model.setMessage(/* value */); // Set message + +// Serialize to JSON +nlohmann::json json = models::TestBearerSecurity200Response::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::TestBearerSecurity200Response::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::TestCookieParameters200Response + +```cpp +// Create a model +auto model = models::TestCookieParameters200Response(); +model.setMessage(/* value */); // Set message + +// Serialize to JSON +nlohmann::json json = models::TestCookieParameters200Response::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::TestCookieParameters200Response::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::TestHeaderParameters200Response + +```cpp +// Create a model +auto model = models::TestHeaderParameters200Response(); +model.setMessage(/* value */); // Set message + +// Serialize to JSON +nlohmann::json json = models::TestHeaderParameters200Response::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::TestHeaderParameters200Response::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::TestHeaderParameters401Response + +```cpp +// Create a model +auto model = models::TestHeaderParameters401Response(); +model.setMessage(/* value */); // Set message + +// Serialize to JSON +nlohmann::json json = models::TestHeaderParameters401Response::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::TestHeaderParameters401Response::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::TestOAuth2Security200Response + +```cpp +// Create a model +auto model = models::TestOAuth2Security200Response(); +model.setMessage(/* value */); // Set message + +// Serialize to JSON +nlohmann::json json = models::TestOAuth2Security200Response::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::TestOAuth2Security200Response::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::TestQueryParameters200Response + +```cpp +// Create a model +auto model = models::TestQueryParameters200Response(); +model.setMessage(/* value */); // Set message + +// Serialize to JSON +nlohmann::json json = models::TestQueryParameters200Response::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::TestQueryParameters200Response::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::TestQueryParametersDeepObjectParameter + +```cpp +// Create a model +auto model = models::TestQueryParametersDeepObjectParameter(); +model.setName(/* value */); // Set name +model.setAge(/* value */); // Set age + +// Serialize to JSON +nlohmann::json json = models::TestQueryParametersDeepObjectParameter::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::TestQueryParametersDeepObjectParameter::fromJson(nlohmann::json::parse(jsonString)); +``` + +## Implementing API Handlers + +### API Classes + +Each API is generated as an abstract base class with pure virtual methods that you must implement. + +#### Composition + +Create a class that inherits from the generated base class: + +```cpp +#include "api/CompositionApi.h" + +class CompositionImpl : public api::Composition { +public: + CompositionallofPostResponse handlePostForCompositionallof(const CompositionallofPostRequest& params) override { + // Access request parameters: + // Body: params.m_request (std::optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_DOG): + models::Dog successResponse; + // ... populate response ... + return successResponse; + } + + CompositionanyofPostResponse handlePostForCompositionanyof(const CompositionanyofPostRequest& params) override { + // Access request parameters: + // Body: params.m_request (std::optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_STRING_OR_NUMBER): + models::StringOrNumber successResponse; + // ... populate response ... + return successResponse; + } + + CompositiononeofPostResponse handlePostForCompositiononeof(const CompositiononeofPostRequest& params) override { + // Access request parameters: + // Body: params.m_request (std::optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_PAYMENT_METHOD): + models::PaymentMethod successResponse; + // ... populate response ... + return successResponse; + } + +}; +``` +#### Datatypes + +Create a class that inherits from the generated base class: + +```cpp +#include "api/DatatypesApi.h" + +class DatatypesImpl : public api::Datatypes { +public: + DatatypesarraysPostResponse handlePostForDatatypesarrays(const DatatypesarraysPostRequest& params) override { + // Access request parameters: + // Body: params.m_request (std::optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_ARRAY_TYPES): + models::ArrayTypes successResponse; + // ... populate response ... + return successResponse; + } + + DatatypesenumsPostResponse handlePostForDatatypesenums(const DatatypesenumsPostRequest& params) override { + // Access request parameters: + // Body: params.m_request (std::optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_ENUM_TYPES): + models::EnumTypes successResponse; + // ... populate response ... + return successResponse; + } + + ResponsesmultipleGetResponse handleGetForResponsesmultiple(const ResponsesmultipleGetRequest& params) override { + // Access request parameters: + // Query: params.m_scenario + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_SUCCESS_RESPONSE): + models::SuccessResponse successResponse; + // ... populate response ... + return successResponse; + // Return success response (HTTP HTTP_RESPONSE_CODE_CREATED_RESPONSE): + models::CreatedResponse successResponse; + // ... populate response ... + return successResponse; + + // Or return error response (HTTP HTTP_RESPONSE_CODE_NOT_FOUND_RESPONSE): + // models::NotFoundResponse errorResponse; + // return errorResponse; + + // Or return error response (HTTP HTTP_RESPONSE_CODE_ERROR_RESPONSE): + // models::ErrorResponse errorResponse; + // return errorResponse; + } + + NestedobjectsPostResponse handlePostForNestedobjects(const NestedobjectsPostRequest& params) override { + // Access request parameters: + // Body: params.m_request (std::optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_COMPANY): + models::Company successResponse; + // ... populate response ... + return successResponse; + } + + void handleDeleteForResponsesnocontent(const ResponsesnocontentDeleteRequest& params) override { + // Access request parameters from params struct + // Implement your logic here + } + + NullableoptionalPostResponse handlePostForNullableoptional(const NullableoptionalPostRequest& params) override { + // Access request parameters: + // Body: params.m_request (std::optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_NULLABLE_OPTIONAL_TYPES): + models::NullableOptionalTypes successResponse; + // ... populate response ... + return successResponse; + } + + DatatypesprimitivesPostResponse handlePostForDatatypesprimitives(const DatatypesprimitivesPostRequest& params) override { + // Access request parameters: + // Body: params.m_request (std::optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_PRIMITIVE_TYPES): + models::PrimitiveTypes successResponse; + // ... populate response ... + return successResponse; + + // Or return error response (HTTP HTTP_RESPONSE_CODE_ERROR_RESPONSE): + // models::ErrorResponse errorResponse; + // return errorResponse; + } + +}; +``` +#### Parameters + +Create a class that inherits from the generated base class: + +```cpp +#include "api/ParametersApi.h" + +class ParametersImpl : public api::Parameters { +public: + ParameterscombinedresourceIdPostResponse handlePostForParameterscombinedresourceId(const ParameterscombinedresourceIdPostRequest& params) override { + // Access request parameters: + // Path: params.m_resourceId + // Query: params.m_filter + // Query: params.m_limit (optional) + // Header: params.m_xCorrelationId + // Header: params.m_xClientVersion (optional) + // Body: params.m_request (std::optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_TEST_ALL_PARAMETER_TYPES200_RESPONSE): + models::TestAllParameterTypes200Response successResponse; + // ... populate response ... + return successResponse; + + // Or return error response (HTTP HTTP_RESPONSE_CODE_ERROR_RESPONSE): + // models::ErrorResponse errorResponse; + // return errorResponse; + } + + ParameterscookiesGetResponse handleGetForParameterscookies(const ParameterscookiesGetRequest& params) override { + // Access request parameters: + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_TEST_COOKIE_PARAMETERS200_RESPONSE): + models::TestCookieParameters200Response successResponse; + // ... populate response ... + return successResponse; + } + + ParametersheadersGetResponse handleGetForParametersheaders(const ParametersheadersGetRequest& params) override { + // Access request parameters: + // Header: params.m_xApiVersion + // Header: params.m_xRequestId (optional) + // Header: params.m_xRateLimit (optional) + // Header: params.m_xTags (optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_TEST_HEADER_PARAMETERS200_RESPONSE): + models::TestHeaderParameters200Response successResponse; + // ... populate response ... + return successResponse; + + // Or return error response (HTTP HTTP_RESPONSE_CODE_TEST_HEADER_PARAMETERS401_RESPONSE): + // models::TestHeaderParameters401Response errorResponse; + // return errorResponse; + } + + ParametersquerypathIdGetResponse handleGetForParametersquerypathId(const ParametersquerypathIdGetRequest& params) override { + // Access request parameters: + // Path: params.m_pathId + // Query: params.m_stringParam + // Query: params.m_intParam (optional) + // Query: params.m_boolParam (optional) + // Query: params.m_arrayParam (optional) + // Query: params.m_spaceDelimited (optional) + // Query: params.m_pipeDelimited (optional) + // Query: params.m_deepObject (optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_TEST_QUERY_PARAMETERS200_RESPONSE): + models::TestQueryParameters200Response successResponse; + // ... populate response ... + return successResponse; + } + +}; +``` +#### Security + +Create a class that inherits from the generated base class: + +```cpp +#include "api/SecurityApi.h" + +class SecurityImpl : public api::Security { +public: + SecurityapikeyGetResponse handleGetForSecurityapikey() override { + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_TEST_API_KEY_SECURITY200_RESPONSE): + models::TestApiKeySecurity200Response successResponse; + // ... populate response ... + return successResponse; + + // Or return error response (HTTP HTTP_RESPONSE_CODE_ERROR_RESPONSE): + // models::ErrorResponse errorResponse; + // return errorResponse; + } + + SecuritybasicGetResponse handleGetForSecuritybasic() override { + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_TEST_BASIC_SECURITY200_RESPONSE): + models::TestBasicSecurity200Response successResponse; + // ... populate response ... + return successResponse; + + // Or return error response (HTTP HTTP_RESPONSE_CODE_ERROR_RESPONSE): + // models::ErrorResponse errorResponse; + // return errorResponse; + } + + SecuritybearerGetResponse handleGetForSecuritybearer() override { + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_TEST_BEARER_SECURITY200_RESPONSE): + models::TestBearerSecurity200Response successResponse; + // ... populate response ... + return successResponse; + + // Or return error response (HTTP HTTP_RESPONSE_CODE_ERROR_RESPONSE): + // models::ErrorResponse errorResponse; + // return errorResponse; + } + + Securityoauth2getResponse handleGetForSecurityoauth2() override { + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_TEST_O_AUTH2_SECURITY200_RESPONSE): + models::TestOAuth2Security200Response successResponse; + // ... populate response ... + return successResponse; + + // Or return error response (HTTP HTTP_RESPONSE_CODE_ERROR_RESPONSE): + // models::ErrorResponse errorResponse; + // return errorResponse; + } + +}; +``` + +## Running the Server + +Here's a complete example of setting up and running the server: + +```cpp +#include +#include + +#include "api/CompositionApi.h" + +#include "api/DatatypesApi.h" + +#include "api/ParametersApi.h" + +#include "api/SecurityApi.h" + +#include "api/AuthenticationManager.h" + +int main() { + httplib::Server server; + + // Create authentication manager (required for this API) + auto authMgr = std::make_shared(); + + // Create API implementations + + CompositionImpl composition; + + DatatypesImpl datatypes; + + ParametersImpl parameters; + + SecurityImpl security; + + + // Register routes + + composition.registerRoutes(server, authMgr); + + datatypes.registerRoutes(server, authMgr); + + parameters.registerRoutes(server, authMgr); + + security.registerRoutes(server, authMgr); + + + // Start server + std::cout << "Server starting on http://localhost:8080" << std::endl; + server.listen("localhost", 8080); + + return 0; +} +``` + +### With Authentication + +When authentication is required, you must: +1. Implement the `AuthenticationManager` interface (see Authentication section below) +2. Pass the authentication manager to `registerRoutes()` + + +## Authentication + +This API requires authentication. Implement the `AuthenticationManager` interface to provide your authentication logic: + +```cpp +#include "api/AuthenticationManager.h" + +class MyAuthManager : public api::AuthenticationManager { +public: + bool validateApiKey(const std::string& key) override { + // Validate API key from header, query, or cookie + // Example: check against database or cache + return checkApiKeyInDatabase(key); + } + + bool validateBearerToken(const std::string& token) override { + // Validate JWT or other bearer tokens + // Example: verify signature and expiration + return jwt::verify(token, secret_key); + } + + bool validateBasicAuth(const std::string& username, const std::string& password) override { + // Validate username/password credentials + // Example: check against user database with hashed passwords + auto user = findUser(username); + return user && bcrypt::verify(password, user->passwordHash); + } + + bool validateOAuth2(const std::string& token, const std::vector& scopes) override { + // Validate OAuth2 token and check required scopes + // Example: introspect token and verify scopes + auto introspection = oauthProvider.introspect(token); + return introspection.active && hasAllScopes(introspection.scopes, scopes); + } +}; +``` + +### Authentication Flow + +1. The server automatically extracts credentials from requests (headers, query params, cookies) +2. Before calling your handler, it validates credentials using your `AuthenticationManager` +3. If validation fails, the server returns HTTP 401 Unauthorized automatically +4. If validation succeeds, your handler is called + +### Security Schemes + +The generated code supports: +- **API Key**: Header, query parameter, or cookie-based authentication +- **Bearer Token**: Authorization header with "Bearer" scheme (e.g., JWT) +- **Basic Auth**: HTTP Basic authentication (username:password) +- **OAuth2**: OAuth 2.0 token-based authentication with scope validation + + +## Error Handling + +### Response Variants + +Each API endpoint that returns data uses `std::variant` to represent multiple possible response types (success and errors): + +```cpp +// Example: endpoint returns success (User) or errors (NotFound, ServerError) +using GetUserResponse = std::variant; + +GetUserResponse handleGetUser(const GetUserRequest& params) override { + if (userExists(params.m_userId)) { + User user = fetchUser(params.m_userId); + return user; // Automatically sets HTTP 200 + } else { + NotFound error; + error.setMessage("User not found"); + return error; // Automatically sets HTTP 404 + } +} +``` + +The server automatically: +- Detects which type is returned from the variant +- Sets the appropriate HTTP status code +- Serializes the response to JSON + +### HTTP Status Codes + +Status codes are automatically set based on the response type you return. Each model type is associated with a specific HTTP status code defined in your OpenAPI specification. + +**Optimized Status Code Constants:** +The generator only creates HTTP status code constants (e.g., `HTTP_RESPONSE_CODE_200`, `HTTP_RESPONSE_CODE_404`) for codes actually used by your API operations. This reduces code bloat and compilation time compared to generating all possible HTTP status codes. + +### Parameter Validation + +The generated code automatically validates: +- **Required parameters**: Returns HTTP 400 if missing +- **Type conversion**: Returns HTTP 400 if parameter cannot be converted to expected type +- **JSON parsing**: Returns HTTP 400 if request body is invalid JSON + +Custom validation logic should be implemented in your handler methods. + +### Working with Optional Parameters + +Optional parameters and model fields use `std::optional`: + +```cpp +void handleRequest(const RequestParams& params) override { + // Check if optional query parameter is present + if (params.m_optionalParam) { + auto value = *params.m_optionalParam; // Dereference to get value + // Use value... + } + + // Check if optional request body is present + if (params.m_request) { + auto body = *params.m_request; // Dereference to get body + // Use body... + } +} +``` + +## Advanced Features + +### Parameter Serialization Styles + +The generator supports various parameter serialization styles as defined in OpenAPI: + +- **simple**: Comma-separated values (default for path/header) +- **form**: Ampersand-separated values (default for query) +- **spaceDelimited**: Space-separated values +- **pipeDelimited**: Pipe-separated values +- **deepObject**: Nested object notation for query parameters + +These are automatically handled during parameter parsing. + +### Enum Handling + +All generated enums automatically include an `UNSPECIFIED` value as the first enum entry for safe initialization: + +```cpp +enum class Status { + UNSPECIFIED = 0, // Added automatically for safety + PENDING, + APPROVED, + REJECTED +}; + +// Safe default initialization +Status status; // Defaults to UNSPECIFIED (0) + +// Explicit initialization +Status activeStatus = Status::APPROVED; + +// Enum serialization/deserialization +// UNSPECIFIED is not a valid API value and indicates uninitialized state +``` + +**Why UNSPECIFIED?** +- Provides a safe default value for uninitialized enums +- Prevents undefined behavior from using uninitialized enum values +- Makes it clear when an enum hasn't been set vs. having a valid API value +- Does not appear in OpenAPI spec - internal C++ implementation detail + +### Union Types (anyOf/oneOf) + +When your OpenAPI spec uses `anyOf` or `oneOf`, the generated code uses `std::variant`: + +```cpp +// OpenAPI: { "anyOf": [{"type": "string"}, {"type": "number"}] } +using MyUnionType = std::variant; + +// In your model: +MyUnionType value; + +// Use std::visit to handle different types: +std::visit([](const auto& v) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + std::cout << "String: " << v << std::endl; + } else if constexpr (std::is_same_v) { + std::cout << "Number: " << v << std::endl; + } +}, value); +``` + +## Additional Resources + +- [cpp-httplib Documentation](https://github.com/yhirose/cpp-httplib) +- [nlohmann/json Documentation](https://github.com/nlohmann/json) +- [OpenAPI Generator Documentation](https://openapi-generator.tech/docs/generators/cpp-httplib-server) +- [OpenAPI Specification](https://swagger.io/specification/) + +- [cpp-httplib Documentation](https://github.com/yhirose/cpp-httplib) +- [nlohmann/json Documentation](https://github.com/nlohmann/json) +- [OpenAPI Generator Documentation](https://openapi-generator.tech/docs/generators/) diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/api/AuthenticationManager.h b/samples/server/petstore/cpp-httplib-server/feature-test/api/AuthenticationManager.h new file mode 100644 index 000000000000..63a50f854e00 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/api/AuthenticationManager.h @@ -0,0 +1,79 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once + +#include +#include +#include + +namespace api { + +/** + * @brief Authentication Manager Interface + * + * This interface defines the contract for authentication validation. + * Users must implement this interface to provide their own authentication logic. + * + * Example implementation: + * @code + * class MyAuthManager : public AuthenticationManager { + * public: + * bool validateApiKey(const std::string& key) override { + * return database.checkApiKey(key); + * } + * + * bool validateBearerToken(const std::string& token) override { + * return jwt::verify(token, secret); + * } + * + * bool validateBasicAuth(const std::string& username, const std::string& password) override { + * return bcrypt::verify(password, database.getPasswordHash(username)); + * } + * + * bool validateOAuth2(const std::string& token, const std::vector& scopes) override { + * auto introspection = oauthProvider.introspect(token); + * return introspection.active && hasRequiredScopes(introspection, scopes); + * } + * }; + * @endcode + */ +class AuthenticationManager { +public: + virtual ~AuthenticationManager() = default; + + /** + * @brief Validate an API key + * @param key The API key to validate + * @return true if the API key is valid, false otherwise + */ + virtual bool validateApiKey(const std::string& key) = 0; + + /** + * @brief Validate a Bearer token (e.g., JWT) + * @param token The bearer token to validate + * @return true if the token is valid, false otherwise + */ + virtual bool validateBearerToken(const std::string& token) = 0; + + /** + * @brief Validate Basic authentication credentials + * @param username The username + * @param password The password + * @return true if the credentials are valid, false otherwise + */ + virtual bool validateBasicAuth(const std::string& username, const std::string& password) = 0; + + /** + * @brief Validate an OAuth2 token with required scopes + * @param token The OAuth2 access token + * @param scopes The required scopes for this operation + * @return true if the token is valid and has required scopes, false otherwise + */ + virtual bool validateOAuth2(const std::string& token, const std::vector& scopes) = 0; +}; + +} // namespace api diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/api/CompositionApi.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/api/CompositionApi.cpp new file mode 100644 index 000000000000..43744d360a5f --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/api/CompositionApi.cpp @@ -0,0 +1,323 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +// System headers +#include +#include +#include + +// Project headers +#include "CompositionApi.h" + +constexpr int HTTP_RESPONSE_CODE_DOG = 200; +constexpr int HTTP_RESPONSE_CODE_STRING_OR_NUMBER = 200; +constexpr int HTTP_RESPONSE_CODE_PAYMENT_METHOD = 200; +constexpr int HTTP_RESPONSE_CODE_BAD_REQUEST = 400; +constexpr int HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR = 500; + +namespace api { + +using namespace models; + +bool Composition::parseCompositionallofPostParams(const httplib::Request& req, Composition::CompositionallofPostRequest& params, std::vector& paramErrors) +{ + std::vector errors; + if (!req.body.empty()) + { + try + { + nlohmann::json json = nlohmann::json::parse(req.body); + from_json(json, params.m_request); + } + catch (const std::exception& e) + { + errors.push_back("Invalid request body: " + std::string(e.what())); + } + } + else + { + errors.push_back("Missing required request body"); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Composition::handleCompositionallofPostResponse(const CompositionallofPostResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_DOG; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} +bool Composition::parseCompositionanyofPostParams(const httplib::Request& req, Composition::CompositionanyofPostRequest& params, std::vector& paramErrors) +{ + std::vector errors; + if (!req.body.empty()) + { + try + { + nlohmann::json json = nlohmann::json::parse(req.body); + from_json(json, params.m_request); + } + catch (const std::exception& e) + { + errors.push_back("Invalid request body: " + std::string(e.what())); + } + } + else + { + errors.push_back("Missing required request body"); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Composition::handleCompositionanyofPostResponse(const CompositionanyofPostResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_STRING_OR_NUMBER; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} +bool Composition::parseCompositiononeofPostParams(const httplib::Request& req, Composition::CompositiononeofPostRequest& params, std::vector& paramErrors) +{ + std::vector errors; + if (!req.body.empty()) + { + try + { + nlohmann::json json = nlohmann::json::parse(req.body); + from_json(json, params.m_request); + } + catch (const std::exception& e) + { + errors.push_back("Invalid request body: " + std::string(e.what())); + } + } + else + { + errors.push_back("Missing required request body"); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Composition::handleCompositiononeofPostResponse(const CompositiononeofPostResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_PAYMENT_METHOD; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} + + +void Composition::handleCompositionallofPostRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + CompositionallofPostRequest params; + std::vector paramErrors; + if (!parseCompositionallofPostParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handlePostForCompositionallof(params); + handleCompositionallofPostResponse(result, res); + + } + catch (const nlohmann::json::parse_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::invalid_iterator& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::type_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::other_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Composition::handleCompositionanyofPostRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + CompositionanyofPostRequest params; + std::vector paramErrors; + if (!parseCompositionanyofPostParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handlePostForCompositionanyof(params); + handleCompositionanyofPostResponse(result, res); + + } + catch (const nlohmann::json::parse_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::invalid_iterator& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::type_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::other_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Composition::handleCompositiononeofPostRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + CompositiononeofPostRequest params; + std::vector paramErrors; + if (!parseCompositiononeofPostParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handlePostForCompositiononeof(params); + handleCompositiononeofPostResponse(result, res); + + } + catch (const nlohmann::json::parse_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::invalid_iterator& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::type_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::other_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } +} + + +void Composition::registerRoutes(httplib::Server& svr) +{ + svr.Post("/composition/allof", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleCompositionallofPostRequest(req, res); + }); + svr.Post("/composition/anyof", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleCompositionanyofPostRequest(req, res); + }); + svr.Post("/composition/oneof", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleCompositiononeofPostRequest(req, res); + }); +} + +} // namespace api \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/api/CompositionApi.h b/samples/server/petstore/cpp-httplib-server/feature-test/api/CompositionApi.h new file mode 100644 index 000000000000..9a6a96e71eef --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/api/CompositionApi.h @@ -0,0 +1,113 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once + +// System headers +#include +#include +#include +#include + +// Project headers +#include "models/Dog.h" +#include "models/PaymentMethod.h" +#include "models/StringOrNumber.h" + +namespace api { + class AuthenticationManager; +class Composition { +public: + Composition() = default; + virtual ~Composition() = default; + /** + * @brief Register all routes for this API + * @param svr The httplib::Server instance to register routes on + */ + void registerRoutes(httplib::Server& svr); + // ========================= + // ===== Request types ===== + // ========================= + + /** + * @brief Request type for handlePostForCompositionallof. + */ + struct CompositionallofPostRequest + { + models::Dog m_request; //Request Body (required) + }; + + /** + * @brief Request type for handlePostForCompositionanyof. + */ + struct CompositionanyofPostRequest + { + models::StringOrNumber m_request; //Request Body (required) + }; + + /** + * @brief Request type for handlePostForCompositiononeof. + */ + struct CompositiononeofPostRequest + { + models::PaymentMethod m_request; //Request Body (required) + }; + + // ========================== + // ===== Response types ===== + // ========================== + + /** + * @brief Response type for handlePostForCompositionallof. + */ + using CompositionallofPostResponse = models::Dog; + + /** + * @brief Response type for handlePostForCompositionanyof. + */ + using CompositionanyofPostResponse = models::StringOrNumber; + + /** + * @brief Response type for handlePostForCompositiononeof. + */ + using CompositiononeofPostResponse = models::PaymentMethod; + // ============================================================ + // ===== Pure virtual functions to be handled by the user ===== + // ============================================================ + /** + * CompositionallofPostRequest - struct containing all the query parameters and headers and schemas as available. + * @return CompositionallofPostResponse The response type returned by the handler. + */ + virtual CompositionallofPostResponse handlePostForCompositionallof(const CompositionallofPostRequest& params)=0; + + /** + * CompositionanyofPostRequest - struct containing all the query parameters and headers and schemas as available. + * @return CompositionanyofPostResponse The response type returned by the handler. + */ + virtual CompositionanyofPostResponse handlePostForCompositionanyof(const CompositionanyofPostRequest& params)=0; + + /** + * CompositiononeofPostRequest - struct containing all the query parameters and headers and schemas as available. + * @return CompositiononeofPostResponse The response type returned by the handler. + */ + virtual CompositiononeofPostResponse handlePostForCompositiononeof(const CompositiononeofPostRequest& params)=0; + +private: + // ======================================== + // ===== Helper function declarations ===== + // ======================================== + static bool parseCompositionallofPostParams(const httplib::Request& req, CompositionallofPostRequest& params, std::vector& paramErrors); + void handleCompositionallofPostRequest(const httplib::Request& req, httplib::Response& res); + static void handleCompositionallofPostResponse(const CompositionallofPostResponse& result, httplib::Response& res); + static bool parseCompositionanyofPostParams(const httplib::Request& req, CompositionanyofPostRequest& params, std::vector& paramErrors); + void handleCompositionanyofPostRequest(const httplib::Request& req, httplib::Response& res); + static void handleCompositionanyofPostResponse(const CompositionanyofPostResponse& result, httplib::Response& res); + static bool parseCompositiononeofPostParams(const httplib::Request& req, CompositiononeofPostRequest& params, std::vector& paramErrors); + void handleCompositiononeofPostRequest(const httplib::Request& req, httplib::Response& res); + static void handleCompositiononeofPostResponse(const CompositiononeofPostResponse& result, httplib::Response& res); +}; + +} // namespace api \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/api/DatatypesApi.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/api/DatatypesApi.cpp new file mode 100644 index 000000000000..9eb36ae26c40 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/api/DatatypesApi.cpp @@ -0,0 +1,690 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +// System headers +#include +#include +#include + +// Project headers +#include "DatatypesApi.h" + +constexpr int HTTP_RESPONSE_CODE_ARRAY_TYPES = 200; +constexpr int HTTP_RESPONSE_CODE_ENUM_TYPES = 200; +constexpr int HTTP_RESPONSE_CODE_SUCCESS_RESPONSE = 200; +constexpr int HTTP_RESPONSE_CODE_CREATED_RESPONSE = 201; +constexpr int HTTP_RESPONSE_CODE_NOT_FOUND_RESPONSE = 404; +constexpr int HTTP_RESPONSE_CODE_ERROR_RESPONSE = 500; +constexpr int HTTP_RESPONSE_CODE_COMPANY = 200; +constexpr int HTTP_RESPONSE_CODE_NULLABLE_OPTIONAL_TYPES = 200; +constexpr int HTTP_RESPONSE_CODE_PRIMITIVE_TYPES = 200; +constexpr int HTTP_RESPONSE_CODE_NO_CONTENT = 204; +constexpr int HTTP_RESPONSE_CODE_BAD_REQUEST = 400; + +namespace api { + +using namespace models; + +bool Datatypes::parseDatatypesarraysPostParams(const httplib::Request& req, Datatypes::DatatypesarraysPostRequest& params, std::vector& paramErrors) +{ + std::vector errors; + if (!req.body.empty()) + { + try + { + nlohmann::json json = nlohmann::json::parse(req.body); + from_json(json, params.m_request); + } + catch (const std::exception& e) + { + errors.push_back("Invalid request body: " + std::string(e.what())); + } + } + else + { + errors.push_back("Missing required request body"); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Datatypes::handleDatatypesarraysPostResponse(const DatatypesarraysPostResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_ARRAY_TYPES; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} +bool Datatypes::parseDatatypesenumsPostParams(const httplib::Request& req, Datatypes::DatatypesenumsPostRequest& params, std::vector& paramErrors) +{ + std::vector errors; + if (!req.body.empty()) + { + try + { + nlohmann::json json = nlohmann::json::parse(req.body); + from_json(json, params.m_request); + } + catch (const std::exception& e) + { + errors.push_back("Invalid request body: " + std::string(e.what())); + } + } + else + { + errors.push_back("Missing required request body"); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Datatypes::handleDatatypesenumsPostResponse(const DatatypesenumsPostResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_ENUM_TYPES; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} +bool Datatypes::parseResponsesmultipleGetParams(const httplib::Request& req, Datatypes::ResponsesmultipleGetRequest& params, std::vector& paramErrors) +{ + std::vector errors; + + // Query Parameters - scenario + if (req.has_param("scenario")) + { + try + { + params.m_scenario = (req.get_param_value("scenario")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter 'scenario': " + std::string(e.what())); + } + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Datatypes::handleResponsesmultipleGetResponse(const ResponsesmultipleGetResponse& result, httplib::Response& res) +{ + std::visit([&](const auto& value) + { + using T = std::decay_t; + + // Success types + if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_SUCCESS_RESPONSE; + nlohmann::json responseJson; + to_json(responseJson, value); + res.set_content(responseJson.dump(), "application/json"); + }else if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_CREATED_RESPONSE; + nlohmann::json responseJson; + to_json(responseJson, value); + res.set_content(responseJson.dump(), "application/json"); + } + // Error types + else if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_NOT_FOUND_RESPONSE; + nlohmann::json errorJson = value; + res.set_content(errorJson.dump(), "application/json"); + } + else if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + nlohmann::json errorJson = value; + res.set_content(errorJson.dump(), "application/json"); + } + }, result); +} +bool Datatypes::parseNestedobjectsPostParams(const httplib::Request& req, Datatypes::NestedobjectsPostRequest& params, std::vector& paramErrors) +{ + std::vector errors; + if (!req.body.empty()) + { + try + { + nlohmann::json json = nlohmann::json::parse(req.body); + from_json(json, params.m_request); + } + catch (const std::exception& e) + { + errors.push_back("Invalid request body: " + std::string(e.what())); + } + } + else + { + errors.push_back("Missing required request body"); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Datatypes::handleNestedobjectsPostResponse(const NestedobjectsPostResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_COMPANY; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} +bool Datatypes::parseResponsesnocontentDeleteParams(const httplib::Request& req, Datatypes::ResponsesnocontentDeleteRequest& params, std::vector& paramErrors) +{ + std::vector errors; + + // Query Parameters - id + if (req.has_param("id")) + { + try + { + params.m_id = std::stoi(req.get_param_value("id")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter 'id': " + std::string(e.what())); + } + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +bool Datatypes::parseNullableoptionalPostParams(const httplib::Request& req, Datatypes::NullableoptionalPostRequest& params, std::vector& paramErrors) +{ + std::vector errors; + if (!req.body.empty()) + { + try + { + nlohmann::json json = nlohmann::json::parse(req.body); + from_json(json, params.m_request); + } + catch (const std::exception& e) + { + errors.push_back("Invalid request body: " + std::string(e.what())); + } + } + else + { + errors.push_back("Missing required request body"); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Datatypes::handleNullableoptionalPostResponse(const NullableoptionalPostResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_NULLABLE_OPTIONAL_TYPES; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} +bool Datatypes::parseDatatypesprimitivesPostParams(const httplib::Request& req, Datatypes::DatatypesprimitivesPostRequest& params, std::vector& paramErrors) +{ + std::vector errors; + if (!req.body.empty()) + { + try + { + nlohmann::json json = nlohmann::json::parse(req.body); + from_json(json, params.m_request); + } + catch (const std::exception& e) + { + errors.push_back("Invalid request body: " + std::string(e.what())); + } + } + else + { + errors.push_back("Missing required request body"); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Datatypes::handleDatatypesprimitivesPostResponse(const DatatypesprimitivesPostResponse& result, httplib::Response& res) +{ + std::visit([&](const auto& value) + { + using T = std::decay_t; + + // Success types + if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_PRIMITIVE_TYPES; + nlohmann::json responseJson; + to_json(responseJson, value); + res.set_content(responseJson.dump(), "application/json"); + } + // Error types + else if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + nlohmann::json errorJson = value; + res.set_content(errorJson.dump(), "application/json"); + } + }, result); +} + + +void Datatypes::handleDatatypesarraysPostRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + DatatypesarraysPostRequest params; + std::vector paramErrors; + if (!parseDatatypesarraysPostParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handlePostForDatatypesarrays(params); + handleDatatypesarraysPostResponse(result, res); + + } + catch (const nlohmann::json::parse_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::invalid_iterator& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::type_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::other_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Datatypes::handleDatatypesenumsPostRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + DatatypesenumsPostRequest params; + std::vector paramErrors; + if (!parseDatatypesenumsPostParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handlePostForDatatypesenums(params); + handleDatatypesenumsPostResponse(result, res); + + } + catch (const nlohmann::json::parse_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::invalid_iterator& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::type_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::other_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Datatypes::handleResponsesmultipleGetRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + ResponsesmultipleGetRequest params; + std::vector paramErrors; + if (!parseResponsesmultipleGetParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handleGetForResponsesmultiple(params); + handleResponsesmultipleGetResponse(result, res); + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Datatypes::handleNestedobjectsPostRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + NestedobjectsPostRequest params; + std::vector paramErrors; + if (!parseNestedobjectsPostParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handlePostForNestedobjects(params); + handleNestedobjectsPostResponse(result, res); + + } + catch (const nlohmann::json::parse_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::invalid_iterator& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::type_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::other_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Datatypes::handleResponsesnocontentDeleteRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + ResponsesnocontentDeleteRequest params; + std::vector paramErrors; + if (!parseResponsesnocontentDeleteParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + + handleDeleteForResponsesnocontent(params); + res.status = HTTP_RESPONSE_CODE_NO_CONTENT; + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Datatypes::handleNullableoptionalPostRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + NullableoptionalPostRequest params; + std::vector paramErrors; + if (!parseNullableoptionalPostParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handlePostForNullableoptional(params); + handleNullableoptionalPostResponse(result, res); + + } + catch (const nlohmann::json::parse_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::invalid_iterator& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::type_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::other_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Datatypes::handleDatatypesprimitivesPostRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + DatatypesprimitivesPostRequest params; + std::vector paramErrors; + if (!parseDatatypesprimitivesPostParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handlePostForDatatypesprimitives(params); + handleDatatypesprimitivesPostResponse(result, res); + + } + catch (const nlohmann::json::parse_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::invalid_iterator& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::type_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::other_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } +} + + +void Datatypes::registerRoutes(httplib::Server& svr) +{ + svr.Post("/datatypes/arrays", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleDatatypesarraysPostRequest(req, res); + }); + svr.Post("/datatypes/enums", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleDatatypesenumsPostRequest(req, res); + }); + svr.Get("/responses/multiple", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleResponsesmultipleGetRequest(req, res); + }); + svr.Post("/nested/objects", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleNestedobjectsPostRequest(req, res); + }); + svr.Delete("/responses/nocontent", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleResponsesnocontentDeleteRequest(req, res); + }); + svr.Post("/nullable/optional", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleNullableoptionalPostRequest(req, res); + }); + svr.Post("/datatypes/primitives", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleDatatypesprimitivesPostRequest(req, res); + }); +} + +} // namespace api \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/api/DatatypesApi.h b/samples/server/petstore/cpp-httplib-server/feature-test/api/DatatypesApi.h new file mode 100644 index 000000000000..2b9d192e147c --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/api/DatatypesApi.h @@ -0,0 +1,208 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once + +// System headers +#include +#include +#include +#include + +// Project headers +#include "models/ArrayTypes.h" +#include "models/Company.h" +#include "models/CreatedResponse.h" +#include "models/EnumTypes.h" +#include "models/ErrorResponse.h" +#include "models/NotFoundResponse.h" +#include "models/NullableOptionalTypes.h" +#include "models/PrimitiveTypes.h" +#include "models/SuccessResponse.h" + +namespace api { + class AuthenticationManager; +class Datatypes { +public: + Datatypes() = default; + virtual ~Datatypes() = default; + /** + * @brief Register all routes for this API + * @param svr The httplib::Server instance to register routes on + */ + void registerRoutes(httplib::Server& svr); + // ========================= + // ===== Request types ===== + // ========================= + + /** + * @brief Request type for handlePostForDatatypesarrays. + */ + struct DatatypesarraysPostRequest + { + models::ArrayTypes m_request; //Request Body (required) + }; + + /** + * @brief Request type for handlePostForDatatypesenums. + */ + struct DatatypesenumsPostRequest + { + models::EnumTypes m_request; //Request Body (required) + }; + + /** + * @brief Request type for handleGetForResponsesmultiple. + */ + struct ResponsesmultipleGetRequest + { + + std::string m_scenario; //Query Params (required) + }; + + /** + * @brief Request type for handlePostForNestedobjects. + */ + struct NestedobjectsPostRequest + { + models::Company m_request; //Request Body (required) + }; + + /** + * @brief Request type for handleDeleteForResponsesnocontent. + */ + struct ResponsesnocontentDeleteRequest + { + + int m_id; //Query Params (required) + }; + + /** + * @brief Request type for handlePostForNullableoptional. + */ + struct NullableoptionalPostRequest + { + models::NullableOptionalTypes m_request; //Request Body (required) + }; + + /** + * @brief Request type for handlePostForDatatypesprimitives. + */ + struct DatatypesprimitivesPostRequest + { + models::PrimitiveTypes m_request; //Request Body (required) + }; + + // ========================== + // ===== Response types ===== + // ========================== + + /** + * @brief Response type for handlePostForDatatypesarrays. + */ + using DatatypesarraysPostResponse = models::ArrayTypes; + + /** + * @brief Response type for handlePostForDatatypesenums. + */ + using DatatypesenumsPostResponse = models::EnumTypes; + + /** + * @brief Response type for handleGetForResponsesmultiple. + */ + using ResponsesmultipleGetResponse = std::variant< + models::SuccessResponse , + models::CreatedResponse , + models::NotFoundResponse , + models::ErrorResponse >; + + /** + * @brief Response type for handlePostForNestedobjects. + */ + using NestedobjectsPostResponse = models::Company; + + /** + * @brief Response type for handlePostForNullableoptional. + */ + using NullableoptionalPostResponse = models::NullableOptionalTypes; + + /** + * @brief Response type for handlePostForDatatypesprimitives. + */ + using DatatypesprimitivesPostResponse = std::variant< + models::PrimitiveTypes , + models::ErrorResponse >; + // ============================================================ + // ===== Pure virtual functions to be handled by the user ===== + // ============================================================ + /** + * DatatypesarraysPostRequest - struct containing all the query parameters and headers and schemas as available. + * @return DatatypesarraysPostResponse The response type returned by the handler. + */ + virtual DatatypesarraysPostResponse handlePostForDatatypesarrays(const DatatypesarraysPostRequest& params)=0; + + /** + * DatatypesenumsPostRequest - struct containing all the query parameters and headers and schemas as available. + * @return DatatypesenumsPostResponse The response type returned by the handler. + */ + virtual DatatypesenumsPostResponse handlePostForDatatypesenums(const DatatypesenumsPostRequest& params)=0; + + /** + * ResponsesmultipleGetRequest - struct containing all the query parameters and headers and schemas as available. + * @return ResponsesmultipleGetResponse The response type returned by the handler. + */ + virtual ResponsesmultipleGetResponse handleGetForResponsesmultiple(const ResponsesmultipleGetRequest& params)=0; + + /** + * NestedobjectsPostRequest - struct containing all the query parameters and headers and schemas as available. + * @return NestedobjectsPostResponse The response type returned by the handler. + */ + virtual NestedobjectsPostResponse handlePostForNestedobjects(const NestedobjectsPostRequest& params)=0; + + /** + * ResponsesnocontentDeleteRequest - struct containing all the query parameters and headers and schemas as available. + */ + virtual void handleDeleteForResponsesnocontent(const ResponsesnocontentDeleteRequest& params)=0; + + /** + * NullableoptionalPostRequest - struct containing all the query parameters and headers and schemas as available. + * @return NullableoptionalPostResponse The response type returned by the handler. + */ + virtual NullableoptionalPostResponse handlePostForNullableoptional(const NullableoptionalPostRequest& params)=0; + + /** + * DatatypesprimitivesPostRequest - struct containing all the query parameters and headers and schemas as available. + * @return DatatypesprimitivesPostResponse The response type returned by the handler. + */ + virtual DatatypesprimitivesPostResponse handlePostForDatatypesprimitives(const DatatypesprimitivesPostRequest& params)=0; + +private: + // ======================================== + // ===== Helper function declarations ===== + // ======================================== + static bool parseDatatypesarraysPostParams(const httplib::Request& req, DatatypesarraysPostRequest& params, std::vector& paramErrors); + void handleDatatypesarraysPostRequest(const httplib::Request& req, httplib::Response& res); + static void handleDatatypesarraysPostResponse(const DatatypesarraysPostResponse& result, httplib::Response& res); + static bool parseDatatypesenumsPostParams(const httplib::Request& req, DatatypesenumsPostRequest& params, std::vector& paramErrors); + void handleDatatypesenumsPostRequest(const httplib::Request& req, httplib::Response& res); + static void handleDatatypesenumsPostResponse(const DatatypesenumsPostResponse& result, httplib::Response& res); + static bool parseResponsesmultipleGetParams(const httplib::Request& req, ResponsesmultipleGetRequest& params, std::vector& paramErrors); + void handleResponsesmultipleGetRequest(const httplib::Request& req, httplib::Response& res); + static void handleResponsesmultipleGetResponse(const ResponsesmultipleGetResponse& result, httplib::Response& res); + static bool parseNestedobjectsPostParams(const httplib::Request& req, NestedobjectsPostRequest& params, std::vector& paramErrors); + void handleNestedobjectsPostRequest(const httplib::Request& req, httplib::Response& res); + static void handleNestedobjectsPostResponse(const NestedobjectsPostResponse& result, httplib::Response& res); + static bool parseResponsesnocontentDeleteParams(const httplib::Request& req, ResponsesnocontentDeleteRequest& params, std::vector& paramErrors); + void handleResponsesnocontentDeleteRequest(const httplib::Request& req, httplib::Response& res); + static bool parseNullableoptionalPostParams(const httplib::Request& req, NullableoptionalPostRequest& params, std::vector& paramErrors); + void handleNullableoptionalPostRequest(const httplib::Request& req, httplib::Response& res); + static void handleNullableoptionalPostResponse(const NullableoptionalPostResponse& result, httplib::Response& res); + static bool parseDatatypesprimitivesPostParams(const httplib::Request& req, DatatypesprimitivesPostRequest& params, std::vector& paramErrors); + void handleDatatypesprimitivesPostRequest(const httplib::Request& req, httplib::Response& res); + static void handleDatatypesprimitivesPostResponse(const DatatypesprimitivesPostResponse& result, httplib::Response& res); +}; + +} // namespace api \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/api/ParametersApi.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/api/ParametersApi.cpp new file mode 100644 index 000000000000..fb16c3dd891d --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/api/ParametersApi.cpp @@ -0,0 +1,775 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +// System headers +#include +#include +#include + +// Project headers +#include "ParametersApi.h" + +constexpr int HTTP_RESPONSE_CODE_TEST_ALL_PARAMETER_TYPES200_RESPONSE = 200; +constexpr int HTTP_RESPONSE_CODE_ERROR_RESPONSE = 400; +constexpr int HTTP_RESPONSE_CODE_TEST_COOKIE_PARAMETERS200_RESPONSE = 200; +constexpr int HTTP_RESPONSE_CODE_TEST_HEADER_PARAMETERS200_RESPONSE = 200; +constexpr int HTTP_RESPONSE_CODE_TEST_HEADER_PARAMETERS401_RESPONSE = 401; +constexpr int HTTP_RESPONSE_CODE_TEST_QUERY_PARAMETERS200_RESPONSE = 200; +constexpr int HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR = 500; + +namespace api { + +using namespace models; + +bool Parameters::parseParameterscombinedresourceIdPostParams(const httplib::Request& req, Parameters::ParameterscombinedresourceIdPostRequest& params, std::vector& paramErrors) +{ + std::vector errors; + if (!req.body.empty()) + { + try + { + nlohmann::json json = nlohmann::json::parse(req.body); + SimpleObject temp; + from_json(json, temp); + params.m_request = temp; + } + catch (const std::exception& e) + { + errors.push_back("Invalid request body: " + std::string(e.what())); + } + } + + // Query Parameters - filter + if (req.has_param("filter")) + { + params.m_filter = req.get_param_value("filter"); + } + // Query Parameters - limit + if (req.has_param("limit")) + { + try + { + params.m_limit = std::stoi(req.get_param_value("limit")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter 'limit': " + std::string(e.what())); + } + } + else + { + // Use default value for optional parameter + params.m_limit = 10; + } + + // Header Parameters - X-Correlation-Id + if (!req.get_header_value("X-Correlation-Id").empty()) + { + params.m_xCorrelationId = req.get_header_value("X-Correlation-Id"); + } + // Header Parameters - X-Client-Version + if (!req.get_header_value("X-Client-Version").empty()) + { + params.m_xClientVersion = req.get_header_value("X-Client-Version"); + } + else + { + // Use default value for optional parameter + params.m_xClientVersion = ""; + } + + // Path Parameters - resourceId (index: 1) + if (req.matches.size() < 1 + 1) + { + errors.push_back("Missing path parameter 'resourceId'"); + } + else + { + try + { + params.m_resourceId = std::stoi(req.matches[1]); + } + catch (const std::exception& e) + { + errors.push_back("Invalid path parameter 'resourceId': " + std::string(e.what())); + } + } + + // Cookie Parameters - authToken + try + { + auto cookieHeader = req.get_header_value("Cookie"); + if (!cookieHeader.empty()) + { + std::string cookieValue; + std::string key = "authToken="; + size_t start = cookieHeader.find(key); + if (start != std::string::npos) + { + start += key.length(); + size_t end = cookieHeader.find(";", start); + if (end == std::string::npos) end = cookieHeader.length(); + cookieValue = cookieHeader.substr(start, end - start); + params.m_authToken = cookieValue; + } + } + } + catch (const std::exception& e) + { + errors.push_back("Invalid cookie parameter 'authToken': " + std::string(e.what())); + } + // Cookie Parameters - userPrefs + try + { + auto cookieHeader = req.get_header_value("Cookie"); + if (!cookieHeader.empty()) + { + std::string cookieValue; + std::string key = "userPrefs="; + size_t start = cookieHeader.find(key); + if (start != std::string::npos) + { + start += key.length(); + size_t end = cookieHeader.find(";", start); + if (end == std::string::npos) end = cookieHeader.length(); + cookieValue = cookieHeader.substr(start, end - start); + params.m_userPrefs = cookieValue; + } + else + { + // Use default value for optional parameter + params.m_userPrefs = ""; + } + } + else + { + // Use default value for optional parameter + params.m_userPrefs = ""; + } + } + catch (const std::exception& e) + { + errors.push_back("Invalid cookie parameter 'userPrefs': " + std::string(e.what())); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Parameters::handleParameterscombinedresourceIdPostResponse(const ParameterscombinedresourceIdPostResponse& result, httplib::Response& res) +{ + std::visit([&](const auto& value) + { + using T = std::decay_t; + + // Success types + if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_TEST_ALL_PARAMETER_TYPES200_RESPONSE; + nlohmann::json responseJson; + to_json(responseJson, value); + res.set_content(responseJson.dump(), "application/json"); + } + // Error types + else if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + nlohmann::json errorJson = value; + res.set_content(errorJson.dump(), "application/json"); + } + }, result); +} +bool Parameters::parseParameterscookiesGetParams(const httplib::Request& req, Parameters::ParameterscookiesGetRequest& params, std::vector& paramErrors) +{ + std::vector errors; + + // Cookie Parameters - sessionId + try + { + auto cookieHeader = req.get_header_value("Cookie"); + if (!cookieHeader.empty()) + { + std::string cookieValue; + std::string key = "sessionId="; + size_t start = cookieHeader.find(key); + if (start != std::string::npos) + { + start += key.length(); + size_t end = cookieHeader.find(";", start); + if (end == std::string::npos) end = cookieHeader.length(); + cookieValue = cookieHeader.substr(start, end - start); + params.m_sessionId = cookieValue; + } + } + } + catch (const std::exception& e) + { + errors.push_back("Invalid cookie parameter 'sessionId': " + std::string(e.what())); + } + // Cookie Parameters - userId + try + { + auto cookieHeader = req.get_header_value("Cookie"); + if (!cookieHeader.empty()) + { + std::string cookieValue; + std::string key = "userId="; + size_t start = cookieHeader.find(key); + if (start != std::string::npos) + { + start += key.length(); + size_t end = cookieHeader.find(";", start); + if (end == std::string::npos) end = cookieHeader.length(); + cookieValue = cookieHeader.substr(start, end - start); + params.m_userId = std::stoi(cookieValue); + } + else + { + // Use default value for optional parameter + params.m_userId = 0; + } + } + else + { + // Use default value for optional parameter + params.m_userId = 0; + } + } + catch (const std::exception& e) + { + errors.push_back("Invalid cookie parameter 'userId': " + std::string(e.what())); + } + // Cookie Parameters - preferences + try + { + auto cookieHeader = req.get_header_value("Cookie"); + if (!cookieHeader.empty()) + { + std::string cookieValue; + std::string key = "preferences="; + size_t start = cookieHeader.find(key); + if (start != std::string::npos) + { + start += key.length(); + size_t end = cookieHeader.find(";", start); + if (end == std::string::npos) end = cookieHeader.length(); + cookieValue = cookieHeader.substr(start, end - start); + params.m_preferences = cookieValue; + } + else + { + // Use default value for optional parameter + params.m_preferences = ""; + } + } + else + { + // Use default value for optional parameter + params.m_preferences = ""; + } + } + catch (const std::exception& e) + { + errors.push_back("Invalid cookie parameter 'preferences': " + std::string(e.what())); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Parameters::handleParameterscookiesGetResponse(const ParameterscookiesGetResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_TEST_COOKIE_PARAMETERS200_RESPONSE; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} +bool Parameters::parseParametersheadersGetParams(const httplib::Request& req, Parameters::ParametersheadersGetRequest& params, std::vector& paramErrors) +{ + std::vector errors; + + // Header Parameters - X-Api-Version + if (!req.get_header_value("X-Api-Version").empty()) + { + params.m_xApiVersion = req.get_header_value("X-Api-Version"); + } + // Header Parameters - X-Request-Id + if (!req.get_header_value("X-Request-Id").empty()) + { + params.m_xRequestId = req.get_header_value("X-Request-Id"); + } + else + { + // Use default value for optional parameter + params.m_xRequestId = ""; + } + // Header Parameters - X-Rate-Limit + if (!req.get_header_value("X-Rate-Limit").empty()) + { + try + { + params.m_xRateLimit = std::stoi(req.get_header_value("X-Rate-Limit")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid header parameter 'X-Rate-Limit': " + std::string(e.what())); + } + } + else + { + // Use default value for optional parameter + params.m_xRateLimit = 0; + } + // Header Parameters - X-Tags + if (!req.get_header_value("X-Tags").empty()) + { + try + { + // Header arrays may be comma-separated + auto val = req.get_header_value("X-Tags"); + std::stringstream ss(val); + std::string item; + if (!params.m_xTags.has_value()) + { + params.m_xTags = std::vector{}; + } + while (std::getline(ss, item, ',')) + { + if (!item.empty()) + { + params.m_xTags->emplace_back(item); + } + } + } + catch (const std::exception& e) + { + errors.push_back("Invalid header parameter 'X-Tags': " + std::string(e.what())); + } + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Parameters::handleParametersheadersGetResponse(const ParametersheadersGetResponse& result, httplib::Response& res) +{ + std::visit([&](const auto& value) + { + using T = std::decay_t; + + // Success types + if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_TEST_HEADER_PARAMETERS200_RESPONSE; + nlohmann::json responseJson; + to_json(responseJson, value); + res.set_content(responseJson.dump(), "application/json"); + } + // Error types + else if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_TEST_HEADER_PARAMETERS401_RESPONSE; + nlohmann::json errorJson = value; + res.set_content(errorJson.dump(), "application/json"); + } + }, result); +} +bool Parameters::parseParametersquerypathIdGetParams(const httplib::Request& req, Parameters::ParametersquerypathIdGetRequest& params, std::vector& paramErrors) +{ + std::vector errors; + + // Query Parameters - stringParam + if (req.has_param("stringParam")) + { + params.m_stringParam = req.get_param_value("stringParam"); + } + // Query Parameters - intParam + if (req.has_param("intParam")) + { + try + { + params.m_intParam = std::stoi(req.get_param_value("intParam")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter 'intParam': " + std::string(e.what())); + } + } + else + { + // Use default value for optional parameter + params.m_intParam = 42; + } + // Query Parameters - boolParam + if (req.has_param("boolParam")) + { + try + { + params.m_boolParam = (req.get_param_value("boolParam") == "true"); + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter 'boolParam': " + std::string(e.what())); + } + } + else + { + // Use default value for optional parameter + params.m_boolParam = false; + } + // Query Parameters - arrayParam + if (req.has_param("arrayParam")) + { + try + { + // form/simple: multi-param or comma-separated + size_t count = req.get_param_value_count("arrayParam"); + if (!params.m_arrayParam.has_value()) + { + params.m_arrayParam = std::vector{}; + } + if (count > 1) + { + for (size_t i = 0; i < count; ++i) + { + auto val = req.get_param_value("arrayParam", i); + + params.m_arrayParam->emplace_back(val); + + } + } + else if (count == 1) + { + auto val = req.get_param_value("arrayParam", 0); + std::stringstream ss(val); + std::string item; + while (std::getline(ss, item, ',')) + { + if (!item.empty()) + { + + params.m_arrayParam->emplace_back(item); + + } + } + } + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter 'arrayParam': " + std::string(e.what())); + } + } + // Query Parameters - spaceDelimited + if (req.has_param("spaceDelimited")) + { + try + { + // form/simple: multi-param or comma-separated + size_t count = req.get_param_value_count("spaceDelimited"); + if (!params.m_spaceDelimited.has_value()) + { + params.m_spaceDelimited = std::vector{}; + } + if (count > 1) + { + for (size_t i = 0; i < count; ++i) + { + auto val = req.get_param_value("spaceDelimited", i); + + params.m_spaceDelimited->emplace_back(val); + + } + } + else if (count == 1) + { + auto val = req.get_param_value("spaceDelimited", 0); + std::stringstream ss(val); + std::string item; + while (std::getline(ss, item, ',')) + { + if (!item.empty()) + { + + params.m_spaceDelimited->emplace_back(item); + + } + } + } + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter 'spaceDelimited': " + std::string(e.what())); + } + } + // Query Parameters - pipeDelimited + if (req.has_param("pipeDelimited")) + { + try + { + // form/simple: multi-param or comma-separated + size_t count = req.get_param_value_count("pipeDelimited"); + if (!params.m_pipeDelimited.has_value()) + { + params.m_pipeDelimited = std::vector{}; + } + if (count > 1) + { + for (size_t i = 0; i < count; ++i) + { + auto val = req.get_param_value("pipeDelimited", i); + params.m_pipeDelimited->emplace_back(std::stoi(val)); + + } + } + else if (count == 1) + { + auto val = req.get_param_value("pipeDelimited", 0); + std::stringstream ss(val); + std::string item; + while (std::getline(ss, item, ',')) + { + if (!item.empty()) + { + params.m_pipeDelimited->emplace_back(std::stoi(item)); + + } + } + } + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter 'pipeDelimited': " + std::string(e.what())); + } + } + // Query Parameters - deepObject + if (req.has_param("deepObject")) + { + try + { + // Parse JSON object from query + auto val = req.get_param_value("deepObject", 0); + params.m_deepObject = nlohmann::json::parse(val).get(); + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter 'deepObject': " + std::string(e.what())); + } + } + + // Path Parameters - pathId (index: 1) + if (req.matches.size() < 1 + 1) + { + errors.push_back("Missing path parameter 'pathId'"); + } + else + { + try + { + params.m_pathId = std::stoi(req.matches[1]); + } + catch (const std::exception& e) + { + errors.push_back("Invalid path parameter 'pathId': " + std::string(e.what())); + } + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Parameters::handleParametersquerypathIdGetResponse(const ParametersquerypathIdGetResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_TEST_QUERY_PARAMETERS200_RESPONSE; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} + + +void Parameters::handleParameterscombinedresourceIdPostRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + ParameterscombinedresourceIdPostRequest params; + std::vector paramErrors; + if (!parseParameterscombinedresourceIdPostParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handlePostForParameterscombinedresourceId(params); + handleParameterscombinedresourceIdPostResponse(result, res); + + } + catch (const nlohmann::json::parse_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::invalid_iterator& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::type_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::other_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Parameters::handleParameterscookiesGetRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + ParameterscookiesGetRequest params; + std::vector paramErrors; + if (!parseParameterscookiesGetParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handleGetForParameterscookies(params); + handleParameterscookiesGetResponse(result, res); + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Parameters::handleParametersheadersGetRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + ParametersheadersGetRequest params; + std::vector paramErrors; + if (!parseParametersheadersGetParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handleGetForParametersheaders(params); + handleParametersheadersGetResponse(result, res); + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Parameters::handleParametersquerypathIdGetRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + ParametersquerypathIdGetRequest params; + std::vector paramErrors; + if (!parseParametersquerypathIdGetParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handleGetForParametersquerypathId(params); + handleParametersquerypathIdGetResponse(result, res); + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + + +void Parameters::registerRoutes(httplib::Server& svr) +{ + svr.Post("/parameters/combined/{resourceId}", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleParameterscombinedresourceIdPostRequest(req, res); + }); + svr.Get("/parameters/cookies", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleParameterscookiesGetRequest(req, res); + }); + svr.Get("/parameters/headers", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleParametersheadersGetRequest(req, res); + }); + svr.Get("/parameters/query/{pathId}", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleParametersquerypathIdGetRequest(req, res); + }); +} + +} // namespace api \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/api/ParametersApi.h b/samples/server/petstore/cpp-httplib-server/feature-test/api/ParametersApi.h new file mode 100644 index 000000000000..a5be965b8b45 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/api/ParametersApi.h @@ -0,0 +1,166 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once + +// System headers +#include +#include +#include +#include + +// Project headers +#include "models/ErrorResponse.h" +#include "models/SimpleObject.h" +#include "models/TestAllParameterTypes200Response.h" +#include "models/TestCookieParameters200Response.h" +#include "models/TestHeaderParameters200Response.h" +#include "models/TestHeaderParameters401Response.h" +#include "models/TestQueryParameters200Response.h" +#include "models/TestQueryParametersDeepObjectParameter.h" + +namespace api { + class AuthenticationManager; +class Parameters { +public: + Parameters() = default; + virtual ~Parameters() = default; + /** + * @brief Register all routes for this API + * @param svr The httplib::Server instance to register routes on + */ + void registerRoutes(httplib::Server& svr); + // ========================= + // ===== Request types ===== + // ========================= + + /** + * @brief Request type for handlePostForParameterscombinedresourceId. + */ + struct ParameterscombinedresourceIdPostRequest + { + std::optional m_request; //Request Body (optional) + std::string m_filter; //Query Params (required) + std::optional m_limit; //Query Params (optional) + std::string m_xCorrelationId; //HeaderParams (required) + std::optional m_xClientVersion; //HeaderParams (optional) + int m_resourceId; //PathParams (always required) + std::string m_authToken; //Cookies (required) + std::optional m_userPrefs; //Cookies (optional) + }; + + /** + * @brief Request type for handleGetForParameterscookies. + */ + struct ParameterscookiesGetRequest + { + + std::string m_sessionId; //Cookies (required) + std::optional m_userId; //Cookies (optional) + std::optional m_preferences; //Cookies (optional) + }; + + /** + * @brief Request type for handleGetForParametersheaders. + */ + struct ParametersheadersGetRequest + { + + std::string m_xApiVersion; //HeaderParams (required) + std::optional m_xRequestId; //HeaderParams (optional) + std::optional m_xRateLimit; //HeaderParams (optional) + std::optional> m_xTags; //HeaderParams (optional) + }; + + /** + * @brief Request type for handleGetForParametersquerypathId. + */ + struct ParametersquerypathIdGetRequest + { + + std::string m_stringParam; //Query Params (required) + std::optional m_intParam; //Query Params (optional) + std::optional m_boolParam; //Query Params (optional) + std::optional> m_arrayParam; //Query Params (optional) + std::optional> m_spaceDelimited; //Query Params (optional) + std::optional> m_pipeDelimited; //Query Params (optional) + std::optional m_deepObject; //Query Params (optional) + int m_pathId; //PathParams (always required) + }; + + // ========================== + // ===== Response types ===== + // ========================== + + /** + * @brief Response type for handlePostForParameterscombinedresourceId. + */ + using ParameterscombinedresourceIdPostResponse = std::variant< + models::TestAllParameterTypes200Response , + models::ErrorResponse >; + + /** + * @brief Response type for handleGetForParameterscookies. + */ + using ParameterscookiesGetResponse = models::TestCookieParameters200Response; + + /** + * @brief Response type for handleGetForParametersheaders. + */ + using ParametersheadersGetResponse = std::variant< + models::TestHeaderParameters200Response , + models::TestHeaderParameters401Response >; + + /** + * @brief Response type for handleGetForParametersquerypathId. + */ + using ParametersquerypathIdGetResponse = models::TestQueryParameters200Response; + // ============================================================ + // ===== Pure virtual functions to be handled by the user ===== + // ============================================================ + /** + * ParameterscombinedresourceIdPostRequest - struct containing all the query parameters and headers and schemas as available. + * @return ParameterscombinedresourceIdPostResponse The response type returned by the handler. + */ + virtual ParameterscombinedresourceIdPostResponse handlePostForParameterscombinedresourceId(const ParameterscombinedresourceIdPostRequest& params)=0; + + /** + * ParameterscookiesGetRequest - struct containing all the query parameters and headers and schemas as available. + * @return ParameterscookiesGetResponse The response type returned by the handler. + */ + virtual ParameterscookiesGetResponse handleGetForParameterscookies(const ParameterscookiesGetRequest& params)=0; + + /** + * ParametersheadersGetRequest - struct containing all the query parameters and headers and schemas as available. + * @return ParametersheadersGetResponse The response type returned by the handler. + */ + virtual ParametersheadersGetResponse handleGetForParametersheaders(const ParametersheadersGetRequest& params)=0; + + /** + * ParametersquerypathIdGetRequest - struct containing all the query parameters and headers and schemas as available. + * @return ParametersquerypathIdGetResponse The response type returned by the handler. + */ + virtual ParametersquerypathIdGetResponse handleGetForParametersquerypathId(const ParametersquerypathIdGetRequest& params)=0; + +private: + // ======================================== + // ===== Helper function declarations ===== + // ======================================== + static bool parseParameterscombinedresourceIdPostParams(const httplib::Request& req, ParameterscombinedresourceIdPostRequest& params, std::vector& paramErrors); + void handleParameterscombinedresourceIdPostRequest(const httplib::Request& req, httplib::Response& res); + static void handleParameterscombinedresourceIdPostResponse(const ParameterscombinedresourceIdPostResponse& result, httplib::Response& res); + static bool parseParameterscookiesGetParams(const httplib::Request& req, ParameterscookiesGetRequest& params, std::vector& paramErrors); + void handleParameterscookiesGetRequest(const httplib::Request& req, httplib::Response& res); + static void handleParameterscookiesGetResponse(const ParameterscookiesGetResponse& result, httplib::Response& res); + static bool parseParametersheadersGetParams(const httplib::Request& req, ParametersheadersGetRequest& params, std::vector& paramErrors); + void handleParametersheadersGetRequest(const httplib::Request& req, httplib::Response& res); + static void handleParametersheadersGetResponse(const ParametersheadersGetResponse& result, httplib::Response& res); + static bool parseParametersquerypathIdGetParams(const httplib::Request& req, ParametersquerypathIdGetRequest& params, std::vector& paramErrors); + void handleParametersquerypathIdGetRequest(const httplib::Request& req, httplib::Response& res); + static void handleParametersquerypathIdGetResponse(const ParametersquerypathIdGetResponse& result, httplib::Response& res); +}; + +} // namespace api \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/api/SecurityApi.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/api/SecurityApi.cpp new file mode 100644 index 000000000000..fbfdff17aee6 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/api/SecurityApi.cpp @@ -0,0 +1,298 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +// System headers +#include +#include +#include + +// Project headers +#include "SecurityApi.h" +#include "AuthenticationManager.h" + +constexpr int HTTP_RESPONSE_CODE_TEST_API_KEY_SECURITY200_RESPONSE = 200; +constexpr int HTTP_RESPONSE_CODE_ERROR_RESPONSE = 401; +constexpr int HTTP_RESPONSE_CODE_TEST_BASIC_SECURITY200_RESPONSE = 200; +constexpr int HTTP_RESPONSE_CODE_TEST_BEARER_SECURITY200_RESPONSE = 200; +constexpr int HTTP_RESPONSE_CODE_TEST_O_AUTH2_SECURITY200_RESPONSE = 200; +constexpr int HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR = 500; + +namespace api { + +using namespace models; + +void Security::handleSecurityapikeyGetResponse(const SecurityapikeyGetResponse& result, httplib::Response& res) +{ + std::visit([&](const auto& value) + { + using T = std::decay_t; + + // Success types + if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_TEST_API_KEY_SECURITY200_RESPONSE; + nlohmann::json responseJson; + to_json(responseJson, value); + res.set_content(responseJson.dump(), "application/json"); + } + // Error types + else if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + nlohmann::json errorJson = value; + res.set_content(errorJson.dump(), "application/json"); + } + }, result); +} +void Security::handleSecuritybasicGetResponse(const SecuritybasicGetResponse& result, httplib::Response& res) +{ + std::visit([&](const auto& value) + { + using T = std::decay_t; + + // Success types + if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_TEST_BASIC_SECURITY200_RESPONSE; + nlohmann::json responseJson; + to_json(responseJson, value); + res.set_content(responseJson.dump(), "application/json"); + } + // Error types + else if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + nlohmann::json errorJson = value; + res.set_content(errorJson.dump(), "application/json"); + } + }, result); +} +void Security::handleSecuritybearerGetResponse(const SecuritybearerGetResponse& result, httplib::Response& res) +{ + std::visit([&](const auto& value) + { + using T = std::decay_t; + + // Success types + if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_TEST_BEARER_SECURITY200_RESPONSE; + nlohmann::json responseJson; + to_json(responseJson, value); + res.set_content(responseJson.dump(), "application/json"); + } + // Error types + else if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + nlohmann::json errorJson = value; + res.set_content(errorJson.dump(), "application/json"); + } + }, result); +} +void Security::handleSecurityoauth2getResponse(const Securityoauth2getResponse& result, httplib::Response& res) +{ + std::visit([&](const auto& value) + { + using T = std::decay_t; + + // Success types + if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_TEST_O_AUTH2_SECURITY200_RESPONSE; + nlohmann::json responseJson; + to_json(responseJson, value); + res.set_content(responseJson.dump(), "application/json"); + } + // Error types + else if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + nlohmann::json errorJson = value; + res.set_content(errorJson.dump(), "application/json"); + } + }, result); +} + +bool Security::performAuthentication( + const httplib::Request& req, + std::shared_ptr auth, + httplib::Response& res) +{ + if (!auth) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "AuthenticationManager not configured"; + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + return false; + } + + if (req.has_header("X-API-Key")) + { + if (auth->validateApiKey(req.get_header_value("X-API-Key"))) return true; + } + + if (req.has_header("Authorization")) + { + auto authHeader = req.get_header_value("Authorization"); + if (authHeader.find("Basic ") == 0) + { + std::string credentials = authHeader.substr(6); + if (auth->validateBasicAuth(credentials, "")) return true; + } + } + + if (req.has_header("Authorization")) + { + auto authHeader = req.get_header_value("Authorization"); + if (authHeader.find("Bearer ") == 0) + { + std::string token = authHeader.substr(7); + if (auth->validateBearerToken(token)) return true; + } + } + + if (req.has_header("Authorization")) + { + auto authHeader = req.get_header_value("Authorization"); + if (authHeader.find("Bearer ") == 0) + { + std::string token = authHeader.substr(7); + std::vector requiredScopes = { "read:users", "write:users" }; + if (auth->validateOAuth2(token, requiredScopes)) return true; + } + } + + return false; +} + +void Security::handleSecurityapikeyGetRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res, std::shared_ptr auth) +{ + try + { + if (!performAuthentication(req, auth, res)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Authentication required"; + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + return; + } + + auto result = handleGetForSecurityapikey(); + handleSecurityapikeyGetResponse(result, res); + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Security::handleSecuritybasicGetRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res, std::shared_ptr auth) +{ + try + { + if (!performAuthentication(req, auth, res)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Authentication required"; + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + return; + } + + auto result = handleGetForSecuritybasic(); + handleSecuritybasicGetResponse(result, res); + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Security::handleSecuritybearerGetRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res, std::shared_ptr auth) +{ + try + { + if (!performAuthentication(req, auth, res)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Authentication required"; + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + return; + } + + auto result = handleGetForSecuritybearer(); + handleSecuritybearerGetResponse(result, res); + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Security::handleSecurityoauth2GetRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res, std::shared_ptr auth) +{ + try + { + if (!performAuthentication(req, auth, res)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Authentication required"; + res.status = HTTP_RESPONSE_CODE_ERROR_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + return; + } + + auto result = handleGetForSecurityoauth2(); + handleSecurityoauth2getResponse(result, res); + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + + +void Security::registerRoutes(httplib::Server& svr, std::shared_ptr auth) +{ + svr.Get("/security/apikey", [this, auth]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleSecurityapikeyGetRequest(req, res, auth); + }); + svr.Get("/security/basic", [this, auth]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleSecuritybasicGetRequest(req, res, auth); + }); + svr.Get("/security/bearer", [this, auth]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleSecuritybearerGetRequest(req, res, auth); + }); + svr.Get("/security/oauth2", [this, auth]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleSecurityoauth2GetRequest(req, res, auth); + }); +} + +} // namespace api \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/api/SecurityApi.h b/samples/server/petstore/cpp-httplib-server/feature-test/api/SecurityApi.h new file mode 100644 index 000000000000..91af727a5c27 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/api/SecurityApi.h @@ -0,0 +1,106 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once + +// System headers +#include +#include +#include + +// Project headers +#include "models/ErrorResponse.h" +#include "models/TestApiKeySecurity200Response.h" +#include "models/TestBasicSecurity200Response.h" +#include "models/TestBearerSecurity200Response.h" +#include "models/TestOAuth2Security200Response.h" + +namespace api { + class AuthenticationManager; +class Security { +public: + Security() = default; + virtual ~Security() = default; + /** + * @brief Register all routes for this API + * @param svr The httplib::Server instance to register routes on + * @param auth The AuthenticationManager for authentication (optional, defaults to nullptr) + */ + void registerRoutes(httplib::Server& svr, std::shared_ptr auth = nullptr); + + // ========================== + // ===== Response types ===== + // ========================== + + /** + * @brief Response type for handleGetForSecurityapikey. + */ + using SecurityapikeyGetResponse = std::variant< + models::TestApiKeySecurity200Response , + models::ErrorResponse >; + + /** + * @brief Response type for handleGetForSecuritybasic. + */ + using SecuritybasicGetResponse = std::variant< + models::TestBasicSecurity200Response , + models::ErrorResponse >; + + /** + * @brief Response type for handleGetForSecuritybearer. + */ + using SecuritybearerGetResponse = std::variant< + models::TestBearerSecurity200Response , + models::ErrorResponse >; + + /** + * @brief Response type for handleGetForSecurityoauth2. + */ + using Securityoauth2getResponse = std::variant< + models::TestOAuth2Security200Response , + models::ErrorResponse >; + // ============================================================ + // ===== Pure virtual functions to be handled by the user ===== + // ============================================================ + /** + * @return SecurityapikeyGetResponse The response type returned by the handler. + */ + virtual SecurityapikeyGetResponse handleGetForSecurityapikey()=0; + + /** + * @return SecuritybasicGetResponse The response type returned by the handler. + */ + virtual SecuritybasicGetResponse handleGetForSecuritybasic()=0; + + /** + * @return SecuritybearerGetResponse The response type returned by the handler. + */ + virtual SecuritybearerGetResponse handleGetForSecuritybearer()=0; + + /** + * @return Securityoauth2getResponse The response type returned by the handler. + */ + virtual Securityoauth2getResponse handleGetForSecurityoauth2()=0; + +private: + // ======================================== + // ===== Helper function declarations ===== + // ======================================== + void handleSecurityapikeyGetRequest(const httplib::Request& req, httplib::Response& res, std::shared_ptr auth); + static void handleSecurityapikeyGetResponse(const SecurityapikeyGetResponse& result, httplib::Response& res); + void handleSecuritybasicGetRequest(const httplib::Request& req, httplib::Response& res, std::shared_ptr auth); + static void handleSecuritybasicGetResponse(const SecuritybasicGetResponse& result, httplib::Response& res); + void handleSecuritybearerGetRequest(const httplib::Request& req, httplib::Response& res, std::shared_ptr auth); + static void handleSecuritybearerGetResponse(const SecuritybearerGetResponse& result, httplib::Response& res); + void handleSecurityoauth2GetRequest(const httplib::Request& req, httplib::Response& res, std::shared_ptr auth); + static void handleSecurityoauth2getResponse(const Securityoauth2getResponse& result, httplib::Response& res); + static bool performAuthentication( + const httplib::Request& req, + std::shared_ptr auth, + httplib::Response& res); +}; + +} // namespace api \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/Address.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/Address.cpp new file mode 100644 index 000000000000..6658fa89285f --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/Address.cpp @@ -0,0 +1,67 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "Address.h" + +namespace models { + +Address::Address() +: street("") +, city("") +, zipCode("") +, country("USA") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string Address::getStreet() const +{ + return street; +} +std::string Address::getCity() const +{ + return city; +} +std::string Address::getZipCode() const +{ + return zipCode; +} +std::string Address::getCountry() const +{ + return country; +} + +// =================== +// ===== Setters ===== +// =================== +void Address::setStreet(const std::string& streetObj) +{ + street = streetObj; +} +void Address::setCity(const std::string& cityObj) +{ + city = cityObj; +} +void Address::setZipCode(const std::string& zipCodeObj) +{ + zipCode = zipCodeObj; +} +void Address::setCountry(const std::string& countryObj) +{ + country = countryObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/Address.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/Address.h new file mode 100644 index 000000000000..eaf778a713e4 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/Address.h @@ -0,0 +1,48 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class Address +{ +public: + + Address(); + virtual ~Address() = default; + + // Getters and setters + [[nodiscard]] std::string getStreet() const; + void setStreet(const std::string& street); + [[nodiscard]] std::string getCity() const; + void setCity(const std::string& city); + [[nodiscard]] std::string getZipCode() const; + void setZipCode(const std::string& zipCode); + [[nodiscard]] std::string getCountry() const; + void setCountry(const std::string& country); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(Address, + street, city, zipCode, country) + +private: + std::string street; + std::string city; + std::string zipCode; + std::string country; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/Animal.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/Animal.cpp new file mode 100644 index 000000000000..243a7ec6decc --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/Animal.cpp @@ -0,0 +1,49 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "Animal.h" + +namespace models { + +Animal::Animal() +: name("") +, type("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string Animal::getName() const +{ + return name; +} +std::string Animal::getType() const +{ + return type; +} + +// =================== +// ===== Setters ===== +// =================== +void Animal::setName(const std::string& nameObj) +{ + name = nameObj; +} +void Animal::setType(const std::string& typeObj) +{ + type = typeObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/Animal.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/Animal.h new file mode 100644 index 000000000000..e3f179bc7196 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/Animal.h @@ -0,0 +1,42 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class Animal +{ +public: + + Animal(); + virtual ~Animal() = default; + + // Getters and setters + [[nodiscard]] std::string getName() const; + void setName(const std::string& name); + [[nodiscard]] std::string getType() const; + void setType(const std::string& type); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(Animal, + name, type) + +private: + std::string name; + std::string type; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/ArrayTypes.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/ArrayTypes.cpp new file mode 100644 index 000000000000..196122ee2e6e --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/ArrayTypes.cpp @@ -0,0 +1,76 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "ArrayTypes.h" + +namespace models { + +ArrayTypes::ArrayTypes() +: stringArray(std::vector()) +, intArray(std::vector()) +, objectArray(std::vector()) +, enumArray(std::vector()) +, nestedArray(std::vector>()) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::vector ArrayTypes::getStringArray() const +{ + return stringArray; +} +std::vector ArrayTypes::getIntArray() const +{ + return intArray; +} +std::vector ArrayTypes::getObjectArray() const +{ + return objectArray; +} +std::vector ArrayTypes::getEnumArray() const +{ + return enumArray; +} +std::vector> ArrayTypes::getNestedArray() const +{ + return nestedArray; +} + +// =================== +// ===== Setters ===== +// =================== +void ArrayTypes::setStringArray(const std::vector& stringArrayObj) +{ + stringArray = stringArrayObj; +} +void ArrayTypes::setIntArray(const std::vector& intArrayObj) +{ + intArray = intArrayObj; +} +void ArrayTypes::setObjectArray(const std::vector& objectArrayObj) +{ + objectArray = objectArrayObj; +} +void ArrayTypes::setEnumArray(const std::vector& enumArrayObj) +{ + enumArray = enumArrayObj; +} +void ArrayTypes::setNestedArray(const std::vector>& nestedArrayObj) +{ + nestedArray = nestedArrayObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/ArrayTypes.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/ArrayTypes.h new file mode 100644 index 000000000000..ce247d827611 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/ArrayTypes.h @@ -0,0 +1,64 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include +#include +#include "SimpleObject.h" + + + +namespace models { + + +class ArrayTypes +{ +public: + enum class EnumArrayEnum { + RED, + GREEN, + BLUE + }; + + // Enum conversion functions (definitions in .cpp) + static std::string EnumArrayEnumToString(EnumArrayEnum value); + static EnumArrayEnum EnumArrayEnumFromString(const std::string& str); + + + ArrayTypes(); + virtual ~ArrayTypes() = default; + + // Getters and setters + [[nodiscard]] std::vector getStringArray() const; + void setStringArray(const std::vector& stringArray); + [[nodiscard]] std::vector getIntArray() const; + void setIntArray(const std::vector& intArray); + [[nodiscard]] std::vector getObjectArray() const; + void setObjectArray(const std::vector& objectArray); + [[nodiscard]] std::vector getEnumArray() const; + void setEnumArray(const std::vector& enumArray); + [[nodiscard]] std::vector> getNestedArray() const; + void setNestedArray(const std::vector>& nestedArray); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(ArrayTypes, + stringArray, intArray, objectArray, enumArray, nestedArray) + +private: + std::vector stringArray; + std::vector intArray; + std::vector objectArray; + std::vector enumArray; + std::vector> nestedArray; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/BankAccount.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/BankAccount.cpp new file mode 100644 index 000000000000..7f1ceaf01c0d --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/BankAccount.cpp @@ -0,0 +1,58 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "BankAccount.h" + +namespace models { + +BankAccount::BankAccount() +: paymentType("") +, accountNumber("") +, bankName("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string BankAccount::getPaymentType() const +{ + return paymentType; +} +std::string BankAccount::getAccountNumber() const +{ + return accountNumber; +} +std::string BankAccount::getBankName() const +{ + return bankName; +} + +// =================== +// ===== Setters ===== +// =================== +void BankAccount::setPaymentType(const std::string& paymentTypeObj) +{ + paymentType = paymentTypeObj; +} +void BankAccount::setAccountNumber(const std::string& accountNumberObj) +{ + accountNumber = accountNumberObj; +} +void BankAccount::setBankName(const std::string& bankNameObj) +{ + bankName = bankNameObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/BankAccount.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/BankAccount.h new file mode 100644 index 000000000000..e5d88115e447 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/BankAccount.h @@ -0,0 +1,45 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class BankAccount +{ +public: + + BankAccount(); + virtual ~BankAccount() = default; + + // Getters and setters + [[nodiscard]] std::string getPaymentType() const; + void setPaymentType(const std::string& paymentType); + [[nodiscard]] std::string getAccountNumber() const; + void setAccountNumber(const std::string& accountNumber); + [[nodiscard]] std::string getBankName() const; + void setBankName(const std::string& bankName); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(BankAccount, + paymentType, accountNumber, bankName) + +private: + std::string paymentType; + std::string accountNumber; + std::string bankName; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/Company.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/Company.cpp new file mode 100644 index 000000000000..39e55c02da29 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/Company.cpp @@ -0,0 +1,67 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "Company.h" + +namespace models { + +Company::Company() +: name("") +, headquarters(Address()) +, departments(std::vector()) +, metadata(std::map()) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string Company::getName() const +{ + return name; +} +Address Company::getHeadquarters() const +{ + return headquarters; +} +std::vector Company::getDepartments() const +{ + return departments; +} +std::map Company::getMetadata() const +{ + return metadata; +} + +// =================== +// ===== Setters ===== +// =================== +void Company::setName(const std::string& nameObj) +{ + name = nameObj; +} +void Company::setHeadquarters(const Address& headquartersObj) +{ + headquarters = headquartersObj; +} +void Company::setDepartments(const std::vector& departmentsObj) +{ + departments = departmentsObj; +} +void Company::setMetadata(const std::map& metadataObj) +{ + metadata = metadataObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/Company.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/Company.h new file mode 100644 index 000000000000..acb61e0db444 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/Company.h @@ -0,0 +1,51 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include +#include "Address.h" +#include "Department.h" + + + +namespace models { + + +class Company +{ +public: + + Company(); + virtual ~Company() = default; + + // Getters and setters + [[nodiscard]] std::string getName() const; + void setName(const std::string& name); + [[nodiscard]] Address getHeadquarters() const; + void setHeadquarters(const Address& headquarters); + [[nodiscard]] std::vector getDepartments() const; + void setDepartments(const std::vector& departments); + [[nodiscard]] std::map getMetadata() const; + void setMetadata(const std::map& metadata); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(Company, + name, headquarters, departments, metadata) + +private: + std::string name; + Address headquarters; + std::vector departments; + std::map metadata; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/CreatedResponse.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/CreatedResponse.cpp new file mode 100644 index 000000000000..09d81a7a3608 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/CreatedResponse.cpp @@ -0,0 +1,58 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "CreatedResponse.h" + +namespace models { + +CreatedResponse::CreatedResponse() +: status("") +, id(0) +, location("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string CreatedResponse::getStatus() const +{ + return status; +} +int CreatedResponse::getId() const +{ + return id; +} +std::string CreatedResponse::getLocation() const +{ + return location; +} + +// =================== +// ===== Setters ===== +// =================== +void CreatedResponse::setStatus(const std::string& statusObj) +{ + status = statusObj; +} +void CreatedResponse::setId(const int& idObj) +{ + id = idObj; +} +void CreatedResponse::setLocation(const std::string& locationObj) +{ + location = locationObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/CreatedResponse.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/CreatedResponse.h new file mode 100644 index 000000000000..b3f94e4cec83 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/CreatedResponse.h @@ -0,0 +1,46 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include + + + +namespace models { + + +class CreatedResponse +{ +public: + + CreatedResponse(); + virtual ~CreatedResponse() = default; + + // Getters and setters + [[nodiscard]] std::string getStatus() const; + void setStatus(const std::string& status); + [[nodiscard]] int getId() const; + void setId(const int& id); + [[nodiscard]] std::string getLocation() const; + void setLocation(const std::string& location); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(CreatedResponse, + status, id, location) + +private: + std::string status; + int id; + std::string location; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/CreditCard.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/CreditCard.cpp new file mode 100644 index 000000000000..8a9d3cd4f9df --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/CreditCard.cpp @@ -0,0 +1,94 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "CreditCard.h" + +namespace models { + +CreditCard::CreditCard() +: paymentType("") +, cardNumber("") +, cardType(CardTypeEnum::UNSPECIFIED) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string CreditCard::getPaymentType() const +{ + return paymentType; +} +std::string CreditCard::getCardNumber() const +{ + return cardNumber; +} +CreditCard::CardTypeEnum CreditCard::getCardType() const +{ + return cardType; +} + +// =================== +// ===== Setters ===== +// =================== +void CreditCard::setPaymentType(const std::string& paymentTypeObj) +{ + paymentType = paymentTypeObj; +} +void CreditCard::setCardNumber(const std::string& cardNumberObj) +{ + cardNumber = cardNumberObj; +} +void CreditCard::setCardType(const CardTypeEnum& cardTypeObj) +{ + cardType = cardTypeObj; +} + + +// ========================================= +// ===== Enum CardTypeEnum Conversions ===== +// ========================================= +std::string CreditCard::CardTypeEnumToString(CreditCard::CardTypeEnum value) +{ + switch (value) + { + case CardTypeEnum::UNSPECIFIED: return "UNSPECIFIED"; + case CardTypeEnum::VISA: return "VISA"; + case CardTypeEnum::MASTERCARD: return "MASTERCARD"; + case CardTypeEnum::AMEX: return "AMEX"; + default: return {}; + } +} + +CreditCard::CardTypeEnum CreditCard::CardTypeEnumFromString(const std::string& str) +{ + if (str == "UNSPECIFIED") + { + return CardTypeEnum::UNSPECIFIED; + } + if (str == "VISA") + { + return CardTypeEnum::VISA; + } + if (str == "MASTERCARD") + { + return CardTypeEnum::MASTERCARD; + } + if (str == "AMEX") + { + return CardTypeEnum::AMEX; + } + throw std::invalid_argument("Invalid enum value"); +} + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/CreditCard.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/CreditCard.h new file mode 100644 index 000000000000..f53af49ef132 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/CreditCard.h @@ -0,0 +1,68 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class CreditCard +{ +public: + enum class CardTypeEnum { + UNSPECIFIED, + VISA, + MASTERCARD, + AMEX + }; + + // Enum conversion functions (definitions in .cpp) + static std::string CardTypeEnumToString(CardTypeEnum value); + static CardTypeEnum CardTypeEnumFromString(const std::string& str); + + + CreditCard(); + virtual ~CreditCard() = default; + + // Getters and setters + [[nodiscard]] std::string getPaymentType() const; + void setPaymentType(const std::string& paymentType); + [[nodiscard]] std::string getCardNumber() const; + void setCardNumber(const std::string& cardNumber); + [[nodiscard]] CardTypeEnum getCardType() const; + void setCardType(const CardTypeEnum& cardType); + + // Serialization helpers for CardTypeEnum + friend inline void to_json(nlohmann::json& j, const CardTypeEnum& e) + { + j = CardTypeEnumToString(e); + } + + friend inline void from_json(const nlohmann::json& j, CardTypeEnum& e) + { + e = CardTypeEnumFromString(j.get()); + } + + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(CreditCard, + paymentType, cardNumber, cardType) + +private: + std::string paymentType; + std::string cardNumber; + CardTypeEnum cardType; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/Department.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/Department.cpp new file mode 100644 index 000000000000..0d517f180d4c --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/Department.cpp @@ -0,0 +1,58 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "Department.h" + +namespace models { + +Department::Department() +: name("") +, manager(Employee()) +, employees(std::vector()) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string Department::getName() const +{ + return name; +} +Employee Department::getManager() const +{ + return manager; +} +std::vector Department::getEmployees() const +{ + return employees; +} + +// =================== +// ===== Setters ===== +// =================== +void Department::setName(const std::string& nameObj) +{ + name = nameObj; +} +void Department::setManager(const Employee& managerObj) +{ + manager = managerObj; +} +void Department::setEmployees(const std::vector& employeesObj) +{ + employees = employeesObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/Department.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/Department.h new file mode 100644 index 000000000000..fa133c2bed92 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/Department.h @@ -0,0 +1,47 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include +#include "Employee.h" + + + +namespace models { + + +class Department +{ +public: + + Department(); + virtual ~Department() = default; + + // Getters and setters + [[nodiscard]] std::string getName() const; + void setName(const std::string& name); + [[nodiscard]] Employee getManager() const; + void setManager(const Employee& manager); + [[nodiscard]] std::vector getEmployees() const; + void setEmployees(const std::vector& employees); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(Department, + name, manager, employees) + +private: + std::string name; + Employee manager; + std::vector employees; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/Dog.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/Dog.cpp new file mode 100644 index 000000000000..5befffac4337 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/Dog.cpp @@ -0,0 +1,49 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "Dog.h" + +namespace models { + +Dog::Dog() +: breed("") +, barkVolume(0) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string Dog::getBreed() const +{ + return breed; +} +int Dog::getBarkVolume() const +{ + return barkVolume; +} + +// =================== +// ===== Setters ===== +// =================== +void Dog::setBreed(const std::string& breedObj) +{ + breed = breedObj; +} +void Dog::setBarkVolume(const int& barkVolumeObj) +{ + barkVolume = barkVolumeObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/Dog.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/Dog.h new file mode 100644 index 000000000000..fc075c18b8bd --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/Dog.h @@ -0,0 +1,45 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include + + +// Project headers +#include "Animal.h" + +namespace models { + + +class Dog : public Animal +{ +public: + + Dog(); + virtual ~Dog() = default; + + // Getters and setters + [[nodiscard]] std::string getBreed() const; + void setBreed(const std::string& breed); + [[nodiscard]] int getBarkVolume() const; + void setBarkVolume(const int& barkVolume); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(Dog, + breed, barkVolume) + +private: + std::string breed; + int barkVolume; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/Employee.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/Employee.cpp new file mode 100644 index 000000000000..a060524f38d7 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/Employee.cpp @@ -0,0 +1,76 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "Employee.h" + +namespace models { + +Employee::Employee() +: id(0) +, name("") +, email("") +, address(Address()) +, skills(std::vector()) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +int Employee::getId() const +{ + return id; +} +std::string Employee::getName() const +{ + return name; +} +std::string Employee::getEmail() const +{ + return email; +} +Address Employee::getAddress() const +{ + return address; +} +std::vector Employee::getSkills() const +{ + return skills; +} + +// =================== +// ===== Setters ===== +// =================== +void Employee::setId(const int& idObj) +{ + id = idObj; +} +void Employee::setName(const std::string& nameObj) +{ + name = nameObj; +} +void Employee::setEmail(const std::string& emailObj) +{ + email = emailObj; +} +void Employee::setAddress(const Address& addressObj) +{ + address = addressObj; +} +void Employee::setSkills(const std::vector& skillsObj) +{ + skills = skillsObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/Employee.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/Employee.h new file mode 100644 index 000000000000..1a7bb642a773 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/Employee.h @@ -0,0 +1,54 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include +#include +#include "Address.h" + + + +namespace models { + + +class Employee +{ +public: + + Employee(); + virtual ~Employee() = default; + + // Getters and setters + [[nodiscard]] int getId() const; + void setId(const int& id); + [[nodiscard]] std::string getName() const; + void setName(const std::string& name); + [[nodiscard]] std::string getEmail() const; + void setEmail(const std::string& email); + [[nodiscard]] Address getAddress() const; + void setAddress(const Address& address); + [[nodiscard]] std::vector getSkills() const; + void setSkills(const std::vector& skills); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(Employee, + id, name, email, address, skills) + +private: + int id; + std::string name; + std::string email; + Address address; + std::vector skills; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/EnumTypes.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/EnumTypes.cpp new file mode 100644 index 000000000000..334c79e77668 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/EnumTypes.cpp @@ -0,0 +1,176 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "EnumTypes.h" + +namespace models { + +EnumTypes::EnumTypes() +: stringEnum(std::nullopt) +, numericEnum(std::nullopt) +, statusCode(std::nullopt) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::optional EnumTypes::getStringEnum() const +{ + return stringEnum; +} +std::optional EnumTypes::getNumericEnum() const +{ + return numericEnum; +} +std::optional EnumTypes::getStatusCode() const +{ + return statusCode; +} + +// =================== +// ===== Setters ===== +// =================== +void EnumTypes::setStringEnum(const std::optional& stringEnumObj) +{ + stringEnum = stringEnumObj; +} +void EnumTypes::setNumericEnum(const std::optional& numericEnumObj) +{ + numericEnum = numericEnumObj; +} +void EnumTypes::setStatusCode(const std::optional& statusCodeObj) +{ + statusCode = statusCodeObj; +} + + +// ========================================= +// ===== Enum StringEnumEnum Conversions ===== +// ========================================= +std::string EnumTypes::StringEnumEnumToString(EnumTypes::StringEnumEnum value) +{ + switch (value) + { + case StringEnumEnum::UNSPECIFIED: return "UNSPECIFIED"; + case StringEnumEnum::PENDING: return "PENDING"; + case StringEnumEnum::APPROVED: return "APPROVED"; + case StringEnumEnum::REJECTED: return "REJECTED"; + default: return {}; + } +} + +EnumTypes::StringEnumEnum EnumTypes::StringEnumEnumFromString(const std::string& str) +{ + if (str == "UNSPECIFIED") + { + return StringEnumEnum::UNSPECIFIED; + } + if (str == "PENDING") + { + return StringEnumEnum::PENDING; + } + if (str == "APPROVED") + { + return StringEnumEnum::APPROVED; + } + if (str == "REJECTED") + { + return StringEnumEnum::REJECTED; + } + throw std::invalid_argument("Invalid enum value"); +} + +// ========================================= +// ===== Enum NumericEnumEnum Conversions ===== +// ========================================= +std::string EnumTypes::NumericEnumEnumToString(EnumTypes::NumericEnumEnum value) +{ + switch (value) + { + case NumericEnumEnum::UNSPECIFIED: return "UNSPECIFIED"; + case NumericEnumEnum::_100: return "_100"; + case NumericEnumEnum::_200: return "_200"; + case NumericEnumEnum::_300: return "_300"; + case NumericEnumEnum::_404: return "_404"; + case NumericEnumEnum::_500: return "_500"; + default: return {}; + } +} + +EnumTypes::NumericEnumEnum EnumTypes::NumericEnumEnumFromString(const std::string& str) +{ + if (str == "UNSPECIFIED") + { + return NumericEnumEnum::UNSPECIFIED; + } + if (str == "_100") + { + return NumericEnumEnum::_100; + } + if (str == "_200") + { + return NumericEnumEnum::_200; + } + if (str == "_300") + { + return NumericEnumEnum::_300; + } + if (str == "_404") + { + return NumericEnumEnum::_404; + } + if (str == "_500") + { + return NumericEnumEnum::_500; + } + throw std::invalid_argument("Invalid enum value"); +} + +// ========================================= +// ===== Enum StatusCodeEnum Conversions ===== +// ========================================= +std::string EnumTypes::StatusCodeEnumToString(EnumTypes::StatusCodeEnum value) +{ + switch (value) + { + case StatusCodeEnum::UNSPECIFIED: return "UNSPECIFIED"; + case StatusCodeEnum::_200: return "_200"; + case StatusCodeEnum::_404: return "_404"; + case StatusCodeEnum::_500: return "_500"; + default: return {}; + } +} + +EnumTypes::StatusCodeEnum EnumTypes::StatusCodeEnumFromString(const std::string& str) +{ + if (str == "UNSPECIFIED") + { + return StatusCodeEnum::UNSPECIFIED; + } + if (str == "_200") + { + return StatusCodeEnum::_200; + } + if (str == "_404") + { + return StatusCodeEnum::_404; + } + if (str == "_500") + { + return StatusCodeEnum::_500; + } + throw std::invalid_argument("Invalid enum value"); +} + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/EnumTypes.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/EnumTypes.h new file mode 100644 index 000000000000..6ea087bf17e3 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/EnumTypes.h @@ -0,0 +1,171 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include +#include + + + +namespace models { + + +class EnumTypes +{ +public: + // =================== + // ===== Enums ======= + // =================== + enum class StringEnumEnum { + UNSPECIFIED, + PENDING, + APPROVED, + REJECTED + }; + + // Enum conversion functions (definitions in .cpp) + static std::string StringEnumEnumToString(StringEnumEnum value); + static StringEnumEnum StringEnumEnumFromString(const std::string& str); + + enum class NumericEnumEnum { + UNSPECIFIED, + _100, + _200, + _300, + _404, + _500 + }; + + // Enum conversion functions (definitions in .cpp) + static std::string NumericEnumEnumToString(NumericEnumEnum value); + static NumericEnumEnum NumericEnumEnumFromString(const std::string& str); + + enum class StatusCodeEnum { + UNSPECIFIED, + _200, + _404, + _500 + }; + + // Enum conversion functions (definitions in .cpp) + static std::string StatusCodeEnumToString(StatusCodeEnum value); + static StatusCodeEnum StatusCodeEnumFromString(const std::string& str); + + + EnumTypes(); + virtual ~EnumTypes() = default; + + // Getters and setters + [[nodiscard]] std::optional getStringEnum() const; + void setStringEnum(const std::optional& stringEnum); + [[nodiscard]] std::optional getNumericEnum() const; + void setNumericEnum(const std::optional& numericEnum); + [[nodiscard]] std::optional getStatusCode() const; + void setStatusCode(const std::optional& statusCode); + + // ============================================================================= + // Friend Enum Serialization Helpers (Required for NLOHMANN JSON serialization) + // ============================================================================= + // These friend functions must be declared inside the class because: + // 1. The enum types are nested and don't exist before the class is defined + // 2. NLOHMANN macros need custom serialization for enum types (uses ToString/FromString) + // 3. The 'friend' keyword makes them free functions in the namespace (not member functions) + // so ADL (Argument-Dependent Lookup) can find them during JSON serialization + // ============================================================================= + + // Serialization helpers for std::optional + friend inline void to_json(nlohmann::json& j, const std::optional& opt) + { + if (opt.has_value()) + { + j = StringEnumEnumToString(opt.value()); + } + else + { + j = nullptr; + } + } + + friend inline void from_json(const nlohmann::json& j, std::optional& opt) + { + if (j.is_null()) + { + opt = std::nullopt; + } + else + { + opt = StringEnumEnumFromString(j.get()); + } + } + + // Serialization helpers for std::optional + friend inline void to_json(nlohmann::json& j, const std::optional& opt) + { + if (opt.has_value()) + { + j = NumericEnumEnumToString(opt.value()); + } + else + { + j = nullptr; + } + } + + friend inline void from_json(const nlohmann::json& j, std::optional& opt) + { + if (j.is_null()) + { + opt = std::nullopt; + } + else + { + opt = NumericEnumEnumFromString(j.get()); + } + } + + // Serialization helpers for std::optional + friend inline void to_json(nlohmann::json& j, const std::optional& opt) + { + if (opt.has_value()) + { + j = StatusCodeEnumToString(opt.value()); + } + else + { + j = nullptr; + } + } + + friend inline void from_json(const nlohmann::json& j, std::optional& opt) + { + if (j.is_null()) + { + opt = std::nullopt; + } + else + { + opt = StatusCodeEnumFromString(j.get()); + } + } + + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(EnumTypes, + stringEnum, numericEnum, statusCode) + +private: + std::optional stringEnum; + std::optional numericEnum; + std::optional statusCode; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/ErrorResponse.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/ErrorResponse.cpp new file mode 100644 index 000000000000..0325e127c914 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/ErrorResponse.cpp @@ -0,0 +1,58 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "ErrorResponse.h" + +namespace models { + +ErrorResponse::ErrorResponse() +: message("") +, code(0) +, details(std::vector()) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string ErrorResponse::getMessage() const +{ + return message; +} +int ErrorResponse::getCode() const +{ + return code; +} +std::vector ErrorResponse::getDetails() const +{ + return details; +} + +// =================== +// ===== Setters ===== +// =================== +void ErrorResponse::setMessage(const std::string& messageObj) +{ + message = messageObj; +} +void ErrorResponse::setCode(const int& codeObj) +{ + code = codeObj; +} +void ErrorResponse::setDetails(const std::vector& detailsObj) +{ + details = detailsObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/ErrorResponse.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/ErrorResponse.h new file mode 100644 index 000000000000..72f143d780e9 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/ErrorResponse.h @@ -0,0 +1,47 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include +#include + + + +namespace models { + + +class ErrorResponse +{ +public: + + ErrorResponse(); + virtual ~ErrorResponse() = default; + + // Getters and setters + [[nodiscard]] std::string getMessage() const; + void setMessage(const std::string& message); + [[nodiscard]] int getCode() const; + void setCode(const int& code); + [[nodiscard]] std::vector getDetails() const; + void setDetails(const std::vector& details); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(ErrorResponse, + message, code, details) + +private: + std::string message; + int code; + std::vector details; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/NotFoundResponse.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/NotFoundResponse.cpp new file mode 100644 index 000000000000..f8e1f625164e --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/NotFoundResponse.cpp @@ -0,0 +1,49 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "NotFoundResponse.h" + +namespace models { + +NotFoundResponse::NotFoundResponse() +: error("") +, resource("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string NotFoundResponse::getError() const +{ + return error; +} +std::string NotFoundResponse::getResource() const +{ + return resource; +} + +// =================== +// ===== Setters ===== +// =================== +void NotFoundResponse::setError(const std::string& errorObj) +{ + error = errorObj; +} +void NotFoundResponse::setResource(const std::string& resourceObj) +{ + resource = resourceObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/NotFoundResponse.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/NotFoundResponse.h new file mode 100644 index 000000000000..9b209b5d3f2e --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/NotFoundResponse.h @@ -0,0 +1,42 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class NotFoundResponse +{ +public: + + NotFoundResponse(); + virtual ~NotFoundResponse() = default; + + // Getters and setters + [[nodiscard]] std::string getError() const; + void setError(const std::string& error); + [[nodiscard]] std::string getResource() const; + void setResource(const std::string& resource); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(NotFoundResponse, + error, resource) + +private: + std::string error; + std::string resource; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/NullableOptionalTypes.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/NullableOptionalTypes.cpp new file mode 100644 index 000000000000..44927b9a4d04 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/NullableOptionalTypes.cpp @@ -0,0 +1,76 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "NullableOptionalTypes.h" + +namespace models { + +NullableOptionalTypes::NullableOptionalTypes() +: requiredField("") +, optionalField("") +, nullableField("") +, optionalNullableField("") +, fieldWithDefault(42) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string NullableOptionalTypes::getRequiredField() const +{ + return requiredField; +} +std::string NullableOptionalTypes::getOptionalField() const +{ + return optionalField; +} +std::string NullableOptionalTypes::getNullableField() const +{ + return nullableField; +} +std::string NullableOptionalTypes::getOptionalNullableField() const +{ + return optionalNullableField; +} +int NullableOptionalTypes::getFieldWithDefault() const +{ + return fieldWithDefault; +} + +// =================== +// ===== Setters ===== +// =================== +void NullableOptionalTypes::setRequiredField(const std::string& requiredFieldObj) +{ + requiredField = requiredFieldObj; +} +void NullableOptionalTypes::setOptionalField(const std::string& optionalFieldObj) +{ + optionalField = optionalFieldObj; +} +void NullableOptionalTypes::setNullableField(const std::string& nullableFieldObj) +{ + nullableField = nullableFieldObj; +} +void NullableOptionalTypes::setOptionalNullableField(const std::string& optionalNullableFieldObj) +{ + optionalNullableField = optionalNullableFieldObj; +} +void NullableOptionalTypes::setFieldWithDefault(const int& fieldWithDefaultObj) +{ + fieldWithDefault = fieldWithDefaultObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/NullableOptionalTypes.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/NullableOptionalTypes.h new file mode 100644 index 000000000000..7e5df57ad443 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/NullableOptionalTypes.h @@ -0,0 +1,53 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include +#include + + + +namespace models { + + +class NullableOptionalTypes +{ +public: + + NullableOptionalTypes(); + virtual ~NullableOptionalTypes() = default; + + // Getters and setters + [[nodiscard]] std::string getRequiredField() const; + void setRequiredField(const std::string& requiredField); + [[nodiscard]] std::string getOptionalField() const; + void setOptionalField(const std::string& optionalField); + [[nodiscard]] std::string getNullableField() const; + void setNullableField(const std::string& nullableField); + [[nodiscard]] std::string getOptionalNullableField() const; + void setOptionalNullableField(const std::string& optionalNullableField); + [[nodiscard]] int getFieldWithDefault() const; + void setFieldWithDefault(const int& fieldWithDefault); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(NullableOptionalTypes, + requiredField, optionalField, nullableField, optionalNullableField, fieldWithDefault) + +private: + std::string requiredField; + std::string optionalField; + std::string nullableField; + std::string optionalNullableField; + int fieldWithDefault; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/PaymentMethod.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/PaymentMethod.cpp new file mode 100644 index 000000000000..978e7ed2bef8 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/PaymentMethod.cpp @@ -0,0 +1,7 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/PaymentMethod.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/PaymentMethod.h new file mode 100644 index 000000000000..0f5d86c9fae5 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/PaymentMethod.h @@ -0,0 +1,48 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include +#include "BankAccount.h" +#include "CreditCard.h" + + + +namespace models { + +// oneOf schema - type alias for std::variant +using PaymentMethod = std::variant< + CreditCard, + BankAccount>; + +// JSON serialization functions (inline for header-only) +inline void from_json(const nlohmann::json& j, PaymentMethod& obj) { + if (!j.contains("paymentType")) { + throw nlohmann::json::type_error::create(302, "Discriminator property 'paymentType' not found in JSON", &j); + } + std::string discriminatorValue = j["paymentType"].get(); + if (discriminatorValue == "credit_card") { + obj = j.get(); + return; + } + if (discriminatorValue == "bank_account") { + obj = j.get(); + return; + } + throw nlohmann::json::type_error::create(302, "Unknown discriminator value: " + discriminatorValue, &j); +} + +inline void to_json(nlohmann::json& j, const PaymentMethod& obj) +{ + std::visit([&j](const auto& val) { j = nlohmann::json(val); }, obj); +} + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/PrimitiveTypes.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/PrimitiveTypes.cpp new file mode 100644 index 000000000000..ce48934299fe --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/PrimitiveTypes.cpp @@ -0,0 +1,130 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "PrimitiveTypes.h" + +namespace models { + +PrimitiveTypes::PrimitiveTypes() +: stringField("") +, intField(0) +, longField(0) +, floatField(0.0f) +, doubleField(0.0) +, boolField(false) +, byteField(std::vector()) +, binaryField("") +, dateField("") +, dateTimeField("") +, passwordField("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string PrimitiveTypes::getStringField() const +{ + return stringField; +} +int PrimitiveTypes::getIntField() const +{ + return intField; +} +long PrimitiveTypes::getLongField() const +{ + return longField; +} +float PrimitiveTypes::getFloatField() const +{ + return floatField; +} +double PrimitiveTypes::getDoubleField() const +{ + return doubleField; +} +bool PrimitiveTypes::isBoolField() const +{ + return boolField; +} +std::vector PrimitiveTypes::getByteField() const +{ + return byteField; +} +std::string PrimitiveTypes::getBinaryField() const +{ + return binaryField; +} +std::string PrimitiveTypes::getDateField() const +{ + return dateField; +} +std::string PrimitiveTypes::getDateTimeField() const +{ + return dateTimeField; +} +std::string PrimitiveTypes::getPasswordField() const +{ + return passwordField; +} + +// =================== +// ===== Setters ===== +// =================== +void PrimitiveTypes::setStringField(const std::string& stringFieldObj) +{ + stringField = stringFieldObj; +} +void PrimitiveTypes::setIntField(const int& intFieldObj) +{ + intField = intFieldObj; +} +void PrimitiveTypes::setLongField(const long& longFieldObj) +{ + longField = longFieldObj; +} +void PrimitiveTypes::setFloatField(const float& floatFieldObj) +{ + floatField = floatFieldObj; +} +void PrimitiveTypes::setDoubleField(const double& doubleFieldObj) +{ + doubleField = doubleFieldObj; +} +void PrimitiveTypes::setBoolField(const bool& boolFieldObj) +{ + boolField = boolFieldObj; +} +void PrimitiveTypes::setByteField(const std::vector& byteFieldObj) +{ + byteField = byteFieldObj; +} +void PrimitiveTypes::setBinaryField(const std::string& binaryFieldObj) +{ + binaryField = binaryFieldObj; +} +void PrimitiveTypes::setDateField(const std::string& dateFieldObj) +{ + dateField = dateFieldObj; +} +void PrimitiveTypes::setDateTimeField(const std::string& dateTimeFieldObj) +{ + dateTimeField = dateTimeFieldObj; +} +void PrimitiveTypes::setPasswordField(const std::string& passwordFieldObj) +{ + passwordField = passwordFieldObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/PrimitiveTypes.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/PrimitiveTypes.h new file mode 100644 index 000000000000..89894663074b --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/PrimitiveTypes.h @@ -0,0 +1,70 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include + + + +namespace models { + + +class PrimitiveTypes +{ +public: + + PrimitiveTypes(); + virtual ~PrimitiveTypes() = default; + + // Getters and setters + [[nodiscard]] std::string getStringField() const; + void setStringField(const std::string& stringField); + [[nodiscard]] int getIntField() const; + void setIntField(const int& intField); + [[nodiscard]] long getLongField() const; + void setLongField(const long& longField); + [[nodiscard]] float getFloatField() const; + void setFloatField(const float& floatField); + [[nodiscard]] double getDoubleField() const; + void setDoubleField(const double& doubleField); + [[nodiscard]] bool isBoolField() const; + void setBoolField(const bool& boolField); + [[nodiscard]] std::vector getByteField() const; + void setByteField(const std::vector& byteField); + [[nodiscard]] std::string getBinaryField() const; + void setBinaryField(const std::string& binaryField); + [[nodiscard]] std::string getDateField() const; + void setDateField(const std::string& dateField); + [[nodiscard]] std::string getDateTimeField() const; + void setDateTimeField(const std::string& dateTimeField); + [[nodiscard]] std::string getPasswordField() const; + void setPasswordField(const std::string& passwordField); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(PrimitiveTypes, + stringField, intField, longField, floatField, doubleField, boolField, byteField, binaryField, dateField, dateTimeField, passwordField) + +private: + std::string stringField; + int intField; + long longField; + float floatField; + double doubleField; + bool boolField; + std::vector byteField; + std::string binaryField; + std::string dateField; + std::string dateTimeField; + std::string passwordField; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/SimpleObject.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/SimpleObject.cpp new file mode 100644 index 000000000000..ca5de491bea0 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/SimpleObject.cpp @@ -0,0 +1,58 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "SimpleObject.h" + +namespace models { + +SimpleObject::SimpleObject() +: id(0) +, name("") +, description("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +int SimpleObject::getId() const +{ + return id; +} +std::string SimpleObject::getName() const +{ + return name; +} +std::string SimpleObject::getDescription() const +{ + return description; +} + +// =================== +// ===== Setters ===== +// =================== +void SimpleObject::setId(const int& idObj) +{ + id = idObj; +} +void SimpleObject::setName(const std::string& nameObj) +{ + name = nameObj; +} +void SimpleObject::setDescription(const std::string& descriptionObj) +{ + description = descriptionObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/SimpleObject.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/SimpleObject.h new file mode 100644 index 000000000000..eae83fbbe860 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/SimpleObject.h @@ -0,0 +1,46 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include + + + +namespace models { + + +class SimpleObject +{ +public: + + SimpleObject(); + virtual ~SimpleObject() = default; + + // Getters and setters + [[nodiscard]] int getId() const; + void setId(const int& id); + [[nodiscard]] std::string getName() const; + void setName(const std::string& name); + [[nodiscard]] std::string getDescription() const; + void setDescription(const std::string& description); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(SimpleObject, + id, name, description) + +private: + int id; + std::string name; + std::string description; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/StringOrNumber.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/StringOrNumber.cpp new file mode 100644 index 000000000000..978e7ed2bef8 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/StringOrNumber.cpp @@ -0,0 +1,7 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/StringOrNumber.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/StringOrNumber.h new file mode 100644 index 000000000000..5e6d40483e0e --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/StringOrNumber.h @@ -0,0 +1,52 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + +// anyOf schema - type alias for std::variant +using StringOrNumber = std::variant< + std::string, + double >; + +// JSON serialization functions (inline for header-only) +inline void from_json(const nlohmann::json& j, StringOrNumber& obj) +{ + try + { + obj = j.get(); + return; + } + catch (const nlohmann::json::exception&) + { + // Type mismatch, try next variant alternative + } + try + { + obj = j.get(); + return; + } + catch (const nlohmann::json::exception&) + { + // Type mismatch, try next variant alternative + } + throw nlohmann::json::type_error::create(302, "Could not deserialize into any variant type of StringOrNumber", &j); +} + +inline void to_json(nlohmann::json& j, const StringOrNumber& obj) +{ + std::visit([&j](const auto& val) { j = nlohmann::json(val); }, obj); +} + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/SuccessResponse.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/SuccessResponse.cpp new file mode 100644 index 000000000000..e4643d35b70f --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/SuccessResponse.cpp @@ -0,0 +1,48 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "SuccessResponse.h" + +namespace models { + +SuccessResponse::SuccessResponse() +: status("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string SuccessResponse::getStatus() const +{ + return status; +} +nlohmann::json SuccessResponse::getData() const +{ + return data; +} + +// =================== +// ===== Setters ===== +// =================== +void SuccessResponse::setStatus(const std::string& statusObj) +{ + status = statusObj; +} +void SuccessResponse::setData(const nlohmann::json& dataObj) +{ + data = dataObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/SuccessResponse.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/SuccessResponse.h new file mode 100644 index 000000000000..a6de84bce543 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/SuccessResponse.h @@ -0,0 +1,42 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class SuccessResponse +{ +public: + + SuccessResponse(); + virtual ~SuccessResponse() = default; + + // Getters and setters + [[nodiscard]] std::string getStatus() const; + void setStatus(const std::string& status); + [[nodiscard]] nlohmann::json getData() const; + void setData(const nlohmann::json& data); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(SuccessResponse, + status, data) + +private: + std::string status; + nlohmann::json data; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestAllParameterTypes200Response.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestAllParameterTypes200Response.cpp new file mode 100644 index 000000000000..0e09058796fd --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestAllParameterTypes200Response.cpp @@ -0,0 +1,67 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "TestAllParameterTypes200Response.h" + +namespace models { + +TestAllParameterTypes200Response::TestAllParameterTypes200Response() +: message("") +, resourceId(0) +, filter("") +, correlationId("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string TestAllParameterTypes200Response::getMessage() const +{ + return message; +} +int TestAllParameterTypes200Response::getResourceId() const +{ + return resourceId; +} +std::string TestAllParameterTypes200Response::getFilter() const +{ + return filter; +} +std::string TestAllParameterTypes200Response::getCorrelationId() const +{ + return correlationId; +} + +// =================== +// ===== Setters ===== +// =================== +void TestAllParameterTypes200Response::setMessage(const std::string& messageObj) +{ + message = messageObj; +} +void TestAllParameterTypes200Response::setResourceId(const int& resourceIdObj) +{ + resourceId = resourceIdObj; +} +void TestAllParameterTypes200Response::setFilter(const std::string& filterObj) +{ + filter = filterObj; +} +void TestAllParameterTypes200Response::setCorrelationId(const std::string& correlationIdObj) +{ + correlationId = correlationIdObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestAllParameterTypes200Response.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestAllParameterTypes200Response.h new file mode 100644 index 000000000000..ce9ade6be871 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestAllParameterTypes200Response.h @@ -0,0 +1,49 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include + + + +namespace models { + + +class TestAllParameterTypes200Response +{ +public: + + TestAllParameterTypes200Response(); + virtual ~TestAllParameterTypes200Response() = default; + + // Getters and setters + [[nodiscard]] std::string getMessage() const; + void setMessage(const std::string& message); + [[nodiscard]] int getResourceId() const; + void setResourceId(const int& resourceId); + [[nodiscard]] std::string getFilter() const; + void setFilter(const std::string& filter); + [[nodiscard]] std::string getCorrelationId() const; + void setCorrelationId(const std::string& correlationId); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(TestAllParameterTypes200Response, + message, resourceId, filter, correlationId) + +private: + std::string message; + int resourceId; + std::string filter; + std::string correlationId; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestApiKeySecurity200Response.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestApiKeySecurity200Response.cpp new file mode 100644 index 000000000000..00d8d58d0a98 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestApiKeySecurity200Response.cpp @@ -0,0 +1,40 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "TestApiKeySecurity200Response.h" + +namespace models { + +TestApiKeySecurity200Response::TestApiKeySecurity200Response() +: message("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string TestApiKeySecurity200Response::getMessage() const +{ + return message; +} + +// =================== +// ===== Setters ===== +// =================== +void TestApiKeySecurity200Response::setMessage(const std::string& messageObj) +{ + message = messageObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestApiKeySecurity200Response.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestApiKeySecurity200Response.h new file mode 100644 index 000000000000..f2ebdc38cc2d --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestApiKeySecurity200Response.h @@ -0,0 +1,39 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class TestApiKeySecurity200Response +{ +public: + + TestApiKeySecurity200Response(); + virtual ~TestApiKeySecurity200Response() = default; + + // Getters and setters + [[nodiscard]] std::string getMessage() const; + void setMessage(const std::string& message); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(TestApiKeySecurity200Response, + message) + +private: + std::string message; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestBasicSecurity200Response.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestBasicSecurity200Response.cpp new file mode 100644 index 000000000000..d771a778e249 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestBasicSecurity200Response.cpp @@ -0,0 +1,40 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "TestBasicSecurity200Response.h" + +namespace models { + +TestBasicSecurity200Response::TestBasicSecurity200Response() +: message("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string TestBasicSecurity200Response::getMessage() const +{ + return message; +} + +// =================== +// ===== Setters ===== +// =================== +void TestBasicSecurity200Response::setMessage(const std::string& messageObj) +{ + message = messageObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestBasicSecurity200Response.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestBasicSecurity200Response.h new file mode 100644 index 000000000000..c2a923e72215 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestBasicSecurity200Response.h @@ -0,0 +1,39 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class TestBasicSecurity200Response +{ +public: + + TestBasicSecurity200Response(); + virtual ~TestBasicSecurity200Response() = default; + + // Getters and setters + [[nodiscard]] std::string getMessage() const; + void setMessage(const std::string& message); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(TestBasicSecurity200Response, + message) + +private: + std::string message; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestBearerSecurity200Response.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestBearerSecurity200Response.cpp new file mode 100644 index 000000000000..64246114370c --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestBearerSecurity200Response.cpp @@ -0,0 +1,40 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "TestBearerSecurity200Response.h" + +namespace models { + +TestBearerSecurity200Response::TestBearerSecurity200Response() +: message("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string TestBearerSecurity200Response::getMessage() const +{ + return message; +} + +// =================== +// ===== Setters ===== +// =================== +void TestBearerSecurity200Response::setMessage(const std::string& messageObj) +{ + message = messageObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestBearerSecurity200Response.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestBearerSecurity200Response.h new file mode 100644 index 000000000000..0cb7cbe8421d --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestBearerSecurity200Response.h @@ -0,0 +1,39 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class TestBearerSecurity200Response +{ +public: + + TestBearerSecurity200Response(); + virtual ~TestBearerSecurity200Response() = default; + + // Getters and setters + [[nodiscard]] std::string getMessage() const; + void setMessage(const std::string& message); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(TestBearerSecurity200Response, + message) + +private: + std::string message; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestCookieParameters200Response.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestCookieParameters200Response.cpp new file mode 100644 index 000000000000..8079fafa8b98 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestCookieParameters200Response.cpp @@ -0,0 +1,40 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "TestCookieParameters200Response.h" + +namespace models { + +TestCookieParameters200Response::TestCookieParameters200Response() +: message("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string TestCookieParameters200Response::getMessage() const +{ + return message; +} + +// =================== +// ===== Setters ===== +// =================== +void TestCookieParameters200Response::setMessage(const std::string& messageObj) +{ + message = messageObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestCookieParameters200Response.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestCookieParameters200Response.h new file mode 100644 index 000000000000..a5548cc28b0d --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestCookieParameters200Response.h @@ -0,0 +1,39 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class TestCookieParameters200Response +{ +public: + + TestCookieParameters200Response(); + virtual ~TestCookieParameters200Response() = default; + + // Getters and setters + [[nodiscard]] std::string getMessage() const; + void setMessage(const std::string& message); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(TestCookieParameters200Response, + message) + +private: + std::string message; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestHeaderParameters200Response.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestHeaderParameters200Response.cpp new file mode 100644 index 000000000000..7097e8c5ec5b --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestHeaderParameters200Response.cpp @@ -0,0 +1,40 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "TestHeaderParameters200Response.h" + +namespace models { + +TestHeaderParameters200Response::TestHeaderParameters200Response() +: message("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string TestHeaderParameters200Response::getMessage() const +{ + return message; +} + +// =================== +// ===== Setters ===== +// =================== +void TestHeaderParameters200Response::setMessage(const std::string& messageObj) +{ + message = messageObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestHeaderParameters200Response.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestHeaderParameters200Response.h new file mode 100644 index 000000000000..cb091980a63d --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestHeaderParameters200Response.h @@ -0,0 +1,39 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class TestHeaderParameters200Response +{ +public: + + TestHeaderParameters200Response(); + virtual ~TestHeaderParameters200Response() = default; + + // Getters and setters + [[nodiscard]] std::string getMessage() const; + void setMessage(const std::string& message); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(TestHeaderParameters200Response, + message) + +private: + std::string message; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestHeaderParameters401Response.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestHeaderParameters401Response.cpp new file mode 100644 index 000000000000..c8557584d4e1 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestHeaderParameters401Response.cpp @@ -0,0 +1,40 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "TestHeaderParameters401Response.h" + +namespace models { + +TestHeaderParameters401Response::TestHeaderParameters401Response() +: message("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string TestHeaderParameters401Response::getMessage() const +{ + return message; +} + +// =================== +// ===== Setters ===== +// =================== +void TestHeaderParameters401Response::setMessage(const std::string& messageObj) +{ + message = messageObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestHeaderParameters401Response.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestHeaderParameters401Response.h new file mode 100644 index 000000000000..7b6e0d5ed738 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestHeaderParameters401Response.h @@ -0,0 +1,39 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class TestHeaderParameters401Response +{ +public: + + TestHeaderParameters401Response(); + virtual ~TestHeaderParameters401Response() = default; + + // Getters and setters + [[nodiscard]] std::string getMessage() const; + void setMessage(const std::string& message); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(TestHeaderParameters401Response, + message) + +private: + std::string message; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestOAuth2Security200Response.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestOAuth2Security200Response.cpp new file mode 100644 index 000000000000..cfc17d555760 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestOAuth2Security200Response.cpp @@ -0,0 +1,40 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "TestOAuth2Security200Response.h" + +namespace models { + +TestOAuth2Security200Response::TestOAuth2Security200Response() +: message("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string TestOAuth2Security200Response::getMessage() const +{ + return message; +} + +// =================== +// ===== Setters ===== +// =================== +void TestOAuth2Security200Response::setMessage(const std::string& messageObj) +{ + message = messageObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestOAuth2Security200Response.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestOAuth2Security200Response.h new file mode 100644 index 000000000000..8e232d4866a2 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestOAuth2Security200Response.h @@ -0,0 +1,39 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class TestOAuth2Security200Response +{ +public: + + TestOAuth2Security200Response(); + virtual ~TestOAuth2Security200Response() = default; + + // Getters and setters + [[nodiscard]] std::string getMessage() const; + void setMessage(const std::string& message); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(TestOAuth2Security200Response, + message) + +private: + std::string message; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestQueryParameters200Response.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestQueryParameters200Response.cpp new file mode 100644 index 000000000000..01a46047c081 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestQueryParameters200Response.cpp @@ -0,0 +1,40 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "TestQueryParameters200Response.h" + +namespace models { + +TestQueryParameters200Response::TestQueryParameters200Response() +: message("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string TestQueryParameters200Response::getMessage() const +{ + return message; +} + +// =================== +// ===== Setters ===== +// =================== +void TestQueryParameters200Response::setMessage(const std::string& messageObj) +{ + message = messageObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestQueryParameters200Response.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestQueryParameters200Response.h new file mode 100644 index 000000000000..7b7b05c4d919 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestQueryParameters200Response.h @@ -0,0 +1,39 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class TestQueryParameters200Response +{ +public: + + TestQueryParameters200Response(); + virtual ~TestQueryParameters200Response() = default; + + // Getters and setters + [[nodiscard]] std::string getMessage() const; + void setMessage(const std::string& message); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(TestQueryParameters200Response, + message) + +private: + std::string message; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestQueryParametersDeepObjectParameter.cpp b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestQueryParametersDeepObjectParameter.cpp new file mode 100644 index 000000000000..6146ef611646 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestQueryParametersDeepObjectParameter.cpp @@ -0,0 +1,49 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "TestQueryParametersDeepObjectParameter.h" + +namespace models { + +TestQueryParametersDeepObjectParameter::TestQueryParametersDeepObjectParameter() +: name("") +, age(0) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string TestQueryParametersDeepObjectParameter::getName() const +{ + return name; +} +int TestQueryParametersDeepObjectParameter::getAge() const +{ + return age; +} + +// =================== +// ===== Setters ===== +// =================== +void TestQueryParametersDeepObjectParameter::setName(const std::string& nameObj) +{ + name = nameObj; +} +void TestQueryParametersDeepObjectParameter::setAge(const int& ageObj) +{ + age = ageObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/feature-test/models/TestQueryParametersDeepObjectParameter.h b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestQueryParametersDeepObjectParameter.h new file mode 100644 index 000000000000..76d6f4edeaea --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/feature-test/models/TestQueryParametersDeepObjectParameter.h @@ -0,0 +1,43 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include + + + +namespace models { + + +class TestQueryParametersDeepObjectParameter +{ +public: + + TestQueryParametersDeepObjectParameter(); + virtual ~TestQueryParametersDeepObjectParameter() = default; + + // Getters and setters + [[nodiscard]] std::string getName() const; + void setName(const std::string& name); + [[nodiscard]] int getAge() const; + void setAge(const int& age); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(TestQueryParametersDeepObjectParameter, + name, age) + +private: + std::string name; + int age; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/.openapi-generator-ignore b/samples/server/petstore/cpp-httplib-server/petstore/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/petstore/cpp-httplib-server/petstore/.openapi-generator/FILES b/samples/server/petstore/cpp-httplib-server/petstore/.openapi-generator/FILES new file mode 100644 index 000000000000..cf79c5ee9f1c --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/.openapi-generator/FILES @@ -0,0 +1,31 @@ +CMakeLists.txt +LICENSE +README.md +api/PetApi.cpp +api/PetApi.h +api/StoreApi.cpp +api/StoreApi.h +api/UserApi.cpp +api/UserApi.h +models/ApiResponse.cpp +models/ApiResponse.h +models/Category.cpp +models/Category.h +models/ComplexParamsResponse.cpp +models/ComplexParamsResponse.h +models/DeepObj.cpp +models/DeepObj.h +models/DeepObjBaz.cpp +models/DeepObjBaz.h +models/NullableExample.cpp +models/NullableExample.h +models/Order.cpp +models/Order.h +models/Pet.cpp +models/Pet.h +models/PetOrCategory.cpp +models/PetOrCategory.h +models/Tag.cpp +models/Tag.h +models/User.cpp +models/User.h diff --git a/samples/server/petstore/cpp-httplib-server/petstore/.openapi-generator/VERSION b/samples/server/petstore/cpp-httplib-server/petstore/.openapi-generator/VERSION new file mode 100644 index 000000000000..5e5282953086 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.16.0-SNAPSHOT diff --git a/samples/server/petstore/cpp-httplib-server/petstore/CMakeLists.txt b/samples/server/petstore/cpp-httplib-server/petstore/CMakeLists.txt new file mode 100644 index 000000000000..12eb57987293 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.14) +project(cpp_httplib_server_petstore LANGUAGES CXX) + +include(FetchContent) + +# Fetch nlohmann_json +FetchContent_Declare( + nlohmann_json + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_TAG v3.11.3 +) +FetchContent_MakeAvailable(nlohmann_json) + +# Fetch cpp-httplib +FetchContent_Declare( + httplib + GIT_REPOSITORY https://github.com/yhirose/cpp-httplib.git + GIT_TAG v0.15.3 +) +FetchContent_MakeAvailable(httplib) + +# System libraries - install with: sudo apt-get install libssl-dev zlib1g-dev +find_package(OpenSSL REQUIRED) +find_package(ZLIB REQUIRED) + +set(TARGET_NAME cpp_httplib_server_petstore_openapi_lib) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +file(GLOB API_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/api/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/api/*.cpp +) +file(GLOB MODEL_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/models/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/models/*.cpp +) +add_library(${TARGET_NAME} ${API_SRCS} ${MODEL_SRCS}) +target_include_directories (${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +# Make sure these libraries/headers are available in the build environment before linking +# Required libraries/headers are httplib,ssl,nlohmann::json,zlib +target_link_libraries(${TARGET_NAME} + PRIVATE + httplib::httplib + OpenSSL::SSL + OpenSSL::Crypto + nlohmann_json::nlohmann_json + ZLIB::ZLIB) + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/LICENSE b/samples/server/petstore/cpp-httplib-server/petstore/LICENSE new file mode 100644 index 000000000000..286685933869 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/LICENSE @@ -0,0 +1,5 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/petstore/README.md b/samples/server/petstore/cpp-httplib-server/petstore/README.md new file mode 100644 index 000000000000..b9d9bcfeb4e6 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/README.md @@ -0,0 +1,629 @@ +# cpp-httplib-server-petstore - C++ Server + +## Overview + +This server was generated using the [OpenAPI Generator](https://openapi-generator.tech) project. +It uses the [cpp-httplib](https://github.com/yhirose/cpp-httplib) library to implement a lightweight HTTP server +with JSON request/response handling via [nlohmann/json](https://github.com/nlohmann/json). + +## Requirements + +- C++17 compatible compiler +- CMake (3.14 or higher) +- OpenSSL (for HTTPS support) +- ZLIB (for compression support) + +**Note:** The following libraries are automatically downloaded via CMake FetchContent: +- [cpp-httplib](https://github.com/yhirose/cpp-httplib) v0.15.3 +- [nlohmann/json](https://github.com/nlohmann/json) v3.11.3 + +### Platform-Specific Installation + +**Linux (Ubuntu/Debian):** +```bash +sudo apt-get update +sudo apt-get install -y libssl-dev zlib1g-dev cmake build-essential +``` + +**macOS:** +```bash +brew install openssl zlib cmake +``` + +**Windows:** +```powershell +# Using vcpkg +vcpkg install openssl:x64-windows zlib:x64-windows + +# Then configure CMake with vcpkg toolchain: +cmake -B build -DCMAKE_TOOLCHAIN_FILE=[vcpkg_root]/scripts/buildsystems/vcpkg.cmake +``` + +## Project Structure + +``` +├── CMakeLists.txt # Project build configuration +├── README.md # This file +├── models/ # Generated model classes +└── api/ # Generated API handler classes +``` + +## Building the Project + +```bash +mkdir build +cd build +cmake .. +make +``` + +## Working with Models + +### Model Classes + +#### models::ApiResponse + +```cpp +// Create a model +auto model = models::ApiResponse(); +model.setCode(/* value */); // Set code +model.setType(/* value */); // Set type +model.setMessage(/* value */); // Set message + +// Serialize to JSON +nlohmann::json json = models::ApiResponse::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::ApiResponse::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::Category + +```cpp +// Create a model +auto model = models::Category(); +model.setId(/* value */); // Set id +model.setName(/* value */); // Set name + +// Serialize to JSON +nlohmann::json json = models::Category::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::Category::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::ComplexParamsResponse + +```cpp +// Create a model +auto model = models::ComplexParamsResponse(); +model.setDeepObj(/* value */); // Set deepObj +model.setEnumParam(/* value */); // Set enumParam +model.setPipeArr(/* value */); // Set pipeArr +model.setSpaceArr(/* value */); // Set spaceArr +model.setXEnumHeader(/* value */); // Set x-enum-header +model.setCookieEnum(/* value */); // Set cookieEnum + +// Serialize to JSON +nlohmann::json json = models::ComplexParamsResponse::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::ComplexParamsResponse::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::DeepObj + +```cpp +// Create a model +auto model = models::DeepObj(); +model.setFoo(/* value */); // Set foo +model.setBar(/* value */); // Set bar +model.setBaz(/* value */); // Set baz + +// Serialize to JSON +nlohmann::json json = models::DeepObj::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::DeepObj::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::DeepObjBaz + +```cpp +// Create a model +auto model = models::DeepObjBaz(); +model.setX(/* value */); // Set x +model.setY(/* value */); // Set y + +// Serialize to JSON +nlohmann::json json = models::DeepObjBaz::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::DeepObjBaz::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::NullableExample + +```cpp +// Create a model +auto model = models::NullableExample(); +model.setMaybeString(/* value */); // Set maybeString + +// Serialize to JSON +nlohmann::json json = models::NullableExample::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::NullableExample::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::Order + +```cpp +// Create a model +auto model = models::Order(); +model.setId(/* value */); // Set id +model.setPetId(/* value */); // Set petId +model.setQuantity(/* value */); // Set quantity +model.setShipDate(/* value */); // Set shipDate +model.setStatus(/* value */); // Set status +model.setComplete(/* value */); // Set complete + +// Serialize to JSON +nlohmann::json json = models::Order::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::Order::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::Pet + +```cpp +// Create a model +auto model = models::Pet(); +model.setId(/* value */); // Set id +model.setName(/* value */); // Set name +model.setPhotoUrls(/* value */); // Set photoUrls +model.setStatus(/* value */); // Set status +model.setCategory(/* value */); // Set category +model.setTags(/* value */); // Set tags + +// Serialize to JSON +nlohmann::json json = models::Pet::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::Pet::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::PetOrCategory + +```cpp +// Create a model +auto model = models::PetOrCategory(); +model.setId(/* value */); // Set id +model.setName(/* value */); // Set name +model.setPhotoUrls(/* value */); // Set photoUrls +model.setStatus(/* value */); // Set status +model.setCategory(/* value */); // Set category +model.setTags(/* value */); // Set tags + +// Serialize to JSON +nlohmann::json json = models::PetOrCategory::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::PetOrCategory::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::Tag + +```cpp +// Create a model +auto model = models::Tag(); +model.setId(/* value */); // Set id +model.setName(/* value */); // Set name + +// Serialize to JSON +nlohmann::json json = models::Tag::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::Tag::fromJson(nlohmann::json::parse(jsonString)); +``` +#### models::User + +```cpp +// Create a model +auto model = models::User(); +model.setId(/* value */); // Set id +model.setUsername(/* value */); // Set username +model.setFirstName(/* value */); // Set firstName +model.setLastName(/* value */); // Set lastName +model.setEmail(/* value */); // Set email +model.setPassword(/* value */); // Set password +model.setPhone(/* value */); // Set phone +model.setUserStatus(/* value */); // Set userStatus + +// Serialize to JSON +nlohmann::json json = models::User::toJson(model); +std::string jsonString = json.dump(); + +// Deserialize from JSON +auto parsedModel = models::User::fromJson(nlohmann::json::parse(jsonString)); +``` + +## Implementing API Handlers + +### API Classes + +Each API is generated as an abstract base class with pure virtual methods that you must implement. + +#### Pet + +Create a class that inherits from the generated base class: + +```cpp +#include "api/PetApi.h" + +class PetImpl : public api::Pet { +public: + PetPostResponse handlePostForPet(const PetPostRequest& params) override { + // Access request parameters: + // Body: params.m_request (std::optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_PET): + models::Pet successResponse; + // ... populate response ... + return successResponse; + + // Or return error response (HTTP HTTP_RESPONSE_CODE_API_RESPONSE): + // models::ApiResponse errorResponse; + // return errorResponse; + } + + PetcomplexGetResponse handleGetForPetcomplex(const PetcomplexGetRequest& params) override { + // Access request parameters: + // Query: params.m_deepObj (optional) + // Query: params.m_enumParam (optional) + // Query: params.m_pipeArr (optional) + // Query: params.m_spaceArr (optional) + // Header: params.m_xEnumHeader (optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_COMPLEX_PARAMS_RESPONSE): + models::ComplexParamsResponse successResponse; + // ... populate response ... + return successResponse; + } + + void handleDeleteForPetpetId(const PetpetIdDeleteRequest& params) override { + // Access request parameters from params struct + // Implement your logic here + } + + PetfindByStatusGetResponse handleGetForPetfindByStatus(const PetfindByStatusGetRequest& params) override { + // Access request parameters: + // Query: params.m_status + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_PET): + models::Pet successResponse; + // ... populate response ... + return successResponse; + } + + PetfindByTagsGetResponse handleGetForPetfindByTags(const PetfindByTagsGetRequest& params) override { + // Access request parameters: + // Query: params.m_tags + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_PET): + models::Pet successResponse; + // ... populate response ... + return successResponse; + } + + PetpetIdGetResponse handleGetForPetpetId(const PetpetIdGetRequest& params) override { + // Access request parameters: + // Path: params.m_petId + // Header: params.m_customHeader (optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_PET): + models::Pet successResponse; + // ... populate response ... + return successResponse; + + // Or return error response (HTTP HTTP_RESPONSE_CODE_API_RESPONSE): + // models::ApiResponse errorResponse; + // return errorResponse; + } + + void handlePutForPet(const PetPutRequest& params) override { + // Access request parameters from params struct + // Implement your logic here + } + +}; +``` +#### Store + +Create a class that inherits from the generated base class: + +```cpp +#include "api/StoreApi.h" + +class StoreImpl : public api::Store { +public: + void handleDeleteForStoreorderorderId(const StoreorderorderIdDeleteRequest& params) override { + // Access request parameters from params struct + // Implement your logic here + } + + StoreorderorderIdGetResponse handleGetForStoreorderorderId(const StoreorderorderIdGetRequest& params) override { + // Access request parameters: + // Path: params.m_orderId + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_ORDER): + models::Order successResponse; + // ... populate response ... + return successResponse; + } + + StoreorderPostResponse handlePostForStoreorder(const StoreorderPostRequest& params) override { + // Access request parameters: + // Body: params.m_request (std::optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_ORDER): + models::Order successResponse; + // ... populate response ... + return successResponse; + } + +}; +``` +#### User + +Create a class that inherits from the generated base class: + +```cpp +#include "api/UserApi.h" + +class UserImpl : public api::User { +public: + UserPostResponse handlePostForUser(const UserPostRequest& params) override { + // Access request parameters: + // Body: params.m_request (std::optional) + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_USER): + models::User successResponse; + // ... populate response ... + return successResponse; + } + + void handleDeleteForUserusername(const UserusernameDeleteRequest& params) override { + // Access request parameters from params struct + // Implement your logic here + } + + UserusernameGetResponse handleGetForUserusername(const UserusernameGetRequest& params) override { + // Access request parameters: + // Path: params.m_username + + // Implement your business logic here + + // Return success response (HTTP HTTP_RESPONSE_CODE_USER): + models::User successResponse; + // ... populate response ... + return successResponse; + } + + void handlePutForUserusername(const UserusernamePutRequest& params) override { + // Access request parameters from params struct + // Implement your logic here + } + +}; +``` + +## Running the Server + +Here's a complete example of setting up and running the server: + +```cpp +#include +#include + +#include "api/PetApi.h" + +#include "api/StoreApi.h" + +#include "api/UserApi.h" + + +int main() { + httplib::Server server; + + // Create API implementations + + PetImpl pet; + + StoreImpl store; + + UserImpl user; + + + // Register routes + + pet.registerRoutes(server); + + store.registerRoutes(server); + + user.registerRoutes(server); + + + // Start server + std::cout << "Server starting on http://localhost:8080" << std::endl; + server.listen("localhost", 8080); + + return 0; +} +``` + +### Without Authentication + +This API does not require authentication. Simply create your API implementations and register them with the server. + + +## Authentication + +This API does not require authentication. + + +## Error Handling + +### Response Variants + +Each API endpoint that returns data uses `std::variant` to represent multiple possible response types (success and errors): + +```cpp +// Example: endpoint returns success (User) or errors (NotFound, ServerError) +using GetUserResponse = std::variant; + +GetUserResponse handleGetUser(const GetUserRequest& params) override { + if (userExists(params.m_userId)) { + User user = fetchUser(params.m_userId); + return user; // Automatically sets HTTP 200 + } else { + NotFound error; + error.setMessage("User not found"); + return error; // Automatically sets HTTP 404 + } +} +``` + +The server automatically: +- Detects which type is returned from the variant +- Sets the appropriate HTTP status code +- Serializes the response to JSON + +### HTTP Status Codes + +Status codes are automatically set based on the response type you return. Each model type is associated with a specific HTTP status code defined in your OpenAPI specification. + +**Optimized Status Code Constants:** +The generator only creates HTTP status code constants (e.g., `HTTP_RESPONSE_CODE_200`, `HTTP_RESPONSE_CODE_404`) for codes actually used by your API operations. This reduces code bloat and compilation time compared to generating all possible HTTP status codes. + +### Parameter Validation + +The generated code automatically validates: +- **Required parameters**: Returns HTTP 400 if missing +- **Type conversion**: Returns HTTP 400 if parameter cannot be converted to expected type +- **JSON parsing**: Returns HTTP 400 if request body is invalid JSON + +Custom validation logic should be implemented in your handler methods. + +### Working with Optional Parameters + +Optional parameters and model fields use `std::optional`: + +```cpp +void handleRequest(const RequestParams& params) override { + // Check if optional query parameter is present + if (params.m_optionalParam) { + auto value = *params.m_optionalParam; // Dereference to get value + // Use value... + } + + // Check if optional request body is present + if (params.m_request) { + auto body = *params.m_request; // Dereference to get body + // Use body... + } +} +``` + +## Advanced Features + +### Parameter Serialization Styles + +The generator supports various parameter serialization styles as defined in OpenAPI: + +- **simple**: Comma-separated values (default for path/header) +- **form**: Ampersand-separated values (default for query) +- **spaceDelimited**: Space-separated values +- **pipeDelimited**: Pipe-separated values +- **deepObject**: Nested object notation for query parameters + +These are automatically handled during parameter parsing. + +### Enum Handling + +All generated enums automatically include an `UNSPECIFIED` value as the first enum entry for safe initialization: + +```cpp +enum class Status { + UNSPECIFIED = 0, // Added automatically for safety + PENDING, + APPROVED, + REJECTED +}; + +// Safe default initialization +Status status; // Defaults to UNSPECIFIED (0) + +// Explicit initialization +Status activeStatus = Status::APPROVED; + +// Enum serialization/deserialization +// UNSPECIFIED is not a valid API value and indicates uninitialized state +``` + +**Why UNSPECIFIED?** +- Provides a safe default value for uninitialized enums +- Prevents undefined behavior from using uninitialized enum values +- Makes it clear when an enum hasn't been set vs. having a valid API value +- Does not appear in OpenAPI spec - internal C++ implementation detail + +### Union Types (anyOf/oneOf) + +When your OpenAPI spec uses `anyOf` or `oneOf`, the generated code uses `std::variant`: + +```cpp +// OpenAPI: { "anyOf": [{"type": "string"}, {"type": "number"}] } +using MyUnionType = std::variant; + +// In your model: +MyUnionType value; + +// Use std::visit to handle different types: +std::visit([](const auto& v) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + std::cout << "String: " << v << std::endl; + } else if constexpr (std::is_same_v) { + std::cout << "Number: " << v << std::endl; + } +}, value); +``` + +## Additional Resources + +- [cpp-httplib Documentation](https://github.com/yhirose/cpp-httplib) +- [nlohmann/json Documentation](https://github.com/nlohmann/json) +- [OpenAPI Generator Documentation](https://openapi-generator.tech/docs/generators/cpp-httplib-server) +- [OpenAPI Specification](https://swagger.io/specification/) + +- [cpp-httplib Documentation](https://github.com/yhirose/cpp-httplib) +- [nlohmann/json Documentation](https://github.com/nlohmann/json) +- [OpenAPI Generator Documentation](https://openapi-generator.tech/docs/generators/) diff --git a/samples/server/petstore/cpp-httplib-server/petstore/api/PetApi.cpp b/samples/server/petstore/cpp-httplib-server/petstore/api/PetApi.cpp new file mode 100644 index 000000000000..a5a6d0f967b0 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/api/PetApi.cpp @@ -0,0 +1,795 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +// System headers +#include +#include +#include + +// Project headers +#include "PetApi.h" + +constexpr int HTTP_RESPONSE_CODE_PET = 201; +constexpr int HTTP_RESPONSE_CODE_API_RESPONSE = 400; +constexpr int HTTP_RESPONSE_CODE_COMPLEX_PARAMS_RESPONSE = 200; +constexpr int HTTP_RESPONSE_CODE_NO_CONTENT = 204; +constexpr int HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR = 500; + +namespace api { + +using namespace models; + +bool Pet::parsePetPostParams(const httplib::Request& req, Pet::PetPostRequest& params, std::vector& paramErrors) +{ + std::vector errors; + if (!req.body.empty()) + { + try + { + nlohmann::json json = nlohmann::json::parse(req.body); + from_json(json, params.m_request); + } + catch (const std::exception& e) + { + errors.push_back("Invalid request body: " + std::string(e.what())); + } + } + else + { + errors.push_back("Missing required request body"); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Pet::handlePetPostResponse(const PetPostResponse& result, httplib::Response& res) +{ + std::visit([&](const auto& value) + { + using T = std::decay_t; + + // Success types + if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_PET; + nlohmann::json responseJson; + to_json(responseJson, value); + res.set_content(responseJson.dump(), "application/json"); + } + // Error types + else if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + nlohmann::json errorJson = value; + res.set_content(errorJson.dump(), "application/json"); + } + }, result); +} +bool Pet::parsePetcomplexGetParams(const httplib::Request& req, Pet::PetcomplexGetRequest& params, std::vector& paramErrors) +{ + std::vector errors; + + // Query Parameters - deepObj + if (req.has_param("deepObj")) + { + try + { + // Parse JSON object from query + auto val = req.get_param_value("deepObj", 0); + params.m_deepObj = nlohmann::json::parse(val).get(); + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter 'deepObj': " + std::string(e.what())); + } + } + // Query Parameters - enumParam + if (req.has_param("enumParam")) + { + try + { + params.m_enumParam = (req.get_param_value("enumParam")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter 'enumParam': " + std::string(e.what())); + } + } + // Query Parameters - pipeArr + if (req.has_param("pipeArr")) + { + try + { + // form/simple: multi-param or comma-separated + size_t count = req.get_param_value_count("pipeArr"); + if (!params.m_pipeArr.has_value()) + { + params.m_pipeArr = std::vector{}; + } + if (count > 1) + { + for (size_t i = 0; i < count; ++i) + { + auto val = req.get_param_value("pipeArr", i); + + params.m_pipeArr->emplace_back(val); + + } + } + else if (count == 1) + { + auto val = req.get_param_value("pipeArr", 0); + std::stringstream ss(val); + std::string item; + while (std::getline(ss, item, ',')) + { + if (!item.empty()) + { + + params.m_pipeArr->emplace_back(item); + + } + } + } + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter 'pipeArr': " + std::string(e.what())); + } + } + // Query Parameters - spaceArr + if (req.has_param("spaceArr")) + { + try + { + // form/simple: multi-param or comma-separated + size_t count = req.get_param_value_count("spaceArr"); + if (!params.m_spaceArr.has_value()) + { + params.m_spaceArr = std::vector{}; + } + if (count > 1) + { + for (size_t i = 0; i < count; ++i) + { + auto val = req.get_param_value("spaceArr", i); + params.m_spaceArr->emplace_back(std::stoi(val)); + + } + } + else if (count == 1) + { + auto val = req.get_param_value("spaceArr", 0); + std::stringstream ss(val); + std::string item; + while (std::getline(ss, item, ',')) + { + if (!item.empty()) + { + params.m_spaceArr->emplace_back(std::stoi(item)); + + } + } + } + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter 'spaceArr': " + std::string(e.what())); + } + } + + // Header Parameters - x-enum-header + if (!req.get_header_value("x-enum-header").empty()) + { + try + { + params.m_xEnumHeader = (req.get_header_value("x-enum-header")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid header parameter 'x-enum-header': " + std::string(e.what())); + } + } + + // Cookie Parameters - cookieEnum + try + { + auto cookieHeader = req.get_header_value("Cookie"); + if (!cookieHeader.empty()) + { + std::string cookieValue; + std::string key = "cookieEnum="; + size_t start = cookieHeader.find(key); + if (start != std::string::npos) + { + start += key.length(); + size_t end = cookieHeader.find(";", start); + if (end == std::string::npos) end = cookieHeader.length(); + cookieValue = cookieHeader.substr(start, end - start); + params.m_cookieEnum = (cookieValue); + } + } + } + catch (const std::exception& e) + { + errors.push_back("Invalid cookie parameter 'cookieEnum': " + std::string(e.what())); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Pet::handlePetcomplexGetResponse(const PetcomplexGetResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_COMPLEX_PARAMS_RESPONSE; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} +bool Pet::parsePetpetIdDeleteParams(const httplib::Request& req, Pet::PetpetIdDeleteRequest& params, std::vector& paramErrors) +{ + std::vector errors; + + // Query Parameters - api_key + if (req.has_param("api_key")) + { + params.m_apiKey = req.get_param_value("api_key"); + } + else + { + // Use default value for optional parameter + params.m_apiKey = ""; + } + + // Path Parameters - petId (index: 1) + if (req.matches.size() < 1 + 1) + { + errors.push_back("Missing path parameter 'petId'"); + } + else + { + try + { + params.m_petId = std::stoll(req.matches[1]); + } + catch (const std::exception& e) + { + errors.push_back("Invalid path parameter 'petId': " + std::string(e.what())); + } + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +bool Pet::parsePetfindByStatusGetParams(const httplib::Request& req, Pet::PetfindByStatusGetRequest& params, std::vector& paramErrors) +{ + std::vector errors; + + // Query Parameters - status + if (req.has_param("status")) + { + try + { + params.m_status = (req.get_param_value("status")); + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter 'status': " + std::string(e.what())); + } + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Pet::handlePetfindByStatusGetResponse(const PetfindByStatusGetResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_PET; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} +bool Pet::parsePetfindByTagsGetParams(const httplib::Request& req, Pet::PetfindByTagsGetRequest& params, std::vector& paramErrors) +{ + std::vector errors; + + // Query Parameters - tags + if (req.has_param("tags")) + { + try + { + // form/simple: multi-param or comma-separated + size_t count = req.get_param_value_count("tags"); + if (count > 1) + { + for (size_t i = 0; i < count; ++i) + { + auto val = req.get_param_value("tags", i); + + params.m_tags.emplace_back(val); + + } + } + else if (count == 1) + { + auto val = req.get_param_value("tags", 0); + std::stringstream ss(val); + std::string item; + while (std::getline(ss, item, ',')) + { + if (!item.empty()) + { + + params.m_tags.emplace_back(item); + + } + } + } + } + catch (const std::exception& e) + { + errors.push_back("Invalid query parameter 'tags': " + std::string(e.what())); + } + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Pet::handlePetfindByTagsGetResponse(const PetfindByTagsGetResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_PET; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} +bool Pet::parsePetpetIdGetParams(const httplib::Request& req, Pet::PetpetIdGetRequest& params, std::vector& paramErrors) +{ + std::vector errors; + + // Header Parameters - customHeader + if (!req.get_header_value("customHeader").empty()) + { + params.m_customHeader = req.get_header_value("customHeader"); + } + else + { + // Use default value for optional parameter + params.m_customHeader = ""; + } + + // Path Parameters - petId (index: 1) + if (req.matches.size() < 1 + 1) + { + errors.push_back("Missing path parameter 'petId'"); + } + else + { + try + { + params.m_petId = std::stoll(req.matches[1]); + } + catch (const std::exception& e) + { + errors.push_back("Invalid path parameter 'petId': " + std::string(e.what())); + } + } + + // Cookie Parameters - cookieParam + try + { + auto cookieHeader = req.get_header_value("Cookie"); + if (!cookieHeader.empty()) + { + std::string cookieValue; + std::string key = "cookieParam="; + size_t start = cookieHeader.find(key); + if (start != std::string::npos) + { + start += key.length(); + size_t end = cookieHeader.find(";", start); + if (end == std::string::npos) end = cookieHeader.length(); + cookieValue = cookieHeader.substr(start, end - start); + params.m_cookieParam = cookieValue; + } + else + { + // Use default value for optional parameter + params.m_cookieParam = ""; + } + } + else + { + // Use default value for optional parameter + params.m_cookieParam = ""; + } + } + catch (const std::exception& e) + { + errors.push_back("Invalid cookie parameter 'cookieParam': " + std::string(e.what())); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Pet::handlePetpetIdGetResponse(const PetpetIdGetResponse& result, httplib::Response& res) +{ + std::visit([&](const auto& value) + { + using T = std::decay_t; + + // Success types + if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_PET; + nlohmann::json responseJson; + to_json(responseJson, value); + res.set_content(responseJson.dump(), "application/json"); + } + // Error types + else if constexpr (std::is_same_v) + { + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + nlohmann::json errorJson = value; + res.set_content(errorJson.dump(), "application/json"); + } + }, result); +} +bool Pet::parsePetPutParams(const httplib::Request& req, Pet::PetPutRequest& params, std::vector& paramErrors) +{ + std::vector errors; + if (!req.body.empty()) + { + try + { + nlohmann::json json = nlohmann::json::parse(req.body); + from_json(json, params.m_request); + } + catch (const std::exception& e) + { + errors.push_back("Invalid request body: " + std::string(e.what())); + } + } + else + { + errors.push_back("Missing required request body"); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} + + +void Pet::handlePetPostRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + PetPostRequest params; + std::vector paramErrors; + if (!parsePetPostParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handlePostForPet(params); + handlePetPostResponse(result, res); + + } + catch (const nlohmann::json::parse_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::invalid_iterator& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::type_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::other_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Pet::handlePetcomplexGetRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + PetcomplexGetRequest params; + std::vector paramErrors; + if (!parsePetcomplexGetParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handleGetForPetcomplex(params); + handlePetcomplexGetResponse(result, res); + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Pet::handlePetpetIdDeleteRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + PetpetIdDeleteRequest params; + std::vector paramErrors; + if (!parsePetpetIdDeleteParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + return; + } + + handleDeleteForPetpetId(params); + res.status = HTTP_RESPONSE_CODE_NO_CONTENT; + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Pet::handlePetfindByStatusGetRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + PetfindByStatusGetRequest params; + std::vector paramErrors; + if (!parsePetfindByStatusGetParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handleGetForPetfindByStatus(params); + handlePetfindByStatusGetResponse(result, res); + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Pet::handlePetfindByTagsGetRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + PetfindByTagsGetRequest params; + std::vector paramErrors; + if (!parsePetfindByTagsGetParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handleGetForPetfindByTags(params); + handlePetfindByTagsGetResponse(result, res); + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Pet::handlePetpetIdGetRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + PetpetIdGetRequest params; + std::vector paramErrors; + if (!parsePetpetIdGetParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handleGetForPetpetId(params); + handlePetpetIdGetResponse(result, res); + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Pet::handlePetPutRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + PetPutRequest params; + std::vector paramErrors; + if (!parsePetPutParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + return; + } + + handlePutForPet(params); + res.status = HTTP_RESPONSE_CODE_NO_CONTENT; + + } + catch (const nlohmann::json::parse_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::invalid_iterator& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::type_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::other_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_API_RESPONSE; + res.set_content(errorJson.dump(), "application/json"); + } +} + + +void Pet::registerRoutes(httplib::Server& svr) +{ + svr.Post("/pet", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handlePetPostRequest(req, res); + }); + svr.Get("/pet/complex", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handlePetcomplexGetRequest(req, res); + }); + svr.Delete("/pet/{petId}", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handlePetpetIdDeleteRequest(req, res); + }); + svr.Get("/pet/findByStatus", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handlePetfindByStatusGetRequest(req, res); + }); + svr.Get("/pet/findByTags", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handlePetfindByTagsGetRequest(req, res); + }); + svr.Get("/pet/{petId}", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handlePetpetIdGetRequest(req, res); + }); + svr.Put("/pet", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handlePetPutRequest(req, res); + }); +} + +} // namespace api \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/petstore/api/PetApi.h b/samples/server/petstore/cpp-httplib-server/petstore/api/PetApi.h new file mode 100644 index 000000000000..8ce89bf21eeb --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/api/PetApi.h @@ -0,0 +1,203 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once + +// System headers +#include +#include +#include + +// Project headers +#include "models/ApiResponse.h" +#include "models/ComplexParamsResponse.h" +#include "models/DeepObj.h" +#include "models/Pet.h" + +namespace api { +class Pet { +public: + Pet() = default; + virtual ~Pet() = default; + /** + * @brief Register all routes for this API + * @param svr The httplib::Server instance to register routes on + */ + void registerRoutes(httplib::Server& svr); + // ========================= + // ===== Request types ===== + // ========================= + + /** + * @brief Request type for handlePostForPet. + */ + struct PetPostRequest + { + models::Pet m_request; //Request Body (required) + }; + + /** + * @brief Request type for handleGetForPetcomplex. + */ + struct PetcomplexGetRequest + { + + std::optional m_deepObj; //Query Params (optional) + std::optional m_enumParam; //Query Params (optional) + std::optional> m_pipeArr; //Query Params (optional) + std::optional> m_spaceArr; //Query Params (optional) + std::optional m_xEnumHeader; //HeaderParams (optional) + std::optional m_cookieEnum; //Cookies (optional) + }; + + /** + * @brief Request type for handleDeleteForPetpetId. + */ + struct PetpetIdDeleteRequest + { + + std::optional m_apiKey; //Query Params (optional) + long m_petId; //PathParams (always required) + }; + + /** + * @brief Request type for handleGetForPetfindByStatus. + */ + struct PetfindByStatusGetRequest + { + + std::string m_status; //Query Params (required) + }; + + /** + * @brief Request type for handleGetForPetfindByTags. + */ + struct PetfindByTagsGetRequest + { + + std::vector m_tags; //Query Params (required) + }; + + /** + * @brief Request type for handleGetForPetpetId. + */ + struct PetpetIdGetRequest + { + + std::optional m_customHeader; //HeaderParams (optional) + long m_petId; //PathParams (always required) + std::optional m_cookieParam; //Cookies (optional) + }; + + /** + * @brief Request type for handlePutForPet. + */ + struct PetPutRequest + { + models::Pet m_request; //Request Body (required) + }; + + // ========================== + // ===== Response types ===== + // ========================== + + /** + * @brief Response type for handlePostForPet. + */ + using PetPostResponse = std::variant< + models::Pet , + models::ApiResponse >; + + /** + * @brief Response type for handleGetForPetcomplex. + */ + using PetcomplexGetResponse = models::ComplexParamsResponse; + + /** + * @brief Response type for handleGetForPetfindByStatus. + */ + using PetfindByStatusGetResponse = models::Pet; + + /** + * @brief Response type for handleGetForPetfindByTags. + */ + using PetfindByTagsGetResponse = models::Pet; + + /** + * @brief Response type for handleGetForPetpetId. + */ + using PetpetIdGetResponse = std::variant< + models::Pet , + models::ApiResponse >; + // ============================================================ + // ===== Pure virtual functions to be handled by the user ===== + // ============================================================ + /** + * PetPostRequest - struct containing all the query parameters and headers and schemas as available. + * @return PetPostResponse The response type returned by the handler. + */ + virtual PetPostResponse handlePostForPet(const PetPostRequest& params)=0; + + /** + * PetcomplexGetRequest - struct containing all the query parameters and headers and schemas as available. + * @return PetcomplexGetResponse The response type returned by the handler. + */ + virtual PetcomplexGetResponse handleGetForPetcomplex(const PetcomplexGetRequest& params)=0; + + /** + * PetpetIdDeleteRequest - struct containing all the query parameters and headers and schemas as available. + */ + virtual void handleDeleteForPetpetId(const PetpetIdDeleteRequest& params)=0; + + /** + * PetfindByStatusGetRequest - struct containing all the query parameters and headers and schemas as available. + * @return PetfindByStatusGetResponse The response type returned by the handler. + */ + virtual PetfindByStatusGetResponse handleGetForPetfindByStatus(const PetfindByStatusGetRequest& params)=0; + + /** + * PetfindByTagsGetRequest - struct containing all the query parameters and headers and schemas as available. + * @return PetfindByTagsGetResponse The response type returned by the handler. + */ + virtual PetfindByTagsGetResponse handleGetForPetfindByTags(const PetfindByTagsGetRequest& params)=0; + + /** + * PetpetIdGetRequest - struct containing all the query parameters and headers and schemas as available. + * @return PetpetIdGetResponse The response type returned by the handler. + */ + virtual PetpetIdGetResponse handleGetForPetpetId(const PetpetIdGetRequest& params)=0; + + /** + * PetPutRequest - struct containing all the query parameters and headers and schemas as available. + */ + virtual void handlePutForPet(const PetPutRequest& params)=0; + +private: + // ======================================== + // ===== Helper function declarations ===== + // ======================================== + static bool parsePetPostParams(const httplib::Request& req, PetPostRequest& params, std::vector& paramErrors); + void handlePetPostRequest(const httplib::Request& req, httplib::Response& res); + static void handlePetPostResponse(const PetPostResponse& result, httplib::Response& res); + static bool parsePetcomplexGetParams(const httplib::Request& req, PetcomplexGetRequest& params, std::vector& paramErrors); + void handlePetcomplexGetRequest(const httplib::Request& req, httplib::Response& res); + static void handlePetcomplexGetResponse(const PetcomplexGetResponse& result, httplib::Response& res); + static bool parsePetpetIdDeleteParams(const httplib::Request& req, PetpetIdDeleteRequest& params, std::vector& paramErrors); + void handlePetpetIdDeleteRequest(const httplib::Request& req, httplib::Response& res); + static bool parsePetfindByStatusGetParams(const httplib::Request& req, PetfindByStatusGetRequest& params, std::vector& paramErrors); + void handlePetfindByStatusGetRequest(const httplib::Request& req, httplib::Response& res); + static void handlePetfindByStatusGetResponse(const PetfindByStatusGetResponse& result, httplib::Response& res); + static bool parsePetfindByTagsGetParams(const httplib::Request& req, PetfindByTagsGetRequest& params, std::vector& paramErrors); + void handlePetfindByTagsGetRequest(const httplib::Request& req, httplib::Response& res); + static void handlePetfindByTagsGetResponse(const PetfindByTagsGetResponse& result, httplib::Response& res); + static bool parsePetpetIdGetParams(const httplib::Request& req, PetpetIdGetRequest& params, std::vector& paramErrors); + void handlePetpetIdGetRequest(const httplib::Request& req, httplib::Response& res); + static void handlePetpetIdGetResponse(const PetpetIdGetResponse& result, httplib::Response& res); + static bool parsePetPutParams(const httplib::Request& req, PetPutRequest& params, std::vector& paramErrors); + void handlePetPutRequest(const httplib::Request& req, httplib::Response& res); +}; + +} // namespace api \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/petstore/api/StoreApi.cpp b/samples/server/petstore/cpp-httplib-server/petstore/api/StoreApi.cpp new file mode 100644 index 000000000000..8798d4c4155c --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/api/StoreApi.cpp @@ -0,0 +1,261 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +// System headers +#include +#include +#include + +// Project headers +#include "StoreApi.h" + +constexpr int HTTP_RESPONSE_CODE_ORDER = 200; +constexpr int HTTP_RESPONSE_CODE_NO_CONTENT = 204; +constexpr int HTTP_RESPONSE_CODE_BAD_REQUEST = 400; +constexpr int HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR = 500; + +namespace api { + +using namespace models; + +bool Store::parseStoreorderorderIdDeleteParams(const httplib::Request& req, Store::StoreorderorderIdDeleteRequest& params, std::vector& paramErrors) +{ + std::vector errors; + + // Path Parameters - orderId (index: 1) + if (req.matches.size() < 1 + 1) + { + errors.push_back("Missing path parameter 'orderId'"); + } + else + { + try + { + params.m_orderId = std::stoll(req.matches[1]); + } + catch (const std::exception& e) + { + errors.push_back("Invalid path parameter 'orderId': " + std::string(e.what())); + } + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +bool Store::parseStoreorderorderIdGetParams(const httplib::Request& req, Store::StoreorderorderIdGetRequest& params, std::vector& paramErrors) +{ + std::vector errors; + + // Path Parameters - orderId (index: 1) + if (req.matches.size() < 1 + 1) + { + errors.push_back("Missing path parameter 'orderId'"); + } + else + { + try + { + params.m_orderId = std::stoll(req.matches[1]); + } + catch (const std::exception& e) + { + errors.push_back("Invalid path parameter 'orderId': " + std::string(e.what())); + } + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Store::handleStoreorderorderIdGetResponse(const StoreorderorderIdGetResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_ORDER; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} +bool Store::parseStoreorderPostParams(const httplib::Request& req, Store::StoreorderPostRequest& params, std::vector& paramErrors) +{ + std::vector errors; + if (!req.body.empty()) + { + try + { + nlohmann::json json = nlohmann::json::parse(req.body); + from_json(json, params.m_request); + } + catch (const std::exception& e) + { + errors.push_back("Invalid request body: " + std::string(e.what())); + } + } + else + { + errors.push_back("Missing required request body"); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void Store::handleStoreorderPostResponse(const StoreorderPostResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_ORDER; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} + + +void Store::handleStoreorderorderIdDeleteRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + StoreorderorderIdDeleteRequest params; + std::vector paramErrors; + if (!parseStoreorderorderIdDeleteParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + + handleDeleteForStoreorderorderId(params); + res.status = HTTP_RESPONSE_CODE_NO_CONTENT; + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Store::handleStoreorderorderIdGetRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + StoreorderorderIdGetRequest params; + std::vector paramErrors; + if (!parseStoreorderorderIdGetParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handleGetForStoreorderorderId(params); + handleStoreorderorderIdGetResponse(result, res); + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void Store::handleStoreorderPostRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + StoreorderPostRequest params; + std::vector paramErrors; + if (!parseStoreorderPostParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handlePostForStoreorder(params); + handleStoreorderPostResponse(result, res); + + } + catch (const nlohmann::json::parse_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::invalid_iterator& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::type_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::other_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } +} + + +void Store::registerRoutes(httplib::Server& svr) +{ + svr.Delete("/store/order/{orderId}", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleStoreorderorderIdDeleteRequest(req, res); + }); + svr.Get("/store/order/{orderId}", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleStoreorderorderIdGetRequest(req, res); + }); + svr.Post("/store/order", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleStoreorderPostRequest(req, res); + }); +} + +} // namespace api \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/petstore/api/StoreApi.h b/samples/server/petstore/cpp-httplib-server/petstore/api/StoreApi.h new file mode 100644 index 000000000000..a36bf52b2706 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/api/StoreApi.h @@ -0,0 +1,101 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once + +// System headers +#include +#include +#include + +// Project headers +#include "models/Order.h" + +namespace api { +class Store { +public: + Store() = default; + virtual ~Store() = default; + /** + * @brief Register all routes for this API + * @param svr The httplib::Server instance to register routes on + */ + void registerRoutes(httplib::Server& svr); + // ========================= + // ===== Request types ===== + // ========================= + + /** + * @brief Request type for handleDeleteForStoreorderorderId. + */ + struct StoreorderorderIdDeleteRequest + { + + long m_orderId; //PathParams (always required) + }; + + /** + * @brief Request type for handleGetForStoreorderorderId. + */ + struct StoreorderorderIdGetRequest + { + + long m_orderId; //PathParams (always required) + }; + + /** + * @brief Request type for handlePostForStoreorder. + */ + struct StoreorderPostRequest + { + models::Order m_request; //Request Body (required) + }; + + + /** + * @brief Response type for handleGetForStoreorderorderId. + */ + using StoreorderorderIdGetResponse = models::Order; + + /** + * @brief Response type for handlePostForStoreorder. + */ + using StoreorderPostResponse = models::Order; + // ============================================================ + // ===== Pure virtual functions to be handled by the user ===== + // ============================================================ + /** + * StoreorderorderIdDeleteRequest - struct containing all the query parameters and headers and schemas as available. + */ + virtual void handleDeleteForStoreorderorderId(const StoreorderorderIdDeleteRequest& params)=0; + + /** + * StoreorderorderIdGetRequest - struct containing all the query parameters and headers and schemas as available. + * @return StoreorderorderIdGetResponse The response type returned by the handler. + */ + virtual StoreorderorderIdGetResponse handleGetForStoreorderorderId(const StoreorderorderIdGetRequest& params)=0; + + /** + * StoreorderPostRequest - struct containing all the query parameters and headers and schemas as available. + * @return StoreorderPostResponse The response type returned by the handler. + */ + virtual StoreorderPostResponse handlePostForStoreorder(const StoreorderPostRequest& params)=0; + +private: + // ======================================== + // ===== Helper function declarations ===== + // ======================================== + static bool parseStoreorderorderIdDeleteParams(const httplib::Request& req, StoreorderorderIdDeleteRequest& params, std::vector& paramErrors); + void handleStoreorderorderIdDeleteRequest(const httplib::Request& req, httplib::Response& res); + static bool parseStoreorderorderIdGetParams(const httplib::Request& req, StoreorderorderIdGetRequest& params, std::vector& paramErrors); + void handleStoreorderorderIdGetRequest(const httplib::Request& req, httplib::Response& res); + static void handleStoreorderorderIdGetResponse(const StoreorderorderIdGetResponse& result, httplib::Response& res); + static bool parseStoreorderPostParams(const httplib::Request& req, StoreorderPostRequest& params, std::vector& paramErrors); + void handleStoreorderPostRequest(const httplib::Request& req, httplib::Response& res); + static void handleStoreorderPostResponse(const StoreorderPostResponse& result, httplib::Response& res); +}; + +} // namespace api \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/petstore/api/UserApi.cpp b/samples/server/petstore/cpp-httplib-server/petstore/api/UserApi.cpp new file mode 100644 index 000000000000..55faa4732883 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/api/UserApi.cpp @@ -0,0 +1,368 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +// System headers +#include +#include +#include + +// Project headers +#include "UserApi.h" + +constexpr int HTTP_RESPONSE_CODE_USER = 200; +constexpr int HTTP_RESPONSE_CODE_NO_CONTENT = 204; +constexpr int HTTP_RESPONSE_CODE_BAD_REQUEST = 400; +constexpr int HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR = 500; + +namespace api { + +using namespace models; + +bool User::parseUserPostParams(const httplib::Request& req, User::UserPostRequest& params, std::vector& paramErrors) +{ + std::vector errors; + if (!req.body.empty()) + { + try + { + nlohmann::json json = nlohmann::json::parse(req.body); + from_json(json, params.m_request); + } + catch (const std::exception& e) + { + errors.push_back("Invalid request body: " + std::string(e.what())); + } + } + else + { + errors.push_back("Missing required request body"); + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void User::handleUserPostResponse(const UserPostResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_USER; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} +bool User::parseUserusernameDeleteParams(const httplib::Request& req, User::UserusernameDeleteRequest& params, std::vector& paramErrors) +{ + std::vector errors; + + // Path Parameters - username (index: 1) + if (req.matches.size() < 1 + 1) + { + errors.push_back("Missing path parameter 'username'"); + } + else + { + try + { + params.m_username = req.matches[1]; + } + catch (const std::exception& e) + { + errors.push_back("Invalid path parameter 'username': " + std::string(e.what())); + } + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +bool User::parseUserusernameGetParams(const httplib::Request& req, User::UserusernameGetRequest& params, std::vector& paramErrors) +{ + std::vector errors; + + // Path Parameters - username (index: 1) + if (req.matches.size() < 1 + 1) + { + errors.push_back("Missing path parameter 'username'"); + } + else + { + try + { + params.m_username = req.matches[1]; + } + catch (const std::exception& e) + { + errors.push_back("Invalid path parameter 'username': " + std::string(e.what())); + } + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} +void User::handleUserusernameGetResponse(const UserusernameGetResponse& result, httplib::Response& res) +{ + // Single response type + res.status = HTTP_RESPONSE_CODE_USER; + nlohmann::json responseJson; + to_json(responseJson, result); + res.set_content(responseJson.dump(), "application/json"); +} +bool User::parseUserusernamePutParams(const httplib::Request& req, User::UserusernamePutRequest& params, std::vector& paramErrors) +{ + std::vector errors; + if (!req.body.empty()) + { + try + { + nlohmann::json json = nlohmann::json::parse(req.body); + from_json(json, params.m_request); + } + catch (const std::exception& e) + { + errors.push_back("Invalid request body: " + std::string(e.what())); + } + } + else + { + errors.push_back("Missing required request body"); + } + + // Path Parameters - username (index: 1) + if (req.matches.size() < 1 + 1) + { + errors.push_back("Missing path parameter 'username'"); + } + else + { + try + { + params.m_username = req.matches[1]; + } + catch (const std::exception& e) + { + errors.push_back("Invalid path parameter 'username': " + std::string(e.what())); + } + } + + // Return errors via out-parameter, return false if any errors + if (!errors.empty()) + { + paramErrors = std::move(errors); + return false; + } + return true; +} + + +void User::handleUserPostRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + UserPostRequest params; + std::vector paramErrors; + if (!parseUserPostParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handlePostForUser(params); + handleUserPostResponse(result, res); + + } + catch (const nlohmann::json::parse_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::invalid_iterator& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::type_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::other_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void User::handleUserusernameDeleteRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + UserusernameDeleteRequest params; + std::vector paramErrors; + if (!parseUserusernameDeleteParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + + handleDeleteForUserusername(params); + res.status = HTTP_RESPONSE_CODE_NO_CONTENT; + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void User::handleUserusernameGetRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + UserusernameGetRequest params; + std::vector paramErrors; + if (!parseUserusernameGetParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + auto result = handleGetForUserusername(params); + handleUserusernameGetResponse(result, res); + + } + catch (const std::exception& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Internal error: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR; + res.set_content(errorJson.dump(), "application/json"); + } +} + +void User::handleUserusernamePutRequest([[maybe_unused]] const httplib::Request& req, httplib::Response& res) +{ + try + { + + UserusernamePutRequest params; + std::vector paramErrors; + if (!parseUserusernamePutParams(req, params, paramErrors)) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid parameters"; + errorJson["errors"] = paramErrors; + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + return; + } + + handlePutForUserusername(params); + res.status = HTTP_RESPONSE_CODE_NO_CONTENT; + + } + catch (const nlohmann::json::parse_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::invalid_iterator& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::type_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::out_of_range& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } + catch (const nlohmann::json::other_error& e) + { + nlohmann::json errorJson = nlohmann::json::object(); + errorJson["message"] = "Invalid JSON: " + std::string(e.what()); + res.status = HTTP_RESPONSE_CODE_BAD_REQUEST; + res.set_content(errorJson.dump(), "application/json"); + } +} + + +void User::registerRoutes(httplib::Server& svr) +{ + svr.Post("/user", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleUserPostRequest(req, res); + }); + svr.Delete("/user/{username}", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleUserusernameDeleteRequest(req, res); + }); + svr.Get("/user/{username}", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleUserusernameGetRequest(req, res); + }); + svr.Put("/user/{username}", [this]([[maybe_unused]] const httplib::Request& req, httplib::Response& res) + { + handleUserusernamePutRequest(req, res); + }); +} + +} // namespace api \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/petstore/api/UserApi.h b/samples/server/petstore/cpp-httplib-server/petstore/api/UserApi.h new file mode 100644 index 000000000000..439afef2741d --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/api/UserApi.h @@ -0,0 +1,120 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once + +// System headers +#include +#include +#include + +// Project headers +#include "models/User.h" + +namespace api { +class User { +public: + User() = default; + virtual ~User() = default; + /** + * @brief Register all routes for this API + * @param svr The httplib::Server instance to register routes on + */ + void registerRoutes(httplib::Server& svr); + // ========================= + // ===== Request types ===== + // ========================= + + /** + * @brief Request type for handlePostForUser. + */ + struct UserPostRequest + { + models::User m_request; //Request Body (required) + }; + + /** + * @brief Request type for handleDeleteForUserusername. + */ + struct UserusernameDeleteRequest + { + + std::string m_username; //PathParams (always required) + }; + + /** + * @brief Request type for handleGetForUserusername. + */ + struct UserusernameGetRequest + { + + std::string m_username; //PathParams (always required) + }; + + /** + * @brief Request type for handlePutForUserusername. + */ + struct UserusernamePutRequest + { + models::User m_request; //Request Body (required) + std::string m_username; //PathParams (always required) + }; + + // ========================== + // ===== Response types ===== + // ========================== + + /** + * @brief Response type for handlePostForUser. + */ + using UserPostResponse = models::User; + + /** + * @brief Response type for handleGetForUserusername. + */ + using UserusernameGetResponse = models::User; + // ============================================================ + // ===== Pure virtual functions to be handled by the user ===== + // ============================================================ + /** + * UserPostRequest - struct containing all the query parameters and headers and schemas as available. + * @return UserPostResponse The response type returned by the handler. + */ + virtual UserPostResponse handlePostForUser(const UserPostRequest& params)=0; + + /** + * UserusernameDeleteRequest - struct containing all the query parameters and headers and schemas as available. + */ + virtual void handleDeleteForUserusername(const UserusernameDeleteRequest& params)=0; + + /** + * UserusernameGetRequest - struct containing all the query parameters and headers and schemas as available. + * @return UserusernameGetResponse The response type returned by the handler. + */ + virtual UserusernameGetResponse handleGetForUserusername(const UserusernameGetRequest& params)=0; + + /** + * UserusernamePutRequest - struct containing all the query parameters and headers and schemas as available. + */ + virtual void handlePutForUserusername(const UserusernamePutRequest& params)=0; + +private: + // ======================================== + // ===== Helper function declarations ===== + // ======================================== + static bool parseUserPostParams(const httplib::Request& req, UserPostRequest& params, std::vector& paramErrors); + void handleUserPostRequest(const httplib::Request& req, httplib::Response& res); + static void handleUserPostResponse(const UserPostResponse& result, httplib::Response& res); + static bool parseUserusernameDeleteParams(const httplib::Request& req, UserusernameDeleteRequest& params, std::vector& paramErrors); + void handleUserusernameDeleteRequest(const httplib::Request& req, httplib::Response& res); + static bool parseUserusernameGetParams(const httplib::Request& req, UserusernameGetRequest& params, std::vector& paramErrors); + void handleUserusernameGetRequest(const httplib::Request& req, httplib::Response& res); + static void handleUserusernameGetResponse(const UserusernameGetResponse& result, httplib::Response& res); + static bool parseUserusernamePutParams(const httplib::Request& req, UserusernamePutRequest& params, std::vector& paramErrors); + void handleUserusernamePutRequest(const httplib::Request& req, httplib::Response& res); +}; + +} // namespace api \ No newline at end of file diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/ApiResponse.cpp b/samples/server/petstore/cpp-httplib-server/petstore/models/ApiResponse.cpp new file mode 100644 index 000000000000..9e2ce953e548 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/ApiResponse.cpp @@ -0,0 +1,58 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "ApiResponse.h" + +namespace models { + +ApiResponse::ApiResponse() +: code(0) +, type("") +, message("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +int ApiResponse::getCode() const +{ + return code; +} +std::string ApiResponse::getType() const +{ + return type; +} +std::string ApiResponse::getMessage() const +{ + return message; +} + +// =================== +// ===== Setters ===== +// =================== +void ApiResponse::setCode(const int& codeObj) +{ + code = codeObj; +} +void ApiResponse::setType(const std::string& typeObj) +{ + type = typeObj; +} +void ApiResponse::setMessage(const std::string& messageObj) +{ + message = messageObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/ApiResponse.h b/samples/server/petstore/cpp-httplib-server/petstore/models/ApiResponse.h new file mode 100644 index 000000000000..3cb5f3ed9df6 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/ApiResponse.h @@ -0,0 +1,46 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include + + + +namespace models { + + +class ApiResponse +{ +public: + + ApiResponse(); + virtual ~ApiResponse() = default; + + // Getters and setters + [[nodiscard]] int getCode() const; + void setCode(const int& code); + [[nodiscard]] std::string getType() const; + void setType(const std::string& type); + [[nodiscard]] std::string getMessage() const; + void setMessage(const std::string& message); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(ApiResponse, + code, type, message) + +private: + int code; + std::string type; + std::string message; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/Category.cpp b/samples/server/petstore/cpp-httplib-server/petstore/models/Category.cpp new file mode 100644 index 000000000000..806dc9beaffc --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/Category.cpp @@ -0,0 +1,49 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "Category.h" + +namespace models { + +Category::Category() +: id(0) +, name("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +long Category::getId() const +{ + return id; +} +std::string Category::getName() const +{ + return name; +} + +// =================== +// ===== Setters ===== +// =================== +void Category::setId(const long& idObj) +{ + id = idObj; +} +void Category::setName(const std::string& nameObj) +{ + name = nameObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/Category.h b/samples/server/petstore/cpp-httplib-server/petstore/models/Category.h new file mode 100644 index 000000000000..432674c5607b --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/Category.h @@ -0,0 +1,42 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class Category +{ +public: + + Category(); + virtual ~Category() = default; + + // Getters and setters + [[nodiscard]] long getId() const; + void setId(const long& id); + [[nodiscard]] std::string getName() const; + void setName(const std::string& name); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(Category, + id, name) + +private: + long id; + std::string name; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/ComplexParamsResponse.cpp b/samples/server/petstore/cpp-httplib-server/petstore/models/ComplexParamsResponse.cpp new file mode 100644 index 000000000000..23ab70c5a1ee --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/ComplexParamsResponse.cpp @@ -0,0 +1,188 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "ComplexParamsResponse.h" + +namespace models { + +ComplexParamsResponse::ComplexParamsResponse() +: deepObj(DeepObj()) +, enumParam(std::nullopt) +, pipeArr(std::vector()) +, spaceArr(std::vector()) +, xEnumHeader(std::nullopt) +, cookieEnum(std::nullopt) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +DeepObj ComplexParamsResponse::getDeepObj() const +{ + return deepObj; +} +std::optional ComplexParamsResponse::getEnumParam() const +{ + return enumParam; +} +std::vector ComplexParamsResponse::getPipeArr() const +{ + return pipeArr; +} +std::vector ComplexParamsResponse::getSpaceArr() const +{ + return spaceArr; +} +std::optional ComplexParamsResponse::getXEnumHeader() const +{ + return xEnumHeader; +} +std::optional ComplexParamsResponse::getCookieEnum() const +{ + return cookieEnum; +} + +// =================== +// ===== Setters ===== +// =================== +void ComplexParamsResponse::setDeepObj(const DeepObj& deepObjObj) +{ + deepObj = deepObjObj; +} +void ComplexParamsResponse::setEnumParam(const std::optional& enumParamObj) +{ + enumParam = enumParamObj; +} +void ComplexParamsResponse::setPipeArr(const std::vector& pipeArrObj) +{ + pipeArr = pipeArrObj; +} +void ComplexParamsResponse::setSpaceArr(const std::vector& spaceArrObj) +{ + spaceArr = spaceArrObj; +} +void ComplexParamsResponse::setXEnumHeader(const std::optional& xEnumHeaderObj) +{ + xEnumHeader = xEnumHeaderObj; +} +void ComplexParamsResponse::setCookieEnum(const std::optional& cookieEnumObj) +{ + cookieEnum = cookieEnumObj; +} + + +// ========================================= +// ===== Enum EnumParamEnum Conversions ===== +// ========================================= +std::string ComplexParamsResponse::EnumParamEnumToString(ComplexParamsResponse::EnumParamEnum value) +{ + switch (value) + { + case EnumParamEnum::UNSPECIFIED: return "UNSPECIFIED"; + case EnumParamEnum::A: return "A"; + case EnumParamEnum::B: return "B"; + case EnumParamEnum::C: return "C"; + default: return {}; + } +} + +ComplexParamsResponse::EnumParamEnum ComplexParamsResponse::EnumParamEnumFromString(const std::string& str) +{ + if (str == "UNSPECIFIED") + { + return EnumParamEnum::UNSPECIFIED; + } + if (str == "A") + { + return EnumParamEnum::A; + } + if (str == "B") + { + return EnumParamEnum::B; + } + if (str == "C") + { + return EnumParamEnum::C; + } + throw std::invalid_argument("Invalid enum value"); +} + +// ========================================= +// ===== Enum XEnumHeaderEnum Conversions ===== +// ========================================= +std::string ComplexParamsResponse::XEnumHeaderEnumToString(ComplexParamsResponse::XEnumHeaderEnum value) +{ + switch (value) + { + case XEnumHeaderEnum::UNSPECIFIED: return "UNSPECIFIED"; + case XEnumHeaderEnum::X: return "X"; + case XEnumHeaderEnum::Y: return "Y"; + case XEnumHeaderEnum::Z: return "Z"; + default: return {}; + } +} + +ComplexParamsResponse::XEnumHeaderEnum ComplexParamsResponse::XEnumHeaderEnumFromString(const std::string& str) +{ + if (str == "UNSPECIFIED") + { + return XEnumHeaderEnum::UNSPECIFIED; + } + if (str == "X") + { + return XEnumHeaderEnum::X; + } + if (str == "Y") + { + return XEnumHeaderEnum::Y; + } + if (str == "Z") + { + return XEnumHeaderEnum::Z; + } + throw std::invalid_argument("Invalid enum value"); +} + +// ========================================= +// ===== Enum CookieEnumEnum Conversions ===== +// ========================================= +std::string ComplexParamsResponse::CookieEnumEnumToString(ComplexParamsResponse::CookieEnumEnum value) +{ + switch (value) + { + case CookieEnumEnum::UNSPECIFIED: return "UNSPECIFIED"; + case CookieEnumEnum::COOKIEA: return "COOKIEA"; + case CookieEnumEnum::COOKIEB: return "COOKIEB"; + default: return {}; + } +} + +ComplexParamsResponse::CookieEnumEnum ComplexParamsResponse::CookieEnumEnumFromString(const std::string& str) +{ + if (str == "UNSPECIFIED") + { + return CookieEnumEnum::UNSPECIFIED; + } + if (str == "COOKIEA") + { + return CookieEnumEnum::COOKIEA; + } + if (str == "COOKIEB") + { + return CookieEnumEnum::COOKIEB; + } + throw std::invalid_argument("Invalid enum value"); +} + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/ComplexParamsResponse.h b/samples/server/petstore/cpp-httplib-server/petstore/models/ComplexParamsResponse.h new file mode 100644 index 000000000000..eaab72300df9 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/ComplexParamsResponse.h @@ -0,0 +1,165 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include +#include +#include +#include "DeepObj.h" + + + +namespace models { + + +class ComplexParamsResponse +{ +public: + enum class EnumParamEnum { + UNSPECIFIED, + A, + B, + C + }; + + // Enum conversion functions (definitions in .cpp) + static std::string EnumParamEnumToString(EnumParamEnum value); + static EnumParamEnum EnumParamEnumFromString(const std::string& str); + + enum class XEnumHeaderEnum { + UNSPECIFIED, + X, + Y, + Z + }; + + // Enum conversion functions (definitions in .cpp) + static std::string XEnumHeaderEnumToString(XEnumHeaderEnum value); + static XEnumHeaderEnum XEnumHeaderEnumFromString(const std::string& str); + + enum class CookieEnumEnum { + UNSPECIFIED, + COOKIEA, + COOKIEB + }; + + // Enum conversion functions (definitions in .cpp) + static std::string CookieEnumEnumToString(CookieEnumEnum value); + static CookieEnumEnum CookieEnumEnumFromString(const std::string& str); + + + ComplexParamsResponse(); + virtual ~ComplexParamsResponse() = default; + + // Getters and setters + [[nodiscard]] DeepObj getDeepObj() const; + void setDeepObj(const DeepObj& deepObj); + [[nodiscard]] std::optional getEnumParam() const; + void setEnumParam(const std::optional& enumParam); + [[nodiscard]] std::vector getPipeArr() const; + void setPipeArr(const std::vector& pipeArr); + [[nodiscard]] std::vector getSpaceArr() const; + void setSpaceArr(const std::vector& spaceArr); + [[nodiscard]] std::optional getXEnumHeader() const; + void setXEnumHeader(const std::optional& xEnumHeader); + [[nodiscard]] std::optional getCookieEnum() const; + void setCookieEnum(const std::optional& cookieEnum); + // Serialization helpers for std::optional + friend inline void to_json(nlohmann::json& j, const std::optional& opt) + { + if (opt.has_value()) + { + j = EnumParamEnumToString(opt.value()); + } + else + { + j = nullptr; + } + } + + friend inline void from_json(const nlohmann::json& j, std::optional& opt) + { + if (j.is_null()) + { + opt = std::nullopt; + } + else + { + opt = EnumParamEnumFromString(j.get()); + } + } + + // Serialization helpers for std::optional + friend inline void to_json(nlohmann::json& j, const std::optional& opt) + { + if (opt.has_value()) + { + j = XEnumHeaderEnumToString(opt.value()); + } + else + { + j = nullptr; + } + } + + friend inline void from_json(const nlohmann::json& j, std::optional& opt) + { + if (j.is_null()) + { + opt = std::nullopt; + } + else + { + opt = XEnumHeaderEnumFromString(j.get()); + } + } + + // Serialization helpers for std::optional + friend inline void to_json(nlohmann::json& j, const std::optional& opt) + { + if (opt.has_value()) + { + j = CookieEnumEnumToString(opt.value()); + } + else + { + j = nullptr; + } + } + + friend inline void from_json(const nlohmann::json& j, std::optional& opt) + { + if (j.is_null()) + { + opt = std::nullopt; + } + else + { + opt = CookieEnumEnumFromString(j.get()); + } + } + + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(ComplexParamsResponse, + deepObj, enumParam, pipeArr, spaceArr, xEnumHeader, cookieEnum) + +private: + DeepObj deepObj; + std::optional enumParam; + std::vector pipeArr; + std::vector spaceArr; + std::optional xEnumHeader; + std::optional cookieEnum; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/DeepObj.cpp b/samples/server/petstore/cpp-httplib-server/petstore/models/DeepObj.cpp new file mode 100644 index 000000000000..451b77069685 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/DeepObj.cpp @@ -0,0 +1,58 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "DeepObj.h" + +namespace models { + +DeepObj::DeepObj() +: foo("") +, bar(0) +, baz(DeepObjBaz()) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string DeepObj::getFoo() const +{ + return foo; +} +int DeepObj::getBar() const +{ + return bar; +} +DeepObjBaz DeepObj::getBaz() const +{ + return baz; +} + +// =================== +// ===== Setters ===== +// =================== +void DeepObj::setFoo(const std::string& fooObj) +{ + foo = fooObj; +} +void DeepObj::setBar(const int& barObj) +{ + bar = barObj; +} +void DeepObj::setBaz(const DeepObjBaz& bazObj) +{ + baz = bazObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/DeepObj.h b/samples/server/petstore/cpp-httplib-server/petstore/models/DeepObj.h new file mode 100644 index 000000000000..25350d579e94 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/DeepObj.h @@ -0,0 +1,47 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include +#include "DeepObjBaz.h" + + + +namespace models { + + +class DeepObj +{ +public: + + DeepObj(); + virtual ~DeepObj() = default; + + // Getters and setters + [[nodiscard]] std::string getFoo() const; + void setFoo(const std::string& foo); + [[nodiscard]] int getBar() const; + void setBar(const int& bar); + [[nodiscard]] DeepObjBaz getBaz() const; + void setBaz(const DeepObjBaz& baz); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(DeepObj, + foo, bar, baz) + +private: + std::string foo; + int bar; + DeepObjBaz baz; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/DeepObjBaz.cpp b/samples/server/petstore/cpp-httplib-server/petstore/models/DeepObjBaz.cpp new file mode 100644 index 000000000000..e685b2ca636b --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/DeepObjBaz.cpp @@ -0,0 +1,49 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "DeepObjBaz.h" + +namespace models { + +DeepObjBaz::DeepObjBaz() +: X("") +, Y(0) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string DeepObjBaz::getX() const +{ + return X; +} +int DeepObjBaz::getY() const +{ + return Y; +} + +// =================== +// ===== Setters ===== +// =================== +void DeepObjBaz::setX(const std::string& XObj) +{ + X = XObj; +} +void DeepObjBaz::setY(const int& YObj) +{ + Y = YObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/DeepObjBaz.h b/samples/server/petstore/cpp-httplib-server/petstore/models/DeepObjBaz.h new file mode 100644 index 000000000000..5220c128694b --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/DeepObjBaz.h @@ -0,0 +1,43 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include + + + +namespace models { + + +class DeepObjBaz +{ +public: + + DeepObjBaz(); + virtual ~DeepObjBaz() = default; + + // Getters and setters + [[nodiscard]] std::string getX() const; + void setX(const std::string& X); + [[nodiscard]] int getY() const; + void setY(const int& Y); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(DeepObjBaz, + X, Y) + +private: + std::string X; + int Y; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/NullableExample.cpp b/samples/server/petstore/cpp-httplib-server/petstore/models/NullableExample.cpp new file mode 100644 index 000000000000..44a3cf6bd4fc --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/NullableExample.cpp @@ -0,0 +1,40 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "NullableExample.h" + +namespace models { + +NullableExample::NullableExample() +: maybeString("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +std::string NullableExample::getMaybeString() const +{ + return maybeString; +} + +// =================== +// ===== Setters ===== +// =================== +void NullableExample::setMaybeString(const std::string& maybeStringObj) +{ + maybeString = maybeStringObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/NullableExample.h b/samples/server/petstore/cpp-httplib-server/petstore/models/NullableExample.h new file mode 100644 index 000000000000..cd532bccb1b8 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/NullableExample.h @@ -0,0 +1,40 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include + + + +namespace models { + + +class NullableExample +{ +public: + + NullableExample(); + virtual ~NullableExample() = default; + + // Getters and setters + [[nodiscard]] std::string getMaybeString() const; + void setMaybeString(const std::string& maybeString); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(NullableExample, + maybeString) + +private: + std::string maybeString; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/Order.cpp b/samples/server/petstore/cpp-httplib-server/petstore/models/Order.cpp new file mode 100644 index 000000000000..de60ab3c2685 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/Order.cpp @@ -0,0 +1,121 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "Order.h" + +namespace models { + +Order::Order() +: id(0) +, petId(0) +, quantity(0) +, shipDate("") +, status(std::nullopt) +, complete(false) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +long Order::getId() const +{ + return id; +} +long Order::getPetId() const +{ + return petId; +} +int Order::getQuantity() const +{ + return quantity; +} +std::string Order::getShipDate() const +{ + return shipDate; +} +std::optional Order::getStatus() const +{ + return status; +} +bool Order::isComplete() const +{ + return complete; +} + +// =================== +// ===== Setters ===== +// =================== +void Order::setId(const long& idObj) +{ + id = idObj; +} +void Order::setPetId(const long& petIdObj) +{ + petId = petIdObj; +} +void Order::setQuantity(const int& quantityObj) +{ + quantity = quantityObj; +} +void Order::setShipDate(const std::string& shipDateObj) +{ + shipDate = shipDateObj; +} +void Order::setStatus(const std::optional& statusObj) +{ + status = statusObj; +} +void Order::setComplete(const bool& completeObj) +{ + complete = completeObj; +} + + +// ========================================= +// ===== Enum StatusEnum Conversions ===== +// ========================================= +std::string Order::StatusEnumToString(Order::StatusEnum value) +{ + switch (value) + { + case StatusEnum::UNSPECIFIED: return "UNSPECIFIED"; + case StatusEnum::PLACED: return "PLACED"; + case StatusEnum::APPROVED: return "APPROVED"; + case StatusEnum::DELIVERED: return "DELIVERED"; + default: return {}; + } +} + +Order::StatusEnum Order::StatusEnumFromString(const std::string& str) +{ + if (str == "UNSPECIFIED") + { + return StatusEnum::UNSPECIFIED; + } + if (str == "PLACED") + { + return StatusEnum::PLACED; + } + if (str == "APPROVED") + { + return StatusEnum::APPROVED; + } + if (str == "DELIVERED") + { + return StatusEnum::DELIVERED; + } + throw std::invalid_argument("Invalid enum value"); +} + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/Order.h b/samples/server/petstore/cpp-httplib-server/petstore/models/Order.h new file mode 100644 index 000000000000..7e7d3aade171 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/Order.h @@ -0,0 +1,92 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include +#include + + + +namespace models { + + +class Order +{ +public: + enum class StatusEnum { + UNSPECIFIED, + PLACED, + APPROVED, + DELIVERED + }; + + // Enum conversion functions (definitions in .cpp) + static std::string StatusEnumToString(StatusEnum value); + static StatusEnum StatusEnumFromString(const std::string& str); + + + Order(); + virtual ~Order() = default; + + // Getters and setters + [[nodiscard]] long getId() const; + void setId(const long& id); + [[nodiscard]] long getPetId() const; + void setPetId(const long& petId); + [[nodiscard]] int getQuantity() const; + void setQuantity(const int& quantity); + [[nodiscard]] std::string getShipDate() const; + void setShipDate(const std::string& shipDate); + [[nodiscard]] std::optional getStatus() const; + void setStatus(const std::optional& status); + [[nodiscard]] bool isComplete() const; + void setComplete(const bool& complete); + // Serialization helpers for std::optional + friend inline void to_json(nlohmann::json& j, const std::optional& opt) + { + if (opt.has_value()) + { + j = StatusEnumToString(opt.value()); + } + else + { + j = nullptr; + } + } + + friend inline void from_json(const nlohmann::json& j, std::optional& opt) + { + if (j.is_null()) + { + opt = std::nullopt; + } + else + { + opt = StatusEnumFromString(j.get()); + } + } + + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(Order, + id, petId, quantity, shipDate, status, complete) + +private: + long id; + long petId; + int quantity; + std::string shipDate; + std::optional status; + bool complete; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/Pet.cpp b/samples/server/petstore/cpp-httplib-server/petstore/models/Pet.cpp new file mode 100644 index 000000000000..0359a9684802 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/Pet.cpp @@ -0,0 +1,121 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "Pet.h" + +namespace models { + +Pet::Pet() +: id(0) +, name("") +, photoUrls(std::vector()) +, status(std::nullopt) +, category(Category()) +, tags(std::vector()) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +long Pet::getId() const +{ + return id; +} +std::string Pet::getName() const +{ + return name; +} +std::vector Pet::getPhotoUrls() const +{ + return photoUrls; +} +std::optional Pet::getStatus() const +{ + return status; +} +Category Pet::getCategory() const +{ + return category; +} +std::vector Pet::getTags() const +{ + return tags; +} + +// =================== +// ===== Setters ===== +// =================== +void Pet::setId(const long& idObj) +{ + id = idObj; +} +void Pet::setName(const std::string& nameObj) +{ + name = nameObj; +} +void Pet::setPhotoUrls(const std::vector& photoUrlsObj) +{ + photoUrls = photoUrlsObj; +} +void Pet::setStatus(const std::optional& statusObj) +{ + status = statusObj; +} +void Pet::setCategory(const Category& categoryObj) +{ + category = categoryObj; +} +void Pet::setTags(const std::vector& tagsObj) +{ + tags = tagsObj; +} + + +// ========================================= +// ===== Enum StatusEnum Conversions ===== +// ========================================= +std::string Pet::StatusEnumToString(Pet::StatusEnum value) +{ + switch (value) + { + case StatusEnum::UNSPECIFIED: return "UNSPECIFIED"; + case StatusEnum::AVAILABLE: return "AVAILABLE"; + case StatusEnum::PENDING: return "PENDING"; + case StatusEnum::SOLD: return "SOLD"; + default: return {}; + } +} + +Pet::StatusEnum Pet::StatusEnumFromString(const std::string& str) +{ + if (str == "UNSPECIFIED") + { + return StatusEnum::UNSPECIFIED; + } + if (str == "AVAILABLE") + { + return StatusEnum::AVAILABLE; + } + if (str == "PENDING") + { + return StatusEnum::PENDING; + } + if (str == "SOLD") + { + return StatusEnum::SOLD; + } + throw std::invalid_argument("Invalid enum value"); +} + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/Pet.h b/samples/server/petstore/cpp-httplib-server/petstore/models/Pet.h new file mode 100644 index 000000000000..a120edbd44fc --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/Pet.h @@ -0,0 +1,94 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include +#include +#include "Category.h" +#include "Tag.h" + + + +namespace models { + + +class Pet +{ +public: + enum class StatusEnum { + UNSPECIFIED, + AVAILABLE, + PENDING, + SOLD + }; + + // Enum conversion functions (definitions in .cpp) + static std::string StatusEnumToString(StatusEnum value); + static StatusEnum StatusEnumFromString(const std::string& str); + + + Pet(); + virtual ~Pet() = default; + + // Getters and setters + [[nodiscard]] long getId() const; + void setId(const long& id); + [[nodiscard]] std::string getName() const; + void setName(const std::string& name); + [[nodiscard]] std::vector getPhotoUrls() const; + void setPhotoUrls(const std::vector& photoUrls); + [[nodiscard]] std::optional getStatus() const; + void setStatus(const std::optional& status); + [[nodiscard]] Category getCategory() const; + void setCategory(const Category& category); + [[nodiscard]] std::vector getTags() const; + void setTags(const std::vector& tags); + // Serialization helpers for std::optional + friend inline void to_json(nlohmann::json& j, const std::optional& opt) + { + if (opt.has_value()) + { + j = StatusEnumToString(opt.value()); + } + else + { + j = nullptr; + } + } + + friend inline void from_json(const nlohmann::json& j, std::optional& opt) + { + if (j.is_null()) + { + opt = std::nullopt; + } + else + { + opt = StatusEnumFromString(j.get()); + } + } + + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(Pet, + id, name, photoUrls, status, category, tags) + +private: + long id; + std::string name; + std::vector photoUrls; + std::optional status; + Category category; + std::vector tags; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/PetOrCategory.cpp b/samples/server/petstore/cpp-httplib-server/petstore/models/PetOrCategory.cpp new file mode 100644 index 000000000000..978e7ed2bef8 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/PetOrCategory.cpp @@ -0,0 +1,7 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/PetOrCategory.h b/samples/server/petstore/cpp-httplib-server/petstore/models/PetOrCategory.h new file mode 100644 index 000000000000..395dfafc31ba --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/PetOrCategory.h @@ -0,0 +1,58 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include +#include +#include +#include "Category.h" +#include "Pet.h" +#include "Tag.h" + + + +namespace models { + +// oneOf schema - type alias for std::variant +using PetOrCategory = std::variant< + Pet, + Category>; + +// JSON serialization functions (inline for header-only) +inline void from_json(const nlohmann::json& j, PetOrCategory& obj) +{ + try + { + obj = j.get(); + return; + } + catch (const nlohmann::json::exception&) + { + // Type mismatch, try next variant alternative + } + try + { + obj = j.get(); + return; + } + catch (const nlohmann::json::exception&) + { + // Type mismatch, try next variant alternative + } + throw nlohmann::json::type_error::create(302, "Could not deserialize into any variant type of PetOrCategory", &j); +} + +inline void to_json(nlohmann::json& j, const PetOrCategory& obj) +{ + std::visit([&j](const auto& val) { j = nlohmann::json(val); }, obj); +} + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/Tag.cpp b/samples/server/petstore/cpp-httplib-server/petstore/models/Tag.cpp new file mode 100644 index 000000000000..c2e885cf556f --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/Tag.cpp @@ -0,0 +1,49 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "Tag.h" + +namespace models { + +Tag::Tag() +: id(0) +, name("") +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +long Tag::getId() const +{ + return id; +} +std::string Tag::getName() const +{ + return name; +} + +// =================== +// ===== Setters ===== +// =================== +void Tag::setId(const long& idObj) +{ + id = idObj; +} +void Tag::setName(const std::string& nameObj) +{ + name = nameObj; +} + + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/Tag.h b/samples/server/petstore/cpp-httplib-server/petstore/models/Tag.h new file mode 100644 index 000000000000..d8255563cdeb --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/Tag.h @@ -0,0 +1,42 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include + + + +namespace models { + + +class Tag +{ +public: + + Tag(); + virtual ~Tag() = default; + + // Getters and setters + [[nodiscard]] long getId() const; + void setId(const long& id); + [[nodiscard]] std::string getName() const; + void setName(const std::string& name); + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(Tag, + id, name) + +private: + long id; + std::string name; +}; + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/User.cpp b/samples/server/petstore/cpp-httplib-server/petstore/models/User.cpp new file mode 100644 index 000000000000..f29293989130 --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/User.cpp @@ -0,0 +1,139 @@ + +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +#include "User.h" + +namespace models { + +User::User() +: id(0) +, username("") +, firstName("") +, lastName("") +, email("") +, password("") +, phone("") +, userStatus(std::nullopt) +{ +} +// ========================================= +// ===== Getters/Setters ===== +// ========================================= +// =================== +// ===== Getters ===== +// =================== +long User::getId() const +{ + return id; +} +std::string User::getUsername() const +{ + return username; +} +std::string User::getFirstName() const +{ + return firstName; +} +std::string User::getLastName() const +{ + return lastName; +} +std::string User::getEmail() const +{ + return email; +} +std::string User::getPassword() const +{ + return password; +} +std::string User::getPhone() const +{ + return phone; +} +std::optional User::getUserStatus() const +{ + return userStatus; +} + +// =================== +// ===== Setters ===== +// =================== +void User::setId(const long& idObj) +{ + id = idObj; +} +void User::setUsername(const std::string& usernameObj) +{ + username = usernameObj; +} +void User::setFirstName(const std::string& firstNameObj) +{ + firstName = firstNameObj; +} +void User::setLastName(const std::string& lastNameObj) +{ + lastName = lastNameObj; +} +void User::setEmail(const std::string& emailObj) +{ + email = emailObj; +} +void User::setPassword(const std::string& passwordObj) +{ + password = passwordObj; +} +void User::setPhone(const std::string& phoneObj) +{ + phone = phoneObj; +} +void User::setUserStatus(const std::optional& userStatusObj) +{ + userStatus = userStatusObj; +} + + +// ========================================= +// ===== Enum UserStatusEnum Conversions ===== +// ========================================= +std::string User::UserStatusEnumToString(User::UserStatusEnum value) +{ + switch (value) + { + case UserStatusEnum::UNSPECIFIED: return "UNSPECIFIED"; + case UserStatusEnum::_0: return "_0"; + case UserStatusEnum::_1: return "_1"; + case UserStatusEnum::_2: return "_2"; + default: return {}; + } +} + +User::UserStatusEnum User::UserStatusEnumFromString(const std::string& str) +{ + if (str == "UNSPECIFIED") + { + return UserStatusEnum::UNSPECIFIED; + } + if (str == "_0") + { + return UserStatusEnum::_0; + } + if (str == "_1") + { + return UserStatusEnum::_1; + } + if (str == "_2") + { + return UserStatusEnum::_2; + } + throw std::invalid_argument("Invalid enum value"); +} + + + + + +} // namespace models + diff --git a/samples/server/petstore/cpp-httplib-server/petstore/models/User.h b/samples/server/petstore/cpp-httplib-server/petstore/models/User.h new file mode 100644 index 000000000000..ca4e9d5ff0de --- /dev/null +++ b/samples/server/petstore/cpp-httplib-server/petstore/models/User.h @@ -0,0 +1,98 @@ +/** +* This file is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#pragma once +// System headers +#include +#include +#include +#include + + + +namespace models { + + +class User +{ +public: + enum class UserStatusEnum { + UNSPECIFIED, + _0, + _1, + _2 + }; + + // Enum conversion functions (definitions in .cpp) + static std::string UserStatusEnumToString(UserStatusEnum value); + static UserStatusEnum UserStatusEnumFromString(const std::string& str); + + + User(); + virtual ~User() = default; + + // Getters and setters + [[nodiscard]] long getId() const; + void setId(const long& id); + [[nodiscard]] std::string getUsername() const; + void setUsername(const std::string& username); + [[nodiscard]] std::string getFirstName() const; + void setFirstName(const std::string& firstName); + [[nodiscard]] std::string getLastName() const; + void setLastName(const std::string& lastName); + [[nodiscard]] std::string getEmail() const; + void setEmail(const std::string& email); + [[nodiscard]] std::string getPassword() const; + void setPassword(const std::string& password); + [[nodiscard]] std::string getPhone() const; + void setPhone(const std::string& phone); + [[nodiscard]] std::optional getUserStatus() const; + void setUserStatus(const std::optional& userStatus); + // Serialization helpers for std::optional + friend inline void to_json(nlohmann::json& j, const std::optional& opt) + { + if (opt.has_value()) + { + j = UserStatusEnumToString(opt.value()); + } + else + { + j = nullptr; + } + } + + friend inline void from_json(const nlohmann::json& j, std::optional& opt) + { + if (j.is_null()) + { + opt = std::nullopt; + } + else + { + opt = UserStatusEnumFromString(j.get()); + } + } + + + + // JSON serialization using NLOHMANN INTRUSIVE macro (must be inside class to access private members) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(User, + id, username, firstName, lastName, email, password, phone, userStatus) + +private: + long id; + std::string username; + std::string firstName; + std::string lastName; + std::string email; + std::string password; + std::string phone; + std::optional userStatus; +}; + + +} // namespace models + diff --git a/website/i18n/en.json b/website/i18n/en.json index f032b40060bf..f24f86b11eb0 100644 --- a/website/i18n/en.json +++ b/website/i18n/en.json @@ -87,6 +87,10 @@ "title": "Config Options for clojure", "sidebar_label": "clojure" }, + "generators/cpp-httplib-server": { + "title": "Config Options for cpp-httplib-server", + "sidebar_label": "cpp-httplib-server" + }, "generators/cpp-oatpp-client": { "title": "Config Options for cpp-oatpp-client", "sidebar_label": "cpp-oatpp-client"