[C++] [Pistache] Model validation, general overhaul (#9251)

* overhaul pistache templates

* fix function signature in model-source
return type now aligns with definition in model-header

* use default keyword for destructors

* generate pistache samples

* move bin/configs/other/cpp-pistache-server-cpp-pistache.yaml to bin/configs/cpp-pistache-server-cpp-pistache.yaml

* Only generate validation body if necessary

* generate pistache samples
This commit is contained in:
Julian G 2021-05-05 10:52:47 +02:00 committed by GitHub
parent 4d2b022619
commit 8f5639554e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1461 additions and 537 deletions

View File

@ -128,6 +128,7 @@ public class CppPistacheServerCodegen extends AbstractCppCodegen {
typeMapping.put("boolean", "bool");
typeMapping.put("array", "std::vector");
typeMapping.put("map", "std::map");
typeMapping.put("set", "std::vector");
typeMapping.put("file", "std::string");
typeMapping.put("object", "Object");
typeMapping.put("binary", "std::string");

View File

@ -14,24 +14,21 @@
#include <pistache/http_headers.h>
#include <pistache/optional.h>
{{^hasModelImport}}#include <nlohmann/json.hpp>{{/hasModelImport}}
#include <utility>
{{#imports}}{{{import}}}
{{/imports}}
{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}
{{#hasModelImport}}
using namespace {{modelNamespace}};{{/hasModelImport}}
namespace {{apiNamespace}}
{
class {{declspec}} {{classname}} {
public:
{{classname}}(std::shared_ptr<Pistache::Rest::Router>);
virtual ~{{classname}}() {}
explicit {{classname}}(const std::shared_ptr<Pistache::Rest::Router>& rtr);
virtual ~{{classname}}() = default;
void init();
const std::string base = "{{basePathWithoutHost}}";
static const std::string base;
private:
void setupRoutes();
@ -41,9 +38,21 @@ private:
{{/operation}}
void {{classnameSnakeLowerCase}}_default_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
std::shared_ptr<Pistache::Rest::Router> router;
{{#operation}}
const std::shared_ptr<Pistache::Rest::Router> router;
/// <summary>
/// Helper function to handle unexpected Exceptions during Parameter parsing and validation.
/// May be overriden to return custom error formats.
/// </summary>
virtual std::pair<Pistache::Http::Code, std::string> handleParsingException(const std::exception& ex) const noexcept;
/// <summary>
/// Helper function to handle unexpected Exceptions during processing of the request in handler functions.
/// May be overriden to return custom error formats.
/// </summary>
virtual std::pair<Pistache::Http::Code, std::string> handleOperationException(const std::exception& ex) const noexcept;
{{#operation}}
/// <summary>
/// {{summary}}
/// </summary>
@ -54,7 +63,7 @@ private:
{{#allParams}}
/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
{{/allParams}}
virtual void {{operationIdSnakeCase}}({{#allParams}}const {{{dataType}}} &{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}Pistache::Http::ResponseWriter &response) = 0;
virtual void {{operationIdSnakeCase}}({{#allParams}}const {{#isModel}}{{modelNamespace}}::{{/isModel}}{{{dataType}}} &{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}Pistache::Http::ResponseWriter &response) = 0;
{{/vendorExtensions.x-codegen-pistache-is-parsing-supported}}
{{^vendorExtensions.x-codegen-pistache-is-parsing-supported}}
virtual void {{operationIdSnakeCase}}(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter &response) = 0;
@ -63,9 +72,7 @@ private:
};
{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}
} // namespace {{apiNamespace}}
#endif /* {{classname}}_H_ */

View File

@ -22,17 +22,16 @@
{{#imports}}{{{import}}}
{{/imports}}
{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}
namespace {{apiNamespace}}
{
{{#hasModelImport}}
using namespace {{modelNamespace}};{{/hasModelImport}}
class {{classname}}Impl : public {{apiNamespace}}::{{classname}} {
public:
{{classname}}Impl(std::shared_ptr<Pistache::Rest::Router>);
~{{classname}}Impl() {}
explicit {{classname}}Impl(const std::shared_ptr<Pistache::Rest::Router>& rtr);
~{{classname}}Impl() override = default;
{{#operation}}
{{#vendorExtensions.x-codegen-pistache-is-parsing-supported}}
@ -45,11 +44,9 @@ public:
};
{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}
} // namespace {{apiNamespace}}
{{/operations}}
#endif
#endif

View File

@ -10,9 +10,10 @@ namespace {{this}} {
{{#hasModelImport}}
using namespace {{modelNamespace}};{{/hasModelImport}}
{{classname}}Impl::{{classname}}Impl(std::shared_ptr<Pistache::Rest::Router> rtr)
{{classname}}Impl::{{classname}}Impl(const std::shared_ptr<Pistache::Rest::Router>& rtr)
: {{classname}}(rtr)
{ }
{
}
{{#operation}}
{{#vendorExtensions.x-codegen-pistache-is-parsing-supported}}
@ -31,4 +32,4 @@ void {{classname}}Impl::{{operationIdSnakeCase}}(const Pistache::Rest::Request &
}
{{/apiNamespaceDeclarations}}
{{/operations}}
{{/operations}}

View File

@ -4,16 +4,18 @@
#include "{{classname}}.h"
#include "{{prefix}}Helpers.h"
{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}
namespace {{apiNamespace}}
{
using namespace {{helpersNamespace}};
{{#hasModelImport}}
using namespace {{modelNamespace}};{{/hasModelImport}}
{{classname}}::{{classname}}(std::shared_ptr<Pistache::Rest::Router> rtr) {
router = rtr;
const std::string {{classname}}::base = "{{basePathWithoutHost}}";
{{classname}}::{{classname}}(const std::shared_ptr<Pistache::Rest::Router>& rtr)
: router(rtr)
{
}
void {{classname}}::init() {
@ -31,8 +33,26 @@ void {{classname}}::setupRoutes() {
router->addCustomHandler(Routes::bind(&{{classname}}::{{classnameSnakeLowerCase}}_default_handler, this));
}
std::pair<Pistache::Http::Code, std::string> {{classname}}::handleParsingException(const std::exception& ex) const noexcept
{
try {
throw ex;
} catch (nlohmann::detail::exception &e) {
return std::make_pair(Pistache::Http::Code::Bad_Request, e.what());
} catch ({{helpersNamespace}}::ValidationException &e) {
return std::make_pair(Pistache::Http::Code::Bad_Request, e.what());
}
}
std::pair<Pistache::Http::Code, std::string> {{classname}}::handleOperationException(const std::exception& ex) const noexcept
{
return std::make_pair(Pistache::Http::Code::Internal_Server_Error, ex.what());
}
{{#operation}}
void {{classname}}::{{operationIdSnakeCase}}_handler(const Pistache::Rest::Request &{{#hasParams}}request{{/hasParams}}, Pistache::Http::ResponseWriter response) {
try {
{{#vendorExtensions.x-codegen-pistache-is-parsing-supported}}
{{#hasPathParams}}
// Getting the path params
@ -71,32 +91,40 @@ void {{classname}}::{{operationIdSnakeCase}}_handler(const Pistache::Rest::Reque
{{#hasBodyParam}}
{{#bodyParam}}
{{^isPrimitiveType}}
nlohmann::json::parse(request.body()).get_to({{paramName}});
nlohmann::json::parse(request.body()).get_to({{paramName}});
{{paramName}}.validate();
{{/isPrimitiveType}}
{{#isPrimitiveType}}
{{paramName}} = request.body();
{{paramName}} = request.body();
{{/isPrimitiveType}}
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleParsingException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
try {
{{/bodyParam}}
{{/hasBodyParam}}
this->{{operationIdSnakeCase}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}response);
this->{{operationIdSnakeCase}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}response);
{{/vendorExtensions.x-codegen-pistache-is-parsing-supported}}
{{^vendorExtensions.x-codegen-pistache-is-parsing-supported}}
try {
this->{{operationIdSnakeCase}}(request, response);
{{/vendorExtensions.x-codegen-pistache-is-parsing-supported}}
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
{{/operation}}
@ -104,8 +132,6 @@ void {{classname}}::{{classnameSnakeLowerCase}}_default_handler(const Pistache::
response.send(Pistache::Http::Code::Not_Found, "The requested method does not exist");
}
{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}
} // namespace {{apiNamespace}}
{{/operations}}

View File

@ -14,16 +14,80 @@
#include <vector>
#include <map>
{{#helpersNamespaceDeclarations}}
namespace {{this}} {
{{/helpersNamespaceDeclarations}}
namespace {{helpersNamespace}}
{
class ValidationException : public std::runtime_error
{
public:
explicit ValidationException(const std::string& what)
: std::runtime_error(what)
{ }
~ValidationException() override = default;
};
/// <summary>
/// Validate a string against the full-date definition of RFC 3339, section 5.6.
/// </summary>
bool validateRfc3339_date(const std::string& str);
/// <summary>
/// Validate a string against the date-time definition of RFC 3339, section 5.6.
/// </summary>
bool validateRfc3339_date_time(const std::string& str);
namespace sfinae_helpers
{
struct NoType {};
template <typename T1, typename T2> NoType operator==(const T1&, const T2&);
template <typename T1, typename T2> class EqualsOperatorAvailable
{
public:
enum
{
value = !std::is_same< decltype(std::declval<T1>() == std::declval<T2>()), NoType >::value
};
};
} // namespace sfinae_helpers
/// <summary>
/// Determine if the given vector<T> only has unique elements. T must provide the == operator.
/// </summary>
template <typename T>
bool hasOnlyUniqueItems(const std::vector<T>& vec)
{
static_assert(sfinae_helpers::EqualsOperatorAvailable<T, T>::value,
"hasOnlyUniqueItems<T> cannot be called, passed template type does not provide == operator.");
if (vec.size() <= 1)
{
return true;
}
// Compare every element of vec to every other element of vec.
// This isn't an elegant way to do this, since it's O(n^2),
// but it's the best solution working only with the == operator.
// This could be greatly improved if our models provided a valid hash
// and/or the < operator
for (size_t i = 0; i < vec.size() - 1; i++)
{
for (size_t j = i + 1; j < vec.size(); j++)
{
if (vec[i] == vec[j])
{
return false;
}
}
}
return true;
}
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);
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);
@ -57,8 +121,6 @@ namespace {{this}} {
return fromStringValue(inStrings, value);
}
{{#helpersNamespaceDeclarations}}
}
{{/helpersNamespaceDeclarations}}
} // namespace {{helpersNamespace}}
#endif // {{prefix}}Helpers_H_
#endif // {{prefix}}Helpers_H_

View File

@ -1,32 +1,74 @@
{{>licenseInfo}}
#include "{{prefix}}Helpers.h"
#include <regex>
{{#helpersNamespaceDeclarations}}
namespace {{this}} {
{{/helpersNamespaceDeclarations}}
namespace {{helpersNamespace}}
{
const std::regex regexRfc3339_date(R"(^(\d{4})\-(\d{2})\-(\d{2})$)");
const std::regex regexRfc3339_date_time(
R"(^(\d{4})\-(\d{2})\-(\d{2})[Tt](\d{2}):(\d{2}):(\d{2})(\.\d+)?([Zz]|([\+\-])(\d{2}):(\d{2}))$)"
);
namespace
{
// Determine if given year is a leap year
// See RFC 3339, Appendix C https://tools.ietf.org/html/rfc3339#appendix-C
bool isLeapYear(const uint16_t year) {
return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
}
bool validateDateValues(const uint16_t year, const uint16_t month, const uint16_t day) {
return !(
(month == 0 || month > 12)
|| (day == 0)
|| (month == 2 && day > (28 + (isLeapYear(year) ? 1 : 0)))
|| (month <= 7 && day > (30 + month % 2))
|| (month >= 8 && day > (31 - month % 2))
);
}
bool validateTimeValues(const uint16_t hours, const uint16_t minutes, const uint16_t seconds) {
return (hours <= 23) && (minutes <= 59) && (seconds <= 60);
}
}
bool validateRfc3339_date(const std::string& str) {
std::smatch match;
const bool found = std::regex_search(str, match, regexRfc3339_date);
return found && validateDateValues(std::stoi(match[1]), std::stoi(match[2]), std::stoi(match[3]));
}
bool validateRfc3339_date_time(const std::string& str) {
std::smatch match;
const bool found = std::regex_search(str, match, regexRfc3339_date_time);
return found
&& validateDateValues(std::stoi(match[1]), std::stoi(match[2]), std::stoi(match[3]))
&& validateTimeValues(std::stoi(match[4]), std::stoi(match[5]), std::stoi(match[6]));
}
std::string toStringValue(const std::string &value){
return std::string(value);
}
std::string toStringValue(const int32_t &value){
std::string toStringValue(const int32_t value){
return std::to_string(value);
}
std::string toStringValue(const int64_t &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 bool value){
return value ? std::string("true") : std::string("false");
}
std::string toStringValue(const float &value){
std::string toStringValue(const float value){
return std::to_string(value);
}
std::string toStringValue(const double &value){
std::string toStringValue(const double value){
return std::to_string(value);
}
@ -56,9 +98,15 @@ bool fromStringValue(const std::string &inStr, int64_t &value){
}
bool fromStringValue(const std::string &inStr, bool &value){
bool result = true;
inStr == "true"?value = true: inStr == "false"?value = false: result = false;
return result;
if (inStr == "true") {
value = true;
return true;
}
if (inStr == "false") {
value = false;
return true;
}
return false;
}
bool fromStringValue(const std::string &inStr, float &value){
@ -81,6 +129,4 @@ bool fromStringValue(const std::string &inStr, double &value){
return true;
}
{{#helpersNamespaceDeclarations}}
}
{{/helpersNamespaceDeclarations}}
} // namespace {{helpersNamespace}}

View File

@ -13,9 +13,8 @@
{{/imports}}
#include <nlohmann/json.hpp>
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
namespace {{modelNamespace}}
{
/// <summary>
/// {{description}}
@ -24,7 +23,7 @@ class {{declspec}} {{classname}}
{
public:
{{classname}}();
virtual ~{{classname}}();
virtual ~{{classname}}() = default;
{{#isEnum}}{{#allowableValues}}
enum class e{{classname}} {
// To have a valid default value.
@ -35,7 +34,20 @@ public:
{{{name}}}{{^-last}}, {{/-last}}
{{/enumVars}}
};{{/allowableValues}}{{/isEnum}}
void validate();
/// <summary>
/// Validate the current data in the model. Throws a ValidationException on failure.
/// </summary>
void validate() const;
/// <summary>
/// Validate the current data in the model. Returns false on error and writes an error
/// message into the given stringstream.
/// </summary>
bool validate(std::stringstream& msg) const;
bool operator==(const {{classname}}& rhs) const;
bool operator!=(const {{classname}}& rhs) const;
/////////////////////////////////////////////
/// {{classname}} members
@ -44,7 +56,7 @@ public:
/// <summary>
/// {{description}}
/// </summary>
{{{dataType}}}{{#isContainer}}&{{/isContainer}} {{getter}}(){{^isContainer}} const{{/isContainer}};
{{{dataType}}} {{getter}}() const;
void {{setter}}({{{dataType}}} const{{^isPrimitiveType}}&{{/isPrimitiveType}} value);{{^required}}
bool {{nameInCamelCase}}IsSet() const;
void unset{{name}}();{{/required}}
@ -65,11 +77,12 @@ protected:
{{#isEnum}}
{{classname}}::e{{classname}} m_value = {{classname}}::e{{classname}}::INVALID_VALUE_OPENAPI_GENERATED;
{{/isEnum}}
// Helper overload for validate. Used when one model stores another model and calls it's validate.
bool validate(std::stringstream& msg, const std::string& pathPrefix) const;
};
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}
} // namespace {{modelNamespace}}
#endif /* {{classname}}_H_ */
{{/model}}

View File

@ -2,12 +2,12 @@
{{#models}}{{#model}}
#include "{{classname}}.h"
{{#isEnum}}#include <stdexcept>
#include <sstream>{{/isEnum}}
#include "{{prefix}}Helpers.h"
{{#isEnum}}#include <stdexcept>{{/isEnum}}
#include <sstream>
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
namespace {{modelNamespace}}
{
{{classname}}::{{classname}}()
{
@ -18,13 +18,69 @@ namespace {{this}} {
{{/required}}{{/vars}}
}
{{classname}}::~{{classname}}()
void {{classname}}::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw {{helpersNamespace}}::ValidationException(msg.str());
}
}
void {{classname}}::validate()
bool {{classname}}::validate(std::stringstream& msg) const
{
// TODO: implement validation
return validate(msg, "");
}
bool {{classname}}::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "{{classname}}" : pathPrefix;
{{#isEnum}}{{! Special case for enum types }}
if (m_value == {{classname}}::e{{classname}}::INVALID_VALUE_OPENAPI_GENERATED)
{
success = false;
msg << _pathPrefix << ": has no value;";
}
{{/isEnum}}
{{^isEnum}}
{{#vars}}
{{#isArray}} {{! Always generate validation body for array types }}
{{^required}}if ({{nameInCamelCase}}IsSet()){{/required}}
{{#required}}/* {{name}} */ {{/required}}{
const {{{dataType}}}& value = m_{{name}};
const std::string currentValuePath = _pathPrefix + ".{{nameInCamelCase}}";
{{> model-validation-body }}
}
{{/isArray}}{{^isArray}}{{#hasValidation}} {{! Only generate validation if necessary }}
{{^required}}if ({{nameInCamelCase}}IsSet()){{/required}}
{{#required}}/* {{name}} */ {{/required}}{
const {{{dataType}}}& value = m_{{name}};
const std::string currentValuePath = _pathPrefix + ".{{nameInCamelCase}}";
{{> model-validation-body }}
}
{{/hasValidation}}{{/isArray}}
{{/vars}}
{{/isEnum}}
return success;
}
bool {{classname}}::operator==(const {{classname}}& rhs) const
{
return
{{#isEnum}}getValue() == rhs.getValue(){{/isEnum}}
{{^isEnum}}{{#vars}}
{{#required}}({{getter}}() == rhs.{{getter}}()){{/required}}
{{^required}}((!{{nameInCamelCase}}IsSet() && !rhs.{{nameInCamelCase}}IsSet()) || ({{nameInCamelCase}}IsSet() && rhs.{{nameInCamelCase}}IsSet() && {{getter}}() == rhs.{{getter}}())){{/required}}{{^-last}} &&{{/-last}}
{{/vars}}{{/isEnum}}
;
}
bool {{classname}}::operator!=(const {{classname}}& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const {{classname}}& o)
@ -74,7 +130,7 @@ void from_json(const nlohmann::json& j, {{classname}}& o)
{{/enumVars}}{{/allowableValues}}{{/isEnum}}
}
{{#vars}}{{{dataType}}}{{#isContainer}}&{{/isContainer}} {{classname}}::{{getter}}(){{^isContainer}} const{{/isContainer}}
{{#vars}}{{{dataType}}} {{classname}}::{{getter}}() const
{
return m_{{name}};
}
@ -102,9 +158,7 @@ void {{classname}}::setValue({{classname}}::e{{classname}} value)
m_value = value;
}{{/isEnum}}
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}
} // namespace {{modelNamespace}}
{{/model}}
{{/models}}

View File

@ -14,9 +14,8 @@
#include <nlohmann/json.hpp>
{{#hasOptional}}#include <pistache/optional.h>{{/hasOptional}}
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
namespace {{modelNamespace}}
{
struct {{classname}}
{
@ -34,9 +33,9 @@ struct {{classname}}
void to_json(nlohmann::json& j, const {{classname}}& o);
void from_json(const nlohmann::json& j, {{classname}}& o);
{{#modelNamespaceDeclarations}}
} // {{this}}
{{/modelNamespaceDeclarations}}
} // namespace {{modelNamespace}}
#endif /* {{classname}}_H_ */
{{/model}}

View File

@ -3,9 +3,8 @@
#include "{{classname}}.h"
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
namespace {{modelNamespace}}
{
nlohmann::json {{classname}}::to_json() const
{
@ -51,9 +50,7 @@ void from_json(const nlohmann::json& j, {{classname}}& o)
{{/vars}}
}
{{#modelNamespaceDeclarations}}
} // {{this}}
{{/modelNamespaceDeclarations}}
} // namespace {{modelNamespace}}
{{/model}}
{{/models}}

View File

@ -0,0 +1,124 @@
{{!
This template generates the validation logic for a model.
This template file calls itself recursively for arrays.
}}
{{! Check for eunm properties that are their own schema }}
{{! These are in their own class with a validate function, the way to check for this is quite a hack
since isEnum, isString and isModel are all false. }}
{{^isString}}{{#allowableValues.enumVars.0.value}}
success = value.validate(msg, currentValuePath) && success;
{{/allowableValues.enumVars.0.value}}{{/isString}}
{{#isModel}}success = value.validate(msg, currentValuePath + ".{{nameInCamelCase}}") && success;{{/isModel}}
{{! Date validation }}
{{#isDate}}
if (!{{helpersNamespace}}::validateRfc3339_date(value))
{
success = false;
msg << currentValuePath << ": must be a valid RFC 3339 date-full string;";
}
{{/isDate}}
{{! Date-Time validation }}
{{#isDateTime}}
if (!{{helpersNamespace}}::validateRfc3339_date_time(value))
{
success = false;
msg << currentValuePath << ": must be a valid RFC 3339 date-time string;";
}
{{/isDateTime}}
{{! string validation }}
{{#isString}}
{{#minLength}}
if (value.length() < {{minLength}})
{
success = false;
msg << currentValuePath << ": must be at least {{minLength}} characters long;";
}
{{/minLength}}
{{#maxLength}}
if (value.length() > {{maxLength}})
{
success = false;
msg << currentValuePath << ": must be at most {{maxLength}} characters long;";
}
{{/maxLength}}
{{!
TODO validate regex of string using pattern variable. This has two challenges
- Is compatibility with the given regex pattern guaranteed?
- Creating the std::regex on every validation would be rather slow. Ideally one would
initialize them for the class once as a static const and use them.
}}
{{! string encoded enum validation }}
{{#isEnum}}
{{#allowableValues}}
if ({{#enumVars}}
value != "{{value}}"{{^-last}} &&{{/-last}}{{/enumVars}}
) {
success = false;
msg << currentValuePath << ": has invalid value \"" << value << "\";";
}
{{/allowableValues}}
{{/isEnum}}
{{/isString}}
{{! numeric validation }}
{{#isNumeric}}
{{#minimum}}
if (value <{{#exclusiveMinimum}}={{/exclusiveMinimum}} {{#isFloat}}static_cast<float>({{/isFloat}}{{minimum}}{{#isFloat}}){{/isFloat}}{{#isLong}}ll{{/isLong}})
{
success = false;
msg << currentValuePath << ": must be greater than{{^exclusiveMinimum}} or equal to{{/exclusiveMinimum}} {{minimum}};";
}
{{/minimum}}
{{#maximum}}
if (value >{{#exclusiveMaximum}}={{/exclusiveMaximum}} {{#isFloat}}static_cast<float>({{/isFloat}}{{maximum}}{{#isFloat}}){{/isFloat}}{{#isLong}}ll{{/isLong}})
{
success = false;
msg << currentValuePath << ": must be less than{{^exclusiveMaximum}} or equal to{{/exclusiveMaximum}} {{maximum}};";
}
{{/maximum}}
{{#multipleOf}}
{{#isInteger}}if (value % {{multipleOf}}{{#isLong}}ll{{/isLong}} != 0){{/isInteger}}
{{#isFloat}}if (std::fmod(value, static_cast<float>({{multipleOf}})) != 0){{/isFloat}}
{{#isDouble}}if (std::fmod(value, {{multipleOf}}) != 0){{/isDouble}}
{
success = false;
msg << currentValuePath << ": must be a multiple of {{multipleOf}};";
}
{{/multipleOf}}
{{/isNumeric}}
{{! Array validation }}
{{#isArray}}
{{#minItems}}
if (value.size() < {{minItems}})
{
success = false;
msg << currentValuePath << ": must have at least {{minItems}} elements;";
}
{{/minItems}}
{{#maxItems}}
if (value.size() > {{maxItems}})
{
success = false;
msg << currentValuePath << ": must have at most {{maxItems}} elements;";
}
{{/maxItems}}
{{#uniqueItems}}
if (!{{helpersNamespace}}::hasOnlyUniqueItems(value))
{
success = false;
msg << currentValuePath << ": may not contain the same item more than once;";
}
{{/uniqueItems}}
{ // Recursive validation of array elements
const std::string oldValuePath = currentValuePath;
int i = 0;
{{! the element var has the same name as the vector, so that the recursive template works - what a wonderful hack }}
for (const {{{items.dataType}}}& value : value)
{ {{! and I do a similar hack with currentValuePath... }}
const std::string currentValuePath = oldValuePath + "[" + std::to_string(i) + "]";
{{#items}}
{{> model-validation-body }} {{! Recursively apply template to array - this is where things will probbaly go wrong }}
{{/items}}
i++;
}
}
{{/isArray}}

View File

@ -1 +1 @@
5.1.0-SNAPSHOT
5.1.1-SNAPSHOT

View File

@ -13,16 +13,17 @@
#include "PetApi.h"
#include "Helpers.h"
namespace org {
namespace openapitools {
namespace server {
namespace api {
namespace org::openapitools::server::api
{
using namespace org::openapitools::server::helpers;
using namespace org::openapitools::server::model;
PetApi::PetApi(std::shared_ptr<Pistache::Rest::Router> rtr) {
router = rtr;
const std::string PetApi::base = "/v2";
PetApi::PetApi(const std::shared_ptr<Pistache::Rest::Router>& rtr)
: router(rtr)
{
}
void PetApi::init() {
@ -45,30 +46,58 @@ void PetApi::setupRoutes() {
router->addCustomHandler(Routes::bind(&PetApi::pet_api_default_handler, this));
}
std::pair<Pistache::Http::Code, std::string> PetApi::handleParsingException(const std::exception& ex) const noexcept
{
try {
throw ex;
} catch (nlohmann::detail::exception &e) {
return std::make_pair(Pistache::Http::Code::Bad_Request, e.what());
} catch (org::openapitools::server::helpers::ValidationException &e) {
return std::make_pair(Pistache::Http::Code::Bad_Request, e.what());
}
}
std::pair<Pistache::Http::Code, std::string> PetApi::handleOperationException(const std::exception& ex) const noexcept
{
return std::make_pair(Pistache::Http::Code::Internal_Server_Error, ex.what());
}
void PetApi::add_pet_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the body param
Pet body;
try {
nlohmann::json::parse(request.body()).get_to(body);
this->add_pet(body, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
nlohmann::json::parse(request.body()).get_to(body);
body.validate();
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleParsingException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
try {
this->add_pet(body, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void PetApi::delete_pet_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the path params
auto petId = request.param(":petId").as<int64_t>();
@ -76,22 +105,24 @@ void PetApi::delete_pet_handler(const Pistache::Rest::Request &request, Pistache
auto apiKey = request.headers().tryGetRaw("api_key");
try {
this->delete_pet(petId, apiKey, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
this->delete_pet(petId, apiKey, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void PetApi::find_pets_by_status_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the query params
auto statusQuery = request.query().get("status");
@ -104,22 +135,24 @@ void PetApi::find_pets_by_status_handler(const Pistache::Rest::Request &request,
}
try {
this->find_pets_by_status(status, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
this->find_pets_by_status(status, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void PetApi::find_pets_by_tags_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the query params
auto tagsQuery = request.query().get("tags");
@ -132,105 +165,118 @@ void PetApi::find_pets_by_tags_handler(const Pistache::Rest::Request &request, P
}
try {
this->find_pets_by_tags(tags, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
this->find_pets_by_tags(tags, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void PetApi::get_pet_by_id_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the path params
auto petId = request.param(":petId").as<int64_t>();
try {
this->get_pet_by_id(petId, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
this->get_pet_by_id(petId, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void PetApi::update_pet_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the body param
Pet body;
try {
nlohmann::json::parse(request.body()).get_to(body);
this->update_pet(body, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
nlohmann::json::parse(request.body()).get_to(body);
body.validate();
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleParsingException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
try {
this->update_pet(body, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void PetApi::update_pet_with_form_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
try {
this->update_pet_with_form(request, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void PetApi::upload_file_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
try {
this->upload_file(request, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void PetApi::pet_api_default_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
response.send(Pistache::Http::Code::Not_Found, "The requested method does not exist");
}
}
}
}
}
} // namespace org::openapitools::server::api

View File

@ -24,25 +24,22 @@
#include <pistache/http_headers.h>
#include <pistache/optional.h>
#include <utility>
#include "ApiResponse.h"
#include "Pet.h"
#include <string>
namespace org {
namespace openapitools {
namespace server {
namespace api {
using namespace org::openapitools::server::model;
namespace org::openapitools::server::api
{
class PetApi {
public:
PetApi(std::shared_ptr<Pistache::Rest::Router>);
virtual ~PetApi() {}
explicit PetApi(const std::shared_ptr<Pistache::Rest::Router>& rtr);
virtual ~PetApi() = default;
void init();
const std::string base = "/v2";
static const std::string base;
private:
void setupRoutes();
@ -57,7 +54,19 @@ private:
void upload_file_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void pet_api_default_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
std::shared_ptr<Pistache::Rest::Router> router;
const std::shared_ptr<Pistache::Rest::Router> router;
/// <summary>
/// Helper function to handle unexpected Exceptions during Parameter parsing and validation.
/// May be overriden to return custom error formats.
/// </summary>
virtual std::pair<Pistache::Http::Code, std::string> handleParsingException(const std::exception& ex) const noexcept;
/// <summary>
/// Helper function to handle unexpected Exceptions during processing of the request in handler functions.
/// May be overriden to return custom error formats.
/// </summary>
virtual std::pair<Pistache::Http::Code, std::string> handleOperationException(const std::exception& ex) const noexcept;
/// <summary>
/// Add a new pet to the store
@ -66,8 +75,7 @@ private:
///
/// </remarks>
/// <param name="body">Pet object that needs to be added to the store</param>
virtual void add_pet(const Pet &body, Pistache::Http::ResponseWriter &response) = 0;
virtual void add_pet(const org::openapitools::server::model::Pet &body, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Deletes a pet
/// </summary>
@ -77,7 +85,6 @@ private:
/// <param name="petId">Pet id to delete</param>
/// <param name="apiKey"> (optional, default to &quot;&quot;)</param>
virtual void delete_pet(const int64_t &petId, const Pistache::Optional<Pistache::Http::Header::Raw> &apiKey, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Finds Pets by status
/// </summary>
@ -86,7 +93,6 @@ private:
/// </remarks>
/// <param name="status">Status values that need to be considered for filter</param>
virtual void find_pets_by_status(const Pistache::Optional<std::vector<std::string>> &status, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Finds Pets by tags
/// </summary>
@ -95,7 +101,6 @@ private:
/// </remarks>
/// <param name="tags">Tags to filter by</param>
virtual void find_pets_by_tags(const Pistache::Optional<std::vector<std::string>> &tags, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Find pet by ID
/// </summary>
@ -104,7 +109,6 @@ private:
/// </remarks>
/// <param name="petId">ID of pet to return</param>
virtual void get_pet_by_id(const int64_t &petId, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Update an existing pet
/// </summary>
@ -112,8 +116,7 @@ private:
///
/// </remarks>
/// <param name="body">Pet object that needs to be added to the store</param>
virtual void update_pet(const Pet &body, Pistache::Http::ResponseWriter &response) = 0;
virtual void update_pet(const org::openapitools::server::model::Pet &body, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Updates a pet in the store with form data
/// </summary>
@ -121,7 +124,6 @@ private:
///
/// </remarks>
virtual void update_pet_with_form(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// uploads an image
/// </summary>
@ -132,10 +134,7 @@ private:
};
}
}
}
}
} // namespace org::openapitools::server::api
#endif /* PetApi_H_ */

View File

@ -13,16 +13,17 @@
#include "StoreApi.h"
#include "Helpers.h"
namespace org {
namespace openapitools {
namespace server {
namespace api {
namespace org::openapitools::server::api
{
using namespace org::openapitools::server::helpers;
using namespace org::openapitools::server::model;
StoreApi::StoreApi(std::shared_ptr<Pistache::Rest::Router> rtr) {
router = rtr;
const std::string StoreApi::base = "/v2";
StoreApi::StoreApi(const std::shared_ptr<Pistache::Rest::Router>& rtr)
: router(rtr)
{
}
void StoreApi::init() {
@ -41,94 +42,123 @@ void StoreApi::setupRoutes() {
router->addCustomHandler(Routes::bind(&StoreApi::store_api_default_handler, this));
}
std::pair<Pistache::Http::Code, std::string> StoreApi::handleParsingException(const std::exception& ex) const noexcept
{
try {
throw ex;
} catch (nlohmann::detail::exception &e) {
return std::make_pair(Pistache::Http::Code::Bad_Request, e.what());
} catch (org::openapitools::server::helpers::ValidationException &e) {
return std::make_pair(Pistache::Http::Code::Bad_Request, e.what());
}
}
std::pair<Pistache::Http::Code, std::string> StoreApi::handleOperationException(const std::exception& ex) const noexcept
{
return std::make_pair(Pistache::Http::Code::Internal_Server_Error, ex.what());
}
void StoreApi::delete_order_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the path params
auto orderId = request.param(":orderId").as<std::string>();
try {
this->delete_order(orderId, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
this->delete_order(orderId, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void StoreApi::get_inventory_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
try {
try {
this->get_inventory(response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
this->get_inventory(response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void StoreApi::get_order_by_id_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the path params
auto orderId = request.param(":orderId").as<int64_t>();
try {
this->get_order_by_id(orderId, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
this->get_order_by_id(orderId, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void StoreApi::place_order_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the body param
Order body;
try {
nlohmann::json::parse(request.body()).get_to(body);
this->place_order(body, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
nlohmann::json::parse(request.body()).get_to(body);
body.validate();
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleParsingException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
try {
this->place_order(body, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void StoreApi::store_api_default_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
response.send(Pistache::Http::Code::Not_Found, "The requested method does not exist");
}
}
}
}
}
} // namespace org::openapitools::server::api

View File

@ -24,25 +24,22 @@
#include <pistache/http_headers.h>
#include <pistache/optional.h>
#include <utility>
#include "Order.h"
#include <map>
#include <string>
namespace org {
namespace openapitools {
namespace server {
namespace api {
using namespace org::openapitools::server::model;
namespace org::openapitools::server::api
{
class StoreApi {
public:
StoreApi(std::shared_ptr<Pistache::Rest::Router>);
virtual ~StoreApi() {}
explicit StoreApi(const std::shared_ptr<Pistache::Rest::Router>& rtr);
virtual ~StoreApi() = default;
void init();
const std::string base = "/v2";
static const std::string base;
private:
void setupRoutes();
@ -53,7 +50,19 @@ private:
void place_order_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void store_api_default_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
std::shared_ptr<Pistache::Rest::Router> router;
const std::shared_ptr<Pistache::Rest::Router> router;
/// <summary>
/// Helper function to handle unexpected Exceptions during Parameter parsing and validation.
/// May be overriden to return custom error formats.
/// </summary>
virtual std::pair<Pistache::Http::Code, std::string> handleParsingException(const std::exception& ex) const noexcept;
/// <summary>
/// Helper function to handle unexpected Exceptions during processing of the request in handler functions.
/// May be overriden to return custom error formats.
/// </summary>
virtual std::pair<Pistache::Http::Code, std::string> handleOperationException(const std::exception& ex) const noexcept;
/// <summary>
/// Delete purchase order by ID
@ -63,7 +72,6 @@ private:
/// </remarks>
/// <param name="orderId">ID of the order that needs to be deleted</param>
virtual void delete_order(const std::string &orderId, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Returns pet inventories by status
/// </summary>
@ -71,7 +79,6 @@ private:
/// Returns a map of status codes to quantities
/// </remarks>
virtual void get_inventory(Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Find purchase order by ID
/// </summary>
@ -80,7 +87,6 @@ private:
/// </remarks>
/// <param name="orderId">ID of pet that needs to be fetched</param>
virtual void get_order_by_id(const int64_t &orderId, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Place an order for a pet
/// </summary>
@ -88,14 +94,11 @@ private:
///
/// </remarks>
/// <param name="body">order placed for purchasing the pet</param>
virtual void place_order(const Order &body, Pistache::Http::ResponseWriter &response) = 0;
virtual void place_order(const org::openapitools::server::model::Order &body, Pistache::Http::ResponseWriter &response) = 0;
};
}
}
}
}
} // namespace org::openapitools::server::api
#endif /* StoreApi_H_ */

View File

@ -13,16 +13,17 @@
#include "UserApi.h"
#include "Helpers.h"
namespace org {
namespace openapitools {
namespace server {
namespace api {
namespace org::openapitools::server::api
{
using namespace org::openapitools::server::helpers;
using namespace org::openapitools::server::model;
UserApi::UserApi(std::shared_ptr<Pistache::Rest::Router> rtr) {
router = rtr;
const std::string UserApi::base = "/v2";
UserApi::UserApi(const std::shared_ptr<Pistache::Rest::Router>& rtr)
: router(rtr)
{
}
void UserApi::init() {
@ -45,114 +46,166 @@ void UserApi::setupRoutes() {
router->addCustomHandler(Routes::bind(&UserApi::user_api_default_handler, this));
}
std::pair<Pistache::Http::Code, std::string> UserApi::handleParsingException(const std::exception& ex) const noexcept
{
try {
throw ex;
} catch (nlohmann::detail::exception &e) {
return std::make_pair(Pistache::Http::Code::Bad_Request, e.what());
} catch (org::openapitools::server::helpers::ValidationException &e) {
return std::make_pair(Pistache::Http::Code::Bad_Request, e.what());
}
}
std::pair<Pistache::Http::Code, std::string> UserApi::handleOperationException(const std::exception& ex) const noexcept
{
return std::make_pair(Pistache::Http::Code::Internal_Server_Error, ex.what());
}
void UserApi::create_user_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the body param
User body;
try {
nlohmann::json::parse(request.body()).get_to(body);
this->create_user(body, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
nlohmann::json::parse(request.body()).get_to(body);
body.validate();
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleParsingException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
try {
this->create_user(body, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void UserApi::create_users_with_array_input_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the body param
std::vector<User> body;
try {
nlohmann::json::parse(request.body()).get_to(body);
this->create_users_with_array_input(body, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
nlohmann::json::parse(request.body()).get_to(body);
body.validate();
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleParsingException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
try {
this->create_users_with_array_input(body, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void UserApi::create_users_with_list_input_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the body param
std::vector<User> body;
try {
nlohmann::json::parse(request.body()).get_to(body);
this->create_users_with_list_input(body, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
nlohmann::json::parse(request.body()).get_to(body);
body.validate();
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleParsingException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
try {
this->create_users_with_list_input(body, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void UserApi::delete_user_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the path params
auto username = request.param(":username").as<std::string>();
try {
this->delete_user(username, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
this->delete_user(username, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void UserApi::get_user_by_name_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the path params
auto username = request.param(":username").as<std::string>();
try {
this->get_user_by_name(username, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
this->get_user_by_name(username, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void UserApi::login_user_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the query params
auto usernameQuery = request.query().get("username");
@ -173,40 +226,44 @@ void UserApi::login_user_handler(const Pistache::Rest::Request &request, Pistach
}
try {
this->login_user(username, password, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
this->login_user(username, password, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void UserApi::logout_user_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
try {
try {
this->logout_user(response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
this->logout_user(response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void UserApi::update_user_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the path params
auto username = request.param(":username").as<std::string>();
@ -215,29 +272,34 @@ void UserApi::update_user_handler(const Pistache::Rest::Request &request, Pistac
User body;
try {
nlohmann::json::parse(request.body()).get_to(body);
this->update_user(username, body, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
nlohmann::json::parse(request.body()).get_to(body);
body.validate();
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleParsingException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
try {
this->update_user(username, body, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
//send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void UserApi::user_api_default_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
response.send(Pistache::Http::Code::Not_Found, "The requested method does not exist");
}
}
}
}
}
} // namespace org::openapitools::server::api

View File

@ -24,25 +24,22 @@
#include <pistache/http_headers.h>
#include <pistache/optional.h>
#include <utility>
#include "User.h"
#include <string>
#include <vector>
namespace org {
namespace openapitools {
namespace server {
namespace api {
using namespace org::openapitools::server::model;
namespace org::openapitools::server::api
{
class UserApi {
public:
UserApi(std::shared_ptr<Pistache::Rest::Router>);
virtual ~UserApi() {}
explicit UserApi(const std::shared_ptr<Pistache::Rest::Router>& rtr);
virtual ~UserApi() = default;
void init();
const std::string base = "/v2";
static const std::string base;
private:
void setupRoutes();
@ -57,7 +54,19 @@ private:
void update_user_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void user_api_default_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
std::shared_ptr<Pistache::Rest::Router> router;
const std::shared_ptr<Pistache::Rest::Router> router;
/// <summary>
/// Helper function to handle unexpected Exceptions during Parameter parsing and validation.
/// May be overriden to return custom error formats.
/// </summary>
virtual std::pair<Pistache::Http::Code, std::string> handleParsingException(const std::exception& ex) const noexcept;
/// <summary>
/// Helper function to handle unexpected Exceptions during processing of the request in handler functions.
/// May be overriden to return custom error formats.
/// </summary>
virtual std::pair<Pistache::Http::Code, std::string> handleOperationException(const std::exception& ex) const noexcept;
/// <summary>
/// Create user
@ -66,8 +75,7 @@ private:
/// This can only be done by the logged in user.
/// </remarks>
/// <param name="body">Created user object</param>
virtual void create_user(const User &body, Pistache::Http::ResponseWriter &response) = 0;
virtual void create_user(const org::openapitools::server::model::User &body, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Creates list of users with given input array
/// </summary>
@ -76,7 +84,6 @@ private:
/// </remarks>
/// <param name="body">List of user object</param>
virtual void create_users_with_array_input(const std::vector<User> &body, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Creates list of users with given input array
/// </summary>
@ -85,7 +92,6 @@ private:
/// </remarks>
/// <param name="body">List of user object</param>
virtual void create_users_with_list_input(const std::vector<User> &body, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Delete user
/// </summary>
@ -94,7 +100,6 @@ private:
/// </remarks>
/// <param name="username">The name that needs to be deleted</param>
virtual void delete_user(const std::string &username, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Get user by user name
/// </summary>
@ -103,7 +108,6 @@ private:
/// </remarks>
/// <param name="username">The name that needs to be fetched. Use user1 for testing.</param>
virtual void get_user_by_name(const std::string &username, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Logs user into the system
/// </summary>
@ -113,7 +117,6 @@ private:
/// <param name="username">The user name for login</param>
/// <param name="password">The password for login in clear text</param>
virtual void login_user(const Pistache::Optional<std::string> &username, const Pistache::Optional<std::string> &password, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Logs out current logged in user session
/// </summary>
@ -121,7 +124,6 @@ private:
///
/// </remarks>
virtual void logout_user(Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Updated user
/// </summary>
@ -130,14 +132,11 @@ private:
/// </remarks>
/// <param name="username">name that need to be deleted</param>
/// <param name="body">Updated user object</param>
virtual void update_user(const std::string &username, const User &body, Pistache::Http::ResponseWriter &response) = 0;
virtual void update_user(const std::string &username, const org::openapitools::server::model::User &body, Pistache::Http::ResponseWriter &response) = 0;
};
}
}
}
}
} // namespace org::openapitools::server::api
#endif /* UserApi_H_ */

View File

@ -19,9 +19,10 @@ namespace api {
using namespace org::openapitools::server::model;
PetApiImpl::PetApiImpl(std::shared_ptr<Pistache::Rest::Router> rtr)
PetApiImpl::PetApiImpl(const std::shared_ptr<Pistache::Rest::Router>& rtr)
: PetApi(rtr)
{ }
{
}
void PetApiImpl::add_pet(const Pet &body, Pistache::Http::ResponseWriter &response) {
response.send(Pistache::Http::Code::Ok, "Do some magic\n");

View File

@ -33,17 +33,15 @@
#include "Pet.h"
#include <string>
namespace org {
namespace openapitools {
namespace server {
namespace api {
namespace org::openapitools::server::api
{
using namespace org::openapitools::server::model;
class PetApiImpl : public org::openapitools::server::api::PetApi {
public:
PetApiImpl(std::shared_ptr<Pistache::Rest::Router>);
~PetApiImpl() {}
explicit PetApiImpl(const std::shared_ptr<Pistache::Rest::Router>& rtr);
~PetApiImpl() override = default;
void add_pet(const Pet &body, Pistache::Http::ResponseWriter &response);
void delete_pet(const int64_t &petId, const Pistache::Optional<Pistache::Http::Header::Raw> &apiKey, Pistache::Http::ResponseWriter &response);
@ -56,11 +54,8 @@ public:
};
}
}
}
}
} // namespace org::openapitools::server::api
#endif
#endif

View File

@ -19,9 +19,10 @@ namespace api {
using namespace org::openapitools::server::model;
StoreApiImpl::StoreApiImpl(std::shared_ptr<Pistache::Rest::Router> rtr)
StoreApiImpl::StoreApiImpl(const std::shared_ptr<Pistache::Rest::Router>& rtr)
: StoreApi(rtr)
{ }
{
}
void StoreApiImpl::delete_order(const std::string &orderId, Pistache::Http::ResponseWriter &response) {
response.send(Pistache::Http::Code::Ok, "Do some magic\n");

View File

@ -33,17 +33,15 @@
#include <map>
#include <string>
namespace org {
namespace openapitools {
namespace server {
namespace api {
namespace org::openapitools::server::api
{
using namespace org::openapitools::server::model;
class StoreApiImpl : public org::openapitools::server::api::StoreApi {
public:
StoreApiImpl(std::shared_ptr<Pistache::Rest::Router>);
~StoreApiImpl() {}
explicit StoreApiImpl(const std::shared_ptr<Pistache::Rest::Router>& rtr);
~StoreApiImpl() override = default;
void delete_order(const std::string &orderId, Pistache::Http::ResponseWriter &response);
void get_inventory(Pistache::Http::ResponseWriter &response);
@ -52,11 +50,8 @@ public:
};
}
}
}
}
} // namespace org::openapitools::server::api
#endif
#endif

View File

@ -19,9 +19,10 @@ namespace api {
using namespace org::openapitools::server::model;
UserApiImpl::UserApiImpl(std::shared_ptr<Pistache::Rest::Router> rtr)
UserApiImpl::UserApiImpl(const std::shared_ptr<Pistache::Rest::Router>& rtr)
: UserApi(rtr)
{ }
{
}
void UserApiImpl::create_user(const User &body, Pistache::Http::ResponseWriter &response) {
response.send(Pistache::Http::Code::Ok, "Do some magic\n");

View File

@ -33,17 +33,15 @@
#include <string>
#include <vector>
namespace org {
namespace openapitools {
namespace server {
namespace api {
namespace org::openapitools::server::api
{
using namespace org::openapitools::server::model;
class UserApiImpl : public org::openapitools::server::api::UserApi {
public:
UserApiImpl(std::shared_ptr<Pistache::Rest::Router>);
~UserApiImpl() {}
explicit UserApiImpl(const std::shared_ptr<Pistache::Rest::Router>& rtr);
~UserApiImpl() override = default;
void create_user(const User &body, Pistache::Http::ResponseWriter &response);
void create_users_with_array_input(const std::vector<User> &body, Pistache::Http::ResponseWriter &response);
@ -56,11 +54,8 @@ public:
};
}
}
}
}
} // namespace org::openapitools::server::api
#endif
#endif

View File

@ -12,11 +12,12 @@
#include "ApiResponse.h"
#include "Helpers.h"
namespace org {
namespace openapitools {
namespace server {
namespace model {
#include <sstream>
namespace org::openapitools::server::model
{
ApiResponse::ApiResponse()
{
@ -29,13 +30,52 @@ ApiResponse::ApiResponse()
}
ApiResponse::~ApiResponse()
void ApiResponse::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw org::openapitools::server::helpers::ValidationException(msg.str());
}
}
void ApiResponse::validate()
bool ApiResponse::validate(std::stringstream& msg) const
{
// TODO: implement validation
return validate(msg, "");
}
bool ApiResponse::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "ApiResponse" : pathPrefix;
return success;
}
bool ApiResponse::operator==(const ApiResponse& rhs) const
{
return
((!codeIsSet() && !rhs.codeIsSet()) || (codeIsSet() && rhs.codeIsSet() && getCode() == rhs.getCode())) &&
((!typeIsSet() && !rhs.typeIsSet()) || (typeIsSet() && rhs.typeIsSet() && getType() == rhs.getType())) &&
((!messageIsSet() && !rhs.messageIsSet()) || (messageIsSet() && rhs.messageIsSet() && getMessage() == rhs.getMessage()))
;
}
bool ApiResponse::operator!=(const ApiResponse& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const ApiResponse& o)
@ -123,8 +163,5 @@ void ApiResponse::unsetMessage()
}
}
}
}
}
} // namespace org::openapitools::server::model

View File

@ -22,10 +22,8 @@
#include <string>
#include <nlohmann/json.hpp>
namespace org {
namespace openapitools {
namespace server {
namespace model {
namespace org::openapitools::server::model
{
/// <summary>
/// Describes the result of uploading an image resource
@ -34,9 +32,22 @@ class ApiResponse
{
public:
ApiResponse();
virtual ~ApiResponse();
virtual ~ApiResponse() = default;
void validate();
/// <summary>
/// Validate the current data in the model. Throws a ValidationException on failure.
/// </summary>
void validate() const;
/// <summary>
/// Validate the current data in the model. Returns false on error and writes an error
/// message into the given stringstream.
/// </summary>
bool validate(std::stringstream& msg) const;
bool operator==(const ApiResponse& rhs) const;
bool operator!=(const ApiResponse& rhs) const;
/////////////////////////////////////////////
/// ApiResponse members
@ -72,11 +83,11 @@ protected:
bool m_TypeIsSet;
std::string m_Message;
bool m_MessageIsSet;
// Helper overload for validate. Used when one model stores another model and calls it's validate.
bool validate(std::stringstream& msg, const std::string& pathPrefix) const;
};
}
}
}
}
} // namespace org::openapitools::server::model
#endif /* ApiResponse_H_ */

View File

@ -12,11 +12,12 @@
#include "Category.h"
#include "Helpers.h"
namespace org {
namespace openapitools {
namespace server {
namespace model {
#include <sstream>
namespace org::openapitools::server::model
{
Category::Category()
{
@ -27,13 +28,48 @@ Category::Category()
}
Category::~Category()
void Category::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw org::openapitools::server::helpers::ValidationException(msg.str());
}
}
void Category::validate()
bool Category::validate(std::stringstream& msg) const
{
// TODO: implement validation
return validate(msg, "");
}
bool Category::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Category" : pathPrefix;
return success;
}
bool Category::operator==(const Category& rhs) const
{
return
((!idIsSet() && !rhs.idIsSet()) || (idIsSet() && rhs.idIsSet() && getId() == rhs.getId())) &&
((!nameIsSet() && !rhs.nameIsSet()) || (nameIsSet() && rhs.nameIsSet() && getName() == rhs.getName()))
;
}
bool Category::operator!=(const Category& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const Category& o)
@ -97,8 +133,5 @@ void Category::unsetName()
}
}
}
}
}
} // namespace org::openapitools::server::model

View File

@ -22,10 +22,8 @@
#include <string>
#include <nlohmann/json.hpp>
namespace org {
namespace openapitools {
namespace server {
namespace model {
namespace org::openapitools::server::model
{
/// <summary>
/// A category for a pet
@ -34,9 +32,22 @@ class Category
{
public:
Category();
virtual ~Category();
virtual ~Category() = default;
void validate();
/// <summary>
/// Validate the current data in the model. Throws a ValidationException on failure.
/// </summary>
void validate() const;
/// <summary>
/// Validate the current data in the model. Returns false on error and writes an error
/// message into the given stringstream.
/// </summary>
bool validate(std::stringstream& msg) const;
bool operator==(const Category& rhs) const;
bool operator!=(const Category& rhs) const;
/////////////////////////////////////////////
/// Category members
@ -63,11 +74,11 @@ protected:
bool m_IdIsSet;
std::string m_Name;
bool m_NameIsSet;
// Helper overload for validate. Used when one model stores another model and calls it's validate.
bool validate(std::stringstream& msg, const std::string& pathPrefix) const;
};
}
}
}
}
} // namespace org::openapitools::server::model
#endif /* Category_H_ */

View File

@ -10,34 +10,75 @@
* Do not edit the class manually.
*/
#include "Helpers.h"
#include <regex>
namespace org {
namespace openapitools {
namespace server {
namespace helpers {
namespace org::openapitools::server::helpers
{
const std::regex regexRfc3339_date(R"(^(\d{4})\-(\d{2})\-(\d{2})$)");
const std::regex regexRfc3339_date_time(
R"(^(\d{4})\-(\d{2})\-(\d{2})[Tt](\d{2}):(\d{2}):(\d{2})(\.\d+)?([Zz]|([\+\-])(\d{2}):(\d{2}))$)"
);
namespace
{
// Determine if given year is a leap year
// See RFC 3339, Appendix C https://tools.ietf.org/html/rfc3339#appendix-C
bool isLeapYear(const uint16_t year) {
return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
}
bool validateDateValues(const uint16_t year, const uint16_t month, const uint16_t day) {
return !(
(month == 0 || month > 12)
|| (day == 0)
|| (month == 2 && day > (28 + (isLeapYear(year) ? 1 : 0)))
|| (month <= 7 && day > (30 + month % 2))
|| (month >= 8 && day > (31 - month % 2))
);
}
bool validateTimeValues(const uint16_t hours, const uint16_t minutes, const uint16_t seconds) {
return (hours <= 23) && (minutes <= 59) && (seconds <= 60);
}
}
bool validateRfc3339_date(const std::string& str) {
std::smatch match;
const bool found = std::regex_search(str, match, regexRfc3339_date);
return found && validateDateValues(std::stoi(match[1]), std::stoi(match[2]), std::stoi(match[3]));
}
bool validateRfc3339_date_time(const std::string& str) {
std::smatch match;
const bool found = std::regex_search(str, match, regexRfc3339_date_time);
return found
&& validateDateValues(std::stoi(match[1]), std::stoi(match[2]), std::stoi(match[3]))
&& validateTimeValues(std::stoi(match[4]), std::stoi(match[5]), std::stoi(match[6]));
}
std::string toStringValue(const std::string &value){
return std::string(value);
}
std::string toStringValue(const int32_t &value){
std::string toStringValue(const int32_t value){
return std::to_string(value);
}
std::string toStringValue(const int64_t &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 bool value){
return value ? std::string("true") : std::string("false");
}
std::string toStringValue(const float &value){
std::string toStringValue(const float value){
return std::to_string(value);
}
std::string toStringValue(const double &value){
std::string toStringValue(const double value){
return std::to_string(value);
}
@ -67,9 +108,15 @@ bool fromStringValue(const std::string &inStr, int64_t &value){
}
bool fromStringValue(const std::string &inStr, bool &value){
bool result = true;
inStr == "true"?value = true: inStr == "false"?value = false: result = false;
return result;
if (inStr == "true") {
value = true;
return true;
}
if (inStr == "false") {
value = false;
return true;
}
return false;
}
bool fromStringValue(const std::string &inStr, float &value){
@ -92,7 +139,4 @@ bool fromStringValue(const std::string &inStr, double &value){
return true;
}
}
}
}
}
} // namespace org::openapitools::server::helpers

View File

@ -24,17 +24,80 @@
#include <vector>
#include <map>
namespace org {
namespace openapitools {
namespace server {
namespace helpers {
namespace org::openapitools::server::helpers
{
class ValidationException : public std::runtime_error
{
public:
explicit ValidationException(const std::string& what)
: std::runtime_error(what)
{ }
~ValidationException() override = default;
};
/// <summary>
/// Validate a string against the full-date definition of RFC 3339, section 5.6.
/// </summary>
bool validateRfc3339_date(const std::string& str);
/// <summary>
/// Validate a string against the date-time definition of RFC 3339, section 5.6.
/// </summary>
bool validateRfc3339_date_time(const std::string& str);
namespace sfinae_helpers
{
struct NoType {};
template <typename T1, typename T2> NoType operator==(const T1&, const T2&);
template <typename T1, typename T2> class EqualsOperatorAvailable
{
public:
enum
{
value = !std::is_same< decltype(std::declval<T1>() == std::declval<T2>()), NoType >::value
};
};
} // namespace sfinae_helpers
/// <summary>
/// Determine if the given vector<T> only has unique elements. T must provide the == operator.
/// </summary>
template <typename T>
bool hasOnlyUniqueItems(const std::vector<T>& vec)
{
static_assert(sfinae_helpers::EqualsOperatorAvailable<T, T>::value,
"hasOnlyUniqueItems<T> cannot be called, passed template type does not provide == operator.");
if (vec.size() <= 1)
{
return true;
}
// Compare every element of vec to every other element of vec.
// This isn't an elegant way to do this, since it's O(n^2),
// but it's the best solution working only with the == operator.
// This could be greatly improved if our models provided a valid hash
// and/or the < operator
for (size_t i = 0; i < vec.size() - 1; i++)
{
for (size_t j = i + 1; j < vec.size(); j++)
{
if (vec[i] == vec[j])
{
return false;
}
}
}
return true;
}
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);
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);
@ -68,9 +131,6 @@ namespace helpers {
return fromStringValue(inStrings, value);
}
}
}
}
}
} // namespace org::openapitools::server::helpers
#endif // Helpers_H_
#endif // Helpers_H_

View File

@ -12,11 +12,12 @@
#include "Order.h"
#include "Helpers.h"
namespace org {
namespace openapitools {
namespace server {
namespace model {
#include <sstream>
namespace org::openapitools::server::model
{
Order::Order()
{
@ -35,13 +36,64 @@ Order::Order()
}
Order::~Order()
void Order::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw org::openapitools::server::helpers::ValidationException(msg.str());
}
}
void Order::validate()
bool Order::validate(std::stringstream& msg) const
{
// TODO: implement validation
return validate(msg, "");
}
bool Order::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Order" : pathPrefix;
return success;
}
bool Order::operator==(const Order& rhs) const
{
return
((!idIsSet() && !rhs.idIsSet()) || (idIsSet() && rhs.idIsSet() && getId() == rhs.getId())) &&
((!petIdIsSet() && !rhs.petIdIsSet()) || (petIdIsSet() && rhs.petIdIsSet() && getPetId() == rhs.getPetId())) &&
((!quantityIsSet() && !rhs.quantityIsSet()) || (quantityIsSet() && rhs.quantityIsSet() && getQuantity() == rhs.getQuantity())) &&
((!shipDateIsSet() && !rhs.shipDateIsSet()) || (shipDateIsSet() && rhs.shipDateIsSet() && getShipDate() == rhs.getShipDate())) &&
((!statusIsSet() && !rhs.statusIsSet()) || (statusIsSet() && rhs.statusIsSet() && getStatus() == rhs.getStatus())) &&
((!completeIsSet() && !rhs.completeIsSet()) || (completeIsSet() && rhs.completeIsSet() && isComplete() == rhs.isComplete()))
;
}
bool Order::operator!=(const Order& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const Order& o)
@ -201,8 +253,5 @@ void Order::unsetComplete()
}
}
}
}
}
} // namespace org::openapitools::server::model

View File

@ -22,10 +22,8 @@
#include <string>
#include <nlohmann/json.hpp>
namespace org {
namespace openapitools {
namespace server {
namespace model {
namespace org::openapitools::server::model
{
/// <summary>
/// An order for a pets from the pet store
@ -34,9 +32,22 @@ class Order
{
public:
Order();
virtual ~Order();
virtual ~Order() = default;
void validate();
/// <summary>
/// Validate the current data in the model. Throws a ValidationException on failure.
/// </summary>
void validate() const;
/// <summary>
/// Validate the current data in the model. Returns false on error and writes an error
/// message into the given stringstream.
/// </summary>
bool validate(std::stringstream& msg) const;
bool operator==(const Order& rhs) const;
bool operator!=(const Order& rhs) const;
/////////////////////////////////////////////
/// Order members
@ -99,11 +110,11 @@ protected:
bool m_StatusIsSet;
bool m_Complete;
bool m_CompleteIsSet;
// Helper overload for validate. Used when one model stores another model and calls it's validate.
bool validate(std::stringstream& msg, const std::string& pathPrefix) const;
};
}
}
}
}
} // namespace org::openapitools::server::model
#endif /* Order_H_ */

View File

@ -12,11 +12,12 @@
#include "Pet.h"
#include "Helpers.h"
namespace org {
namespace openapitools {
namespace server {
namespace model {
#include <sstream>
namespace org::openapitools::server::model
{
Pet::Pet()
{
@ -30,13 +31,106 @@ Pet::Pet()
}
Pet::~Pet()
void Pet::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw org::openapitools::server::helpers::ValidationException(msg.str());
}
}
void Pet::validate()
bool Pet::validate(std::stringstream& msg) const
{
// TODO: implement validation
return validate(msg, "");
}
bool Pet::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Pet" : pathPrefix;
/* PhotoUrls */ {
const std::vector<std::string>& value = m_PhotoUrls;
const std::string currentValuePath = _pathPrefix + ".photoUrls";
{ // Recursive validation of array elements
const std::string oldValuePath = currentValuePath;
int i = 0;
for (const std::string& value : value)
{
const std::string currentValuePath = oldValuePath + "[" + std::to_string(i) + "]";
i++;
}
}
}
if (tagsIsSet())
{
const std::vector<Tag>& value = m_Tags;
const std::string currentValuePath = _pathPrefix + ".tags";
{ // Recursive validation of array elements
const std::string oldValuePath = currentValuePath;
int i = 0;
for (const Tag& value : value)
{
const std::string currentValuePath = oldValuePath + "[" + std::to_string(i) + "]";
success = value.validate(msg, currentValuePath + ".tags") && success;
i++;
}
}
}
return success;
}
bool Pet::operator==(const Pet& rhs) const
{
return
((!idIsSet() && !rhs.idIsSet()) || (idIsSet() && rhs.idIsSet() && getId() == rhs.getId())) &&
((!categoryIsSet() && !rhs.categoryIsSet()) || (categoryIsSet() && rhs.categoryIsSet() && getCategory() == rhs.getCategory())) &&
(getName() == rhs.getName())
&&
(getPhotoUrls() == rhs.getPhotoUrls())
&&
((!tagsIsSet() && !rhs.tagsIsSet()) || (tagsIsSet() && rhs.tagsIsSet() && getTags() == rhs.getTags())) &&
((!statusIsSet() && !rhs.statusIsSet()) || (statusIsSet() && rhs.statusIsSet() && getStatus() == rhs.getStatus()))
;
}
bool Pet::operator!=(const Pet& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const Pet& o)
@ -124,7 +218,7 @@ void Pet::setName(std::string const& value)
{
m_Name = value;
}
std::vector<std::string>& Pet::getPhotoUrls()
std::vector<std::string> Pet::getPhotoUrls() const
{
return m_PhotoUrls;
}
@ -132,7 +226,7 @@ void Pet::setPhotoUrls(std::vector<std::string> const& value)
{
m_PhotoUrls = value;
}
std::vector<Tag>& Pet::getTags()
std::vector<Tag> Pet::getTags() const
{
return m_Tags;
}
@ -168,8 +262,5 @@ void Pet::unsetStatus()
}
}
}
}
}
} // namespace org::openapitools::server::model

View File

@ -25,10 +25,8 @@
#include <vector>
#include <nlohmann/json.hpp>
namespace org {
namespace openapitools {
namespace server {
namespace model {
namespace org::openapitools::server::model
{
/// <summary>
/// A pet for sale in the pet store
@ -37,9 +35,22 @@ class Pet
{
public:
Pet();
virtual ~Pet();
virtual ~Pet() = default;
void validate();
/// <summary>
/// Validate the current data in the model. Throws a ValidationException on failure.
/// </summary>
void validate() const;
/// <summary>
/// Validate the current data in the model. Returns false on error and writes an error
/// message into the given stringstream.
/// </summary>
bool validate(std::stringstream& msg) const;
bool operator==(const Pet& rhs) const;
bool operator!=(const Pet& rhs) const;
/////////////////////////////////////////////
/// Pet members
@ -66,12 +77,12 @@ public:
/// <summary>
///
/// </summary>
std::vector<std::string>& getPhotoUrls();
std::vector<std::string> getPhotoUrls() const;
void setPhotoUrls(std::vector<std::string> const& value);
/// <summary>
///
/// </summary>
std::vector<Tag>& getTags();
std::vector<Tag> getTags() const;
void setTags(std::vector<Tag> const& value);
bool tagsIsSet() const;
void unsetTags();
@ -98,11 +109,11 @@ protected:
bool m_TagsIsSet;
std::string m_Status;
bool m_StatusIsSet;
// Helper overload for validate. Used when one model stores another model and calls it's validate.
bool validate(std::stringstream& msg, const std::string& pathPrefix) const;
};
}
}
}
}
} // namespace org::openapitools::server::model
#endif /* Pet_H_ */

View File

@ -12,11 +12,12 @@
#include "Tag.h"
#include "Helpers.h"
namespace org {
namespace openapitools {
namespace server {
namespace model {
#include <sstream>
namespace org::openapitools::server::model
{
Tag::Tag()
{
@ -27,13 +28,48 @@ Tag::Tag()
}
Tag::~Tag()
void Tag::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw org::openapitools::server::helpers::ValidationException(msg.str());
}
}
void Tag::validate()
bool Tag::validate(std::stringstream& msg) const
{
// TODO: implement validation
return validate(msg, "");
}
bool Tag::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Tag" : pathPrefix;
return success;
}
bool Tag::operator==(const Tag& rhs) const
{
return
((!idIsSet() && !rhs.idIsSet()) || (idIsSet() && rhs.idIsSet() && getId() == rhs.getId())) &&
((!nameIsSet() && !rhs.nameIsSet()) || (nameIsSet() && rhs.nameIsSet() && getName() == rhs.getName()))
;
}
bool Tag::operator!=(const Tag& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const Tag& o)
@ -97,8 +133,5 @@ void Tag::unsetName()
}
}
}
}
}
} // namespace org::openapitools::server::model

View File

@ -22,10 +22,8 @@
#include <string>
#include <nlohmann/json.hpp>
namespace org {
namespace openapitools {
namespace server {
namespace model {
namespace org::openapitools::server::model
{
/// <summary>
/// A tag for a pet
@ -34,9 +32,22 @@ class Tag
{
public:
Tag();
virtual ~Tag();
virtual ~Tag() = default;
void validate();
/// <summary>
/// Validate the current data in the model. Throws a ValidationException on failure.
/// </summary>
void validate() const;
/// <summary>
/// Validate the current data in the model. Returns false on error and writes an error
/// message into the given stringstream.
/// </summary>
bool validate(std::stringstream& msg) const;
bool operator==(const Tag& rhs) const;
bool operator!=(const Tag& rhs) const;
/////////////////////////////////////////////
/// Tag members
@ -63,11 +74,11 @@ protected:
bool m_IdIsSet;
std::string m_Name;
bool m_NameIsSet;
// Helper overload for validate. Used when one model stores another model and calls it's validate.
bool validate(std::stringstream& msg, const std::string& pathPrefix) const;
};
}
}
}
}
} // namespace org::openapitools::server::model
#endif /* Tag_H_ */

View File

@ -12,11 +12,12 @@
#include "User.h"
#include "Helpers.h"
namespace org {
namespace openapitools {
namespace server {
namespace model {
#include <sstream>
namespace org::openapitools::server::model
{
User::User()
{
@ -39,13 +40,72 @@ User::User()
}
User::~User()
void User::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw org::openapitools::server::helpers::ValidationException(msg.str());
}
}
void User::validate()
bool User::validate(std::stringstream& msg) const
{
// TODO: implement validation
return validate(msg, "");
}
bool User::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "User" : pathPrefix;
return success;
}
bool User::operator==(const User& rhs) const
{
return
((!idIsSet() && !rhs.idIsSet()) || (idIsSet() && rhs.idIsSet() && getId() == rhs.getId())) &&
((!usernameIsSet() && !rhs.usernameIsSet()) || (usernameIsSet() && rhs.usernameIsSet() && getUsername() == rhs.getUsername())) &&
((!firstNameIsSet() && !rhs.firstNameIsSet()) || (firstNameIsSet() && rhs.firstNameIsSet() && getFirstName() == rhs.getFirstName())) &&
((!lastNameIsSet() && !rhs.lastNameIsSet()) || (lastNameIsSet() && rhs.lastNameIsSet() && getLastName() == rhs.getLastName())) &&
((!emailIsSet() && !rhs.emailIsSet()) || (emailIsSet() && rhs.emailIsSet() && getEmail() == rhs.getEmail())) &&
((!passwordIsSet() && !rhs.passwordIsSet()) || (passwordIsSet() && rhs.passwordIsSet() && getPassword() == rhs.getPassword())) &&
((!phoneIsSet() && !rhs.phoneIsSet()) || (phoneIsSet() && rhs.phoneIsSet() && getPhone() == rhs.getPhone())) &&
((!userStatusIsSet() && !rhs.userStatusIsSet()) || (userStatusIsSet() && rhs.userStatusIsSet() && getUserStatus() == rhs.getUserStatus()))
;
}
bool User::operator!=(const User& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const User& o)
@ -253,8 +313,5 @@ void User::unsetUserStatus()
}
}
}
}
}
} // namespace org::openapitools::server::model

View File

@ -22,10 +22,8 @@
#include <string>
#include <nlohmann/json.hpp>
namespace org {
namespace openapitools {
namespace server {
namespace model {
namespace org::openapitools::server::model
{
/// <summary>
/// A User who is purchasing from the pet store
@ -34,9 +32,22 @@ class User
{
public:
User();
virtual ~User();
virtual ~User() = default;
void validate();
/// <summary>
/// Validate the current data in the model. Throws a ValidationException on failure.
/// </summary>
void validate() const;
/// <summary>
/// Validate the current data in the model. Returns false on error and writes an error
/// message into the given stringstream.
/// </summary>
bool validate(std::stringstream& msg) const;
bool operator==(const User& rhs) const;
bool operator!=(const User& rhs) const;
/////////////////////////////////////////////
/// User members
@ -117,11 +128,11 @@ protected:
bool m_PhoneIsSet;
int32_t m_UserStatus;
bool m_UserStatusIsSet;
// Helper overload for validate. Used when one model stores another model and calls it's validate.
bool validate(std::stringstream& msg, const std::string& pathPrefix) const;
};
}
}
}
}
} // namespace org::openapitools::server::model
#endif /* User_H_ */