From ce772ca800531daaa9f0cc190e57752fad98b23d Mon Sep 17 00:00:00 2001 From: lganzzzo Date: Wed, 1 Aug 2018 01:41:55 +0300 Subject: [PATCH] OpenApi v3.0.0 generation from generic model --- Controller.hpp | 20 +---- Model.hpp | 215 +++++++++++++++++++++++++++++++++++++++++++++ oas3/Generator.cpp | 15 +++- oas3/Generator.hpp | 4 +- oas3/Model.hpp | 100 +++++++++++++++++++++ 5 files changed, 334 insertions(+), 20 deletions(-) create mode 100644 Model.hpp diff --git a/Controller.hpp b/Controller.hpp index 61eecbe..57536f8 100644 --- a/Controller.hpp +++ b/Controller.hpp @@ -47,7 +47,8 @@ protected: {} public: - static std::shared_ptr createShared(const std::shared_ptr& endpointsList){ + static std::shared_ptr createShared(const std::shared_ptr& endpointsList, + OATPP_COMPONENT(std::shared_ptr, documentInfo)){ auto serializerConfig = oatpp::parser::json::mapping::Serializer::Config::createShared(); serializerConfig->includeNullFields = false; @@ -57,20 +58,7 @@ public: auto objectMapper = oatpp::parser::json::mapping::ObjectMapper::createShared(serializerConfig, deserializerConfig); - auto info = oas3::Info::createShared(); - - info->title = "My Service Title"; - info->description = "My Service Description"; - info->version = "1.0-ver"; - - auto document = oas3::Generator::generateDocument(info, endpointsList); - - auto server = oas3::Server::createShared(); - server->url = "http://localhost:8000/"; - - auto servers = document->servers->createShared(); - servers->pushBack(server); - document->servers = servers; + auto document = oas3::Generator::generateDocument(documentInfo, endpointsList); return std::shared_ptr(new Controller(objectMapper, document)); } @@ -80,7 +68,7 @@ public: */ #include OATPP_CODEGEN_BEGIN(ApiController) - ENDPOINT("GET", "/api", api) { + ENDPOINT("GET", "/api-docs/oas-3.0.0.json", api) { return createDtoResponse(Status::CODE_200, m_document); } diff --git a/Model.hpp b/Model.hpp new file mode 100644 index 0000000..72a6fbe --- /dev/null +++ b/Model.hpp @@ -0,0 +1,215 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present, Leonid Stryzhevskyi, + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ***************************************************************************/ + +/** + * This is the general model for swagger info. It is used as a base model + * to generate API info for a particular API specification. Ex. for OAS3 + */ + +#ifndef oatpp_swagger_Config_hpp +#define oatpp_swagger_Config_hpp + +#include "oatpp/core/collection/ListMap.hpp" +#include "oatpp/core/collection/LinkedList.hpp" +#include "oatpp/core/Types.hpp" + +namespace oatpp { namespace swagger { + +struct Contact { + + static std::shared_ptr createShared() { + return std::make_shared(); + } + + String name; + String url; + String email; + +}; + +struct License { + + static std::shared_ptr createShared() { + return std::make_shared(); + } + + String name; + String url; + +}; + +struct DocumentHeader { + + static std::shared_ptr createShared() { + return std::make_shared(); + } + + String title; + String description; + String termsOfService; + std::shared_ptr contact; + std::shared_ptr license; + String version; + +}; + +struct ServerVariable { + + static std::shared_ptr createShared() { + return std::make_shared(); + } + + String description; + std::shared_ptr> enumValues; + String defaultValue; + +}; + +struct Server { + + static std::shared_ptr createShared() { + return std::make_shared(); + } + + String url; + String description; + std::shared_ptr>> variables; + +}; + +class DocumentInfo { +public: + + static std::shared_ptr createShared() { + return std::make_shared(); + } + + std::shared_ptr header; + std::shared_ptr>> servers; + + class Builder { + private: + + std::shared_ptr m_header; + std::shared_ptr>> m_servers; + + std::shared_ptr getHeader() { + if(!m_header) { + m_header = DocumentHeader::createShared(); + } + return m_header; + } + + std::shared_ptr getContact() { + auto header = getHeader(); + if(!header->contact) { + header->contact = Contact::createShared(); + } + return header->contact; + } + + std::shared_ptr getLicense() { + auto header = getHeader(); + if(!header->license) { + header->license = License::createShared(); + } + return header->license; + } + + public: + + Builder& setTitle(const oatpp::String& title) { + getHeader()->title = title; + return *this; + } + + Builder& setDescription(const oatpp::String& description) { + getHeader()->description = description; + return *this; + } + + Builder& setTermsOfService(const oatpp::String& termsOfService) { + getHeader()->termsOfService = termsOfService; + return *this; + } + + Builder& setVersion(const oatpp::String& version) { + getHeader()->version = version; + return *this; + } + + Builder& setContactName(const oatpp::String& name) { + getContact()->name = name; + return *this; + } + + Builder& setContactUrl(const oatpp::String& url) { + getContact()->url = url; + return *this; + } + + Builder& setContactEmail(const oatpp::String& email) { + getContact()->email = email; + return *this; + } + + Builder& setLicenseName(const oatpp::String& name) { + getLicense()->name = name; + return *this; + } + + Builder& setLicenseUrl(const oatpp::String& url) { + getLicense()->url = url; + return *this; + } + + Builder& addServer(const std::shared_ptr& server) { + if(!m_servers) { + m_servers = oatpp::collection::LinkedList>::createShared(); + } + m_servers->pushBack(server); + return *this; + } + + Builder& addServer(const oatpp::String& url, const oatpp::String& description) { + auto server = Server::createShared(); + server->url = url; + server->description = description; + return addServer(server); + } + + std::shared_ptr build() { + auto document = DocumentInfo::createShared(); + document->header = m_header; + document->servers = m_servers; + return document; + } + + }; + +}; + +}} + +#endif /* oatpp_swagger_Config_hpp */ diff --git a/oas3/Generator.cpp b/oas3/Generator.cpp index 8047da6..5f0ab12 100644 --- a/oas3/Generator.cpp +++ b/oas3/Generator.cpp @@ -312,10 +312,21 @@ Components::ObjectWrapper Generator::generateComponents(const UsedSchemas& usedS } -Document::ObjectWrapper Generator::generateDocument(const Info::ObjectWrapper& info, const std::shared_ptr& endpoints) { +Document::ObjectWrapper Generator::generateDocument(const std::shared_ptr& docInfo, const std::shared_ptr& endpoints) { auto document = oas3::Document::createShared(); - document->info = info; + document->info = Info::createFromBaseModel(docInfo->header); + + if(docInfo->servers) { + document->servers = document->servers->createShared(); + + auto curr = docInfo->servers->getFirstNode(); + while (curr != nullptr) { + document->servers->pushBack(Server::createFromBaseModel(curr->getData())); + curr = curr->getNext(); + } + + } UsedSchemas usedSchemas; document->paths = generatePaths(endpoints, usedSchemas); diff --git a/oas3/Generator.hpp b/oas3/Generator.hpp index 57bb390..941cc99 100644 --- a/oas3/Generator.hpp +++ b/oas3/Generator.hpp @@ -25,7 +25,7 @@ #ifndef oatpp_swagger_oas3_Generator_hpp #define oatpp_swagger_oas3_Generator_hpp -#include "./Model.hpp" +#include "oatpp-swagger/oas3/Model.hpp" #include "oatpp/web/server/api/Endpoint.hpp" #include "oatpp/core/collection/LinkedList.hpp" @@ -63,7 +63,7 @@ public: static Components::ObjectWrapper generateComponents(const UsedSchemas& usedSchemas); - static Document::ObjectWrapper generateDocument(const Info::ObjectWrapper& info, const std::shared_ptr& endpoints); + static Document::ObjectWrapper generateDocument(const std::shared_ptr& docInfo, const std::shared_ptr& endpoints); diff --git a/oas3/Model.hpp b/oas3/Model.hpp index dfce884..e6b3e55 100644 --- a/oas3/Model.hpp +++ b/oas3/Model.hpp @@ -25,6 +25,8 @@ #ifndef oatpp_swagger_oas3_Model_hpp #define oatpp_swagger_oas3_Model_hpp +#include "oatpp-swagger/Model.hpp" + #include "oatpp/core/data/mapping/type/Object.hpp" #include "oatpp/core/macro/codegen.hpp" @@ -39,6 +41,17 @@ class Contact : public oatpp::data::mapping::type::Object { DTO_FIELD(String, url); DTO_FIELD(String, email); + static ObjectWrapper createFromBaseModel(const std::shared_ptr& model) { + if(model) { + auto result = createShared(); + result->name = model->name; + result->url = model->url; + result->email = model->email; + return result; + } + return nullptr; + } + }; class License : public oatpp::data::mapping::type::Object { @@ -48,6 +61,16 @@ class License : public oatpp::data::mapping::type::Object { DTO_FIELD(String, name); DTO_FIELD(String, url); + static ObjectWrapper createFromBaseModel(const std::shared_ptr& model) { + if(model) { + auto result = createShared(); + result->name = model->name; + result->url = model->url; + return result; + } + return nullptr; + } + }; class Info : public oatpp::data::mapping::type::Object { @@ -61,13 +84,90 @@ class Info : public oatpp::data::mapping::type::Object { DTO_FIELD(License::ObjectWrapper, license); DTO_FIELD(String, version); + static ObjectWrapper createFromBaseModel(const std::shared_ptr& model) { + if(model) { + auto result = createShared(); + result->title = model->title; + result->description = model->description; + result->termsOfService = model->termsOfService; + result->contact = Contact::createFromBaseModel(model->contact); + result->license = License::createFromBaseModel(model->license); + result->version = model->version; + return result; + } + return nullptr; + } + }; +class ServerVariable : public oatpp::data::mapping::type::Object { + + DTO_INIT(ServerVariable, Object) + + DTO_FIELD(String, description); + DTO_FIELD(List::ObjectWrapper, enumValues, "enum"); + DTO_FIELD(String, defaultValue, "default"); + + static ObjectWrapper createFromBaseModel(const std::shared_ptr& model) { + + if(model) { + + auto result = createShared(); + result->description = model->description; + result->defaultValue = model->defaultValue; + + if(model->enumValues) { + + result->enumValues = List::createShared(); + + auto curr = model->enumValues->getFirstNode(); + while(curr != nullptr) { + result->enumValues->pushBack(curr->getData()); + curr = curr->getNext(); + } + + } + + return result; + + } + + return nullptr; + + } + +}; + class Server : public oatpp::data::mapping::type::Object { DTO_INIT(Server, Object) DTO_FIELD(String, url); + DTO_FIELD(String, description); + DTO_FIELD(Fields::ObjectWrapper, variables); + + static ObjectWrapper createFromBaseModel(const std::shared_ptr& model) { + if(model) { + auto result = createShared(); + result->url = model->url; + result->description = model->description; + + if(model->variables) { + + result->variables = Fields::createShared(); + + auto curr = model->variables->getFirstEntry(); + while (curr != nullptr) { + result->variables->put(curr->getKey(), ServerVariable::createFromBaseModel(curr->getValue())); + curr = curr->getNext(); + } + + } + + return result; + } + return nullptr; + } };