Skip to content

Commit

Permalink
[c++ pistache server] Support basic query handling (OpenAPITools#943)
Browse files Browse the repository at this point in the history
Support basic query handling

Add  helpers for primitive de-serialization
Remove warnings due to unneeded commas
Deserialize basic types in queries
Add dependencies chain for external libraries
Fixes wrong parameter passed to API
  • Loading branch information
etherealjoy authored and jaumard committed Sep 21, 2018
1 parent 32f4cb5 commit 8b338b0
Show file tree
Hide file tree
Showing 21 changed files with 413 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ public class CppPistacheServerCodegen extends AbstractCppCodegen {
protected boolean isAddExternalLibs = true;
public static final String OPTIONAL_EXTERNAL_LIB = "addExternalLibs";
public static final String OPTIONAL_EXTERNAL_LIB_DESC = "Add the Possibility to fetch and compile external Libraries needed by this Framework.";
public static final String HELPERS_PACKAGE_NAME = "helpersPackage";
public static final String HELPERS_PACKAGE_NAME_DESC = "Specify the package name to be used for the helpers (e.g. org.openapitools.server.helpers).";
protected final String PREFIX = "";

protected String helpersPackage = "";
@Override
public CodegenType getTag() {
return CodegenType.SERVER;
Expand All @@ -70,6 +72,7 @@ public CppPistacheServerCodegen() {
modelNamePrefix = PREFIX;
}

helpersPackage = "org.openapitools.server.helpers";
apiPackage = "org.openapitools.server.api";
modelPackage = "org.openapitools.server.model";

Expand All @@ -86,11 +89,14 @@ public CppPistacheServerCodegen() {

cliOptions.clear();
addSwitch(OPTIONAL_EXTERNAL_LIB, OPTIONAL_EXTERNAL_LIB_DESC, this.isAddExternalLibs);
addOption(HELPERS_PACKAGE_NAME, HELPERS_PACKAGE_NAME_DESC, this.helpersPackage);

reservedWords = new HashSet<>();

supportingFiles.add(new SupportingFile("modelbase-header.mustache", "model", modelNamePrefix + "ModelBase.h"));
supportingFiles.add(new SupportingFile("modelbase-source.mustache", "model", modelNamePrefix + "ModelBase.cpp"));
supportingFiles.add(new SupportingFile("helpers-header.mustache", "model", modelNamePrefix + "Helpers.h"));
supportingFiles.add(new SupportingFile("helpers-source.mustache", "model", modelNamePrefix + "Helpers.cpp"));
supportingFiles.add(new SupportingFile("cmake.mustache", "", "CMakeLists.txt"));
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));

Expand Down Expand Up @@ -123,18 +129,26 @@ public CppPistacheServerCodegen() {
@Override
public void processOpts() {
super.processOpts();
if (additionalProperties.containsKey(HELPERS_PACKAGE_NAME)) {
helpersPackage = (String) additionalProperties.get(HELPERS_PACKAGE_NAME);
}
if (additionalProperties.containsKey("modelNamePrefix")) {
additionalProperties().put("prefix", modelNamePrefix);
supportingFiles.clear();
supportingFiles.add(new SupportingFile("modelbase-header.mustache", "model", modelNamePrefix + "ModelBase.h"));
supportingFiles.add(new SupportingFile("modelbase-source.mustache", "model", modelNamePrefix + "ModelBase.cpp"));
supportingFiles.add(new SupportingFile("helpers-header.mustache", "model", modelNamePrefix + "Helpers.h"));
supportingFiles.add(new SupportingFile("helpers-source.mustache", "model", modelNamePrefix + "Helpers.cpp"));
supportingFiles.add(new SupportingFile("cmake.mustache", "", "CMakeLists.txt"));
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
}
additionalProperties.put("modelNamespaceDeclarations", modelPackage.split("\\."));
additionalProperties.put("modelNamespace", modelPackage.replaceAll("\\.", "::"));
additionalProperties.put("apiNamespaceDeclarations", apiPackage.split("\\."));
additionalProperties.put("apiNamespace", apiPackage.replaceAll("\\.", "::"));
additionalProperties.put("apiNamespace", apiPackage.replaceAll("\\.", "::"));
additionalProperties.put("helpersNamespaceDeclarations", helpersPackage.split("\\."));
additionalProperties.put("helpersNamespace", helpersPackage.replaceAll("\\.", "::"));

if (additionalProperties.containsKey(OPTIONAL_EXTERNAL_LIB)) {
setAddExternalLibs(convertPropertyToBooleanAndWriteBack(OPTIONAL_EXTERNAL_LIB));
} else {
Expand Down Expand Up @@ -236,7 +250,7 @@ public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> o
if (param.isPrimitiveType) {
param.dataType = "Pistache::Optional<" + param.dataType + ">";
} else {
param.dataType = "Pistache::Optional<" + param.baseType + ">";
param.dataType = "Pistache::Optional<" + param.dataType + ">";
param.baseType = "Pistache::Optional<" + param.baseType + ">";
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ using namespace {{modelNamespace}};{{/hasModelImport}}
class {{declspec}} {{classname}} {
public:
{{classname}}(Pistache::Address addr);
virtual ~{{classname}}() {};
virtual ~{{classname}}() {}
void init(size_t thr);
void start();
void shutdown();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ using namespace {{modelNamespace}};{{/hasModelImport}}
class {{classname}}Impl : public {{apiNamespace}}::{{classname}} {
public:
{{classname}}Impl(Pistache::Address addr);
~{{classname}}Impl() { };
~{{classname}}Impl() {}

{{#operation}}
{{#vendorExtensions.x-codegen-pistache-isParsingSupported}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
{{#operations}}

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

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

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

Expand Down Expand Up @@ -62,7 +64,14 @@ void {{classname}}::{{operationIdSnakeCase}}_handler(const Pistache::Rest::Reque
{{/hasBodyParam}}{{#hasQueryParams}}
// Getting the query params
{{#queryParams}}
auto {{paramName}} = request.query().get("{{baseName}}");
auto {{paramName}}Query = request.query().get("{{baseName}}");
Pistache::Optional<{{^isContainer}}{{dataType}}{{/isContainer}}{{#isListContainer}}std::vector<{{items.baseType}}>{{/isListContainer}}> {{paramName}};
if(!{{paramName}}Query.isEmpty()){
{{^isContainer}}{{dataType}}{{/isContainer}}{{#isListContainer}}std::vector<{{items.baseType}}>{{/isListContainer}} value;
if(fromStringValue({{paramName}}Query.get(), value)){
{{paramName}} = Pistache::Some(value);
}
}
{{/queryParams}}
{{/hasQueryParams}}{{#hasHeaderParams}}
// Getting the header params
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ set(<%classnameSnakeUpperCase%>_SERVER_SOURCES
<%#operations%>
add_executable(<%classnameSnakeLowerCase%>_server
${<%classnameSnakeUpperCase%>_SERVER_SOURCES})
<%#addExternalLibs%>
add_dependencies(<%classnameSnakeLowerCase%>_server PISTACHE NLOHMANN)
<%/addExternalLibs%>
<%/operations%>
<%/apiInfo.apis%>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{{>licenseInfo}}
/*
* {{prefix}}Helpers.h
*
* This is the helper class for models and primitives
*/

#ifndef {{prefix}}Helpers_H_
#define {{prefix}}Helpers_H_

#include <ctime>
#include <string>
#include <sstream>
#include <vector>
#include <map>

{{#helpersNamespaceDeclarations}}
namespace {{this}} {
{{/helpersNamespaceDeclarations}}

std::string toStringValue(const std::string &value);
std::string toStringValue(const int32_t &value);
std::string toStringValue(const int64_t &value);
std::string toStringValue(const bool &value);
std::string toStringValue(const float &value);
std::string toStringValue(const double &value);

bool fromStringValue(const std::string &inStr, std::string &value);
bool fromStringValue(const std::string &inStr, int32_t &value);
bool fromStringValue(const std::string &inStr, int64_t &value);
bool fromStringValue(const std::string &inStr, bool &value);
bool fromStringValue(const std::string &inStr, float &value);
bool fromStringValue(const std::string &inStr, double &value);
template<typename T>
bool fromStringValue(const std::vector<std::string> &inStr, std::vector<T> &value){
try{
for(auto & item : inStr){
T itemValue;
if(fromStringValue(item, itemValue)){
value.push_back(itemValue);
}
}
}
catch(...){
return false;
}
return value.size() > 0;
}
template<typename T>
bool fromStringValue(const std::string &inStr, std::vector<T> &value, char separator = ','){
std::vector<std::string> inStrings;
std::istringstream f(inStr);
std::string s;
while (std::getline(f, s, separator)) {
inStrings.push_back(s);
}
return fromStringValue(inStrings, value);
}

{{#helpersNamespaceDeclarations}}
}
{{/helpersNamespaceDeclarations}}

#endif // {{prefix}}Helpers_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{{>licenseInfo}}
#include "{{prefix}}Helpers.h"

{{#helpersNamespaceDeclarations}}
namespace {{this}} {
{{/helpersNamespaceDeclarations}}


std::string toStringValue(const std::string &value){
return std::string(value);
}

std::string toStringValue(const int32_t &value){
return std::to_string(value);
}

std::string toStringValue(const int64_t &value){
return std::to_string(value);
}

std::string toStringValue(const bool &value){
return value?std::string("true"):std::string("false");
}

std::string toStringValue(const float &value){
return std::to_string(value);
}

std::string toStringValue(const double &value){
return std::to_string(value);
}

bool fromStringValue(const std::string &inStr, std::string &value){
value = std::string(inStr);
return true;
}

bool fromStringValue(const std::string &inStr, int32_t &value){
try {
value = std::stoi( inStr );
}
catch (const std::invalid_argument) {
return false;
}
return true;
}

bool fromStringValue(const std::string &inStr, int64_t &value){
try {
value = std::stol( inStr );
}
catch (const std::invalid_argument) {
return false;
}
return true;
}

bool fromStringValue(const std::string &inStr, bool &value){
bool result = true;
inStr == "true"?value = true: inStr == "false"?value = false: result = false;
return result;
}

bool fromStringValue(const std::string &inStr, float &value){
try {
value = std::stof( inStr );
}
catch (const std::invalid_argument) {
return false;
}
return true;
}

bool fromStringValue(const std::string &inStr, double &value){
try {
value = std::stod( inStr );
}
catch (const std::invalid_argument) {
return false;
}
return true;
}

{{#helpersNamespaceDeclarations}}
}
{{/helpersNamespaceDeclarations}}
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,15 @@ void {{classname}}::fromJson(nlohmann::json& val)
}
{{/isListContainer}}{{^isListContainer}}{{^isPrimitiveType}}{{^required}}if(val.find("{{baseName}}") != val.end())
{
{{#isString}}{{setter}}(val.at("{{baseName}}"));{{/isString}}{{#isByteArray}}{{setter}}(val.at("{{baseName}}"));
{{/isByteArray}}{{^isString}}{{#isDateTime}}{{setter}}(val.at("{{baseName}}"));
{{/isDateTime}}{{^isDateTime}}{{^isByteArray}}if(!val["{{baseName}}"].is_null())
{{#isString}}{{setter}}(val.at("{{baseName}}"));{{/isString}}{{#isByteArray}}{{setter}}(val.at("{{baseName}}"));{{/isByteArray}}{{#isBinary}}{{setter}}(val.at("{{baseName}}"));
{{/isBinary}}{{^isString}}{{#isDateTime}}{{setter}}(val.at("{{baseName}}"));
{{/isDateTime}}{{^isDateTime}}{{^isByteArray}}{{^isBinary}}if(!val["{{baseName}}"].is_null())
{
{{{dataType}}} newItem;
newItem.fromJson(val["{{baseName}}"]);
{{setter}}( newItem );
}
{{/isByteArray}}{{/isDateTime}}{{/isString}}
{{/isBinary}}{{/isByteArray}}{{/isDateTime}}{{/isString}}
}
{{/required}}{{#required}}{{#isString}}{{setter}}(val.at("{{baseName}}"));
{{/isString}}{{^isString}}{{#isDateTime}}{{setter}}(val.at("{{baseName}}"));
Expand Down
3 changes: 3 additions & 0 deletions samples/server/petstore/cpp-pistache/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,13 @@ UserApiMainServer.cpp

add_executable(pet_api_server
${PET_API_SERVER_SOURCES})
add_dependencies(pet_api_server PISTACHE NLOHMANN)
add_executable(store_api_server
${STORE_API_SERVER_SOURCES})
add_dependencies(store_api_server PISTACHE NLOHMANN)
add_executable(user_api_server
${USER_API_SERVER_SOURCES})
add_dependencies(user_api_server PISTACHE NLOHMANN)

target_link_libraries(pet_api_server pistache pthread)
target_link_libraries(store_api_server pistache pthread)
Expand Down
20 changes: 18 additions & 2 deletions samples/server/petstore/cpp-pistache/api/PetApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
*/

#include "PetApi.h"
#include "Helpers.h"

namespace org {
namespace openapitools {
namespace server {
namespace api {

using namespace org::openapitools::server::helpers;
using namespace org::openapitools::server::model;

PetApi::PetApi(Pistache::Address addr)
Expand Down Expand Up @@ -94,7 +96,14 @@ void PetApi::delete_pet_handler(const Pistache::Rest::Request &request, Pistache
void PetApi::find_pets_by_status_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {

// Getting the query params
auto status = request.query().get("status");
auto statusQuery = request.query().get("status");
Pistache::Optional<std::vector<std::string>> status;
if(!statusQuery.isEmpty()){
std::vector<std::string> value;
if(fromStringValue(statusQuery.get(), value)){
status = Pistache::Some(value);
}
}

try {
this->find_pets_by_status(status, response);
Expand All @@ -108,7 +117,14 @@ void PetApi::find_pets_by_status_handler(const Pistache::Rest::Request &request,
void PetApi::find_pets_by_tags_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {

// Getting the query params
auto tags = request.query().get("tags");
auto tagsQuery = request.query().get("tags");
Pistache::Optional<std::vector<std::string>> tags;
if(!tagsQuery.isEmpty()){
std::vector<std::string> value;
if(fromStringValue(tagsQuery.get(), value)){
tags = Pistache::Some(value);
}
}

try {
this->find_pets_by_tags(tags, response);
Expand Down
6 changes: 3 additions & 3 deletions samples/server/petstore/cpp-pistache/api/PetApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ using namespace org::openapitools::server::model;
class PetApi {
public:
PetApi(Pistache::Address addr);
virtual ~PetApi() {};
virtual ~PetApi() {}
void init(size_t thr);
void start();
void shutdown();
Expand Down Expand Up @@ -90,7 +90,7 @@ class PetApi {
/// Multiple status values can be provided with comma separated strings
/// </remarks>
/// <param name="status">Status values that need to be considered for filter</param>
virtual void find_pets_by_status(const Pistache::Optional<std::string> &status, Pistache::Http::ResponseWriter &response) = 0;
virtual void find_pets_by_status(const Pistache::Optional<std::vector<std::string>> &status, Pistache::Http::ResponseWriter &response) = 0;

/// <summary>
/// Finds Pets by tags
Expand All @@ -99,7 +99,7 @@ class PetApi {
/// Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.
/// </remarks>
/// <param name="tags">Tags to filter by</param>
virtual void find_pets_by_tags(const Pistache::Optional<std::string> &tags, Pistache::Http::ResponseWriter &response) = 0;
virtual void find_pets_by_tags(const Pistache::Optional<std::vector<std::string>> &tags, Pistache::Http::ResponseWriter &response) = 0;

/// <summary>
/// Find pet by ID
Expand Down
Loading

0 comments on commit 8b338b0

Please sign in to comment.