Configure controller paths dynamically - improves (#58)

This commit is contained in:
Leonid Stryzhevskyi 2022-08-28 01:09:52 +03:00
parent a4e0e32398
commit 2bd4ab11ab
7 changed files with 146 additions and 37 deletions

View File

@ -98,13 +98,6 @@ message("\n#####################################################################
###################################################################################################
## define targets
set(SWAGGER_ROOT_PATH "/swagger" CACHE STRING "Default root path to the Swagger")
set(SWAGGER_UI_PATH "/ui" CACHE STRING "Default path suffix to the Swagger UI")
add_compile_definitions(
SWAGGER_ROOT_PATH="${SWAGGER_ROOT_PATH}"
SWAGGER_UI_PATH="${SWAGGER_UI_PATH}"
)
include(cmake/module-utils.cmake)
include(cmake/msvc-runtime.cmake)

View File

@ -113,14 +113,6 @@ endif()
include_directories(${oatpp_INCLUDE_DIRS})
include_directories(${oatpp-swagger_INCLUDE_DIRS})
set(SWAGGER_ROOT_PATH "/swagger" CACHE STRING "Default root path to the Swagger")
set(SWAGGER_UI_PATH "/ui" CACHE STRING "Default path suffix to the Swagger UI")
add_compile_definitions(
SWAGGER_ROOT_PATH="${SWAGGER_ROOT_PATH}"
SWAGGER_UI_PATH="${SWAGGER_UI_PATH}"
)
add_definitions(
-DOATPP_SWAGGER_RES_PATH="${OATPP_BASE_DIR}/bin/oatpp-swagger/res"
)
@ -132,4 +124,23 @@ target_link_libraries (project PUBLIC
)
```
### Customise Swagger UI Paths
To customise swagger UI endpoints paths add the following component:
```c++
/**
* Swagger Controller Paths
*/
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::swagger::ControllerPaths>, controllerPaths)([] {
auto paths = std::make_shared<oatpp::swagger::ControllerPaths>();
paths->apiJson = "custom/path/for/api.json"; // default is "api-docs/oas-3.0.0.json"
paths->ui = "my/custom/path/swagger-ui"; // default is "swagger/ui"
paths->uiResources = "my/custom/path/{filename}"; // default is "swagger/{filename}"
return paths;
}());
```
**NOTE:** `paths->ui` and `paths->uiResources` MUST have the same base path - as shown above.
**Done!**

View File

@ -39,7 +39,7 @@
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "/api-docs/oas-3.0.0.json",
url: "/%%API.JSON%%",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [

View File

@ -2,6 +2,7 @@
add_library(${OATPP_THIS_MODULE_NAME}
oatpp-swagger/AsyncController.hpp
oatpp-swagger/Controller.hpp
oatpp-swagger/ControllerPaths.hpp
oatpp-swagger/Generator.cpp
oatpp-swagger/Generator.hpp
oatpp-swagger/Model.hpp
@ -9,8 +10,7 @@ add_library(${OATPP_THIS_MODULE_NAME}
oatpp-swagger/Resources.hpp
oatpp-swagger/Types.cpp
oatpp-swagger/Types.hpp
oatpp-swagger/oas3/Model.hpp
)
oatpp-swagger/oas3/Model.hpp)
set_target_properties(${OATPP_THIS_MODULE_NAME} PROPERTIES
CXX_STANDARD 11

View File

@ -25,9 +25,11 @@
#ifndef oatpp_swagger_AsyncController_hpp
#define oatpp_swagger_AsyncController_hpp
#include "oatpp-swagger/ControllerPaths.hpp"
#include "oatpp-swagger/Resources.hpp"
#include "oatpp-swagger/Generator.hpp"
#include "oatpp/web/protocol/http/outgoing/StreamingBody.hpp"
#include "oatpp/web/server/api/ApiController.hpp"
#include "oatpp/parser/json/mapping/ObjectMapper.hpp"
@ -51,16 +53,20 @@ namespace oatpp { namespace swagger {
class AsyncController : public oatpp::web::server::api::ApiController {
public:
typedef AsyncController __ControllerType;
public:
private:
oatpp::Object<oas3::Document> m_document;
std::shared_ptr<oatpp::swagger::Resources> m_resources;
private:
ControllerPaths m_paths;
public:
AsyncController(const std::shared_ptr<ObjectMapper>& objectMapper,
const oatpp::Object<oas3::Document>& document,
const std::shared_ptr<oatpp::swagger::Resources>& resources)
const std::shared_ptr<oatpp::swagger::Resources>& resources,
const ControllerPaths& paths)
: oatpp::web::server::api::ApiController(objectMapper)
, m_document(document)
, m_resources(resources)
, m_paths(paths)
{}
public:
@ -92,13 +98,21 @@ public:
Generator generator(generatorConfig);
auto document = generator.generateDocument(documentInfo, endpointsList);
ControllerPaths paths;
try {
auto ps = OATPP_GET_COMPONENT(std::shared_ptr<ControllerPaths>);
if(ps) paths = *ps;
} catch (std::runtime_error&) {
// DO nothing.
}
return std::make_shared<AsyncController>(objectMapper, document, resources);
return std::make_shared<AsyncController>(objectMapper, document, resources, paths);
}
#include OATPP_CODEGEN_BEGIN(ApiController)
ENDPOINT_ASYNC("GET", "/api-docs/oas-3.0.0.json", Api) {
ENDPOINT_ASYNC("GET", m_paths.apiJson, Api) {
ENDPOINT_ASYNC_INIT(Api)
@ -108,23 +122,40 @@ public:
};
ENDPOINT_ASYNC("GET", SWAGGER_ROOT_PATH SWAGGER_UI_PATH, GetUIRoot) {
ENDPOINT_ASYNC("GET", m_paths.ui, GetUIRoot) {
ENDPOINT_ASYNC_INIT(GetUIRoot)
Action act() override {
return _return(controller->createResponse(Status::CODE_200, controller->m_resources->getResource("index.html")));
std::string ui;
if(controller->m_resources->isStreaming()) {
v_char8 buffer[1024];
auto fileStream = controller->m_resources->getResourceStream("index.html");
oatpp::data::stream::BufferOutputStream s(1024);
oatpp::data::stream::transfer(fileStream, &s, 0, buffer, 1024);
ui = s.toString();
} else {
ui = * controller->m_resources->getResource("index.html"); // * - copy of the index.html
}
ui.replace(ui.find("%%API.JSON%%"), 12, controller->m_paths.apiJson);
return _return(controller->createResponse(Status::CODE_200, ui));
}
};
ENDPOINT_ASYNC("GET", SWAGGER_ROOT_PATH "/{filename}", GetUIResource) {
ENDPOINT_ASYNC("GET", m_paths.uiResources, GetUIResource) {
ENDPOINT_ASYNC_INIT(GetUIResource)
Action act() override {
auto filename = request->getPathVariable("filename");
OATPP_ASSERT_HTTP(filename, Status::CODE_400, "filename should not be null")
if(controller->m_resources->isStreaming()) {
auto body = std::make_shared<oatpp::web::protocol::http::outgoing::StreamingBody>(
controller->m_resources->getResourceStream(filename->c_str())
);
return _return(OutgoingResponse::createShared(Status::CODE_200, body));
}
return _return(controller->createResponse(Status::CODE_200, controller->m_resources->getResource(filename->c_str())));
}

View File

@ -25,6 +25,7 @@
#ifndef oatpp_swagger_Controller_hpp
#define oatpp_swagger_Controller_hpp
#include "oatpp-swagger/ControllerPaths.hpp"
#include "oatpp-swagger/Resources.hpp"
#include "oatpp-swagger/Generator.hpp"
@ -53,13 +54,17 @@ class Controller : public oatpp::web::server::api::ApiController {
private:
oatpp::Object<oas3::Document> m_document;
std::shared_ptr<oatpp::swagger::Resources> m_resources;
private:
ControllerPaths m_paths;
public:
Controller(const std::shared_ptr<ObjectMapper>& objectMapper,
const oatpp::Object<oas3::Document>& document,
const std::shared_ptr<oatpp::swagger::Resources>& resources)
const std::shared_ptr<oatpp::swagger::Resources>& resources,
const ControllerPaths& paths)
: oatpp::web::server::api::ApiController(objectMapper)
, m_document(document)
, m_resources(resources)
, m_paths(paths)
{}
public:
@ -85,33 +90,46 @@ public:
std::shared_ptr<Generator::Config> generatorConfig;
try {
generatorConfig = OATPP_GET_COMPONENT(std::shared_ptr<Generator::Config>);
} catch (std::runtime_error e) {
} catch (std::runtime_error&) {
generatorConfig = std::make_shared<Generator::Config>();
}
Generator generator(generatorConfig);
auto document = generator.generateDocument(documentInfo, endpointsList);
return std::make_shared<Controller>(objectMapper, document, resources);
ControllerPaths paths;
try {
auto ps = OATPP_GET_COMPONENT(std::shared_ptr<ControllerPaths>);
if(ps) paths = *ps;
} catch (std::runtime_error&) {
// DO nothing.
}
return std::make_shared<Controller>(objectMapper, document, resources, paths);
}
#include OATPP_CODEGEN_BEGIN(ApiController)
ENDPOINT("GET", "/api-docs/oas-3.0.0.json", api) {
ENDPOINT("GET", m_paths.apiJson, api) {
return createDtoResponse(Status::CODE_200, m_document);
}
ENDPOINT("GET", SWAGGER_ROOT_PATH SWAGGER_UI_PATH, getUIRoot) {
ENDPOINT("GET", m_paths.ui, getUIRoot) {
std::string ui;
if(m_resources->isStreaming()) {
auto body = std::make_shared<oatpp::web::protocol::http::outgoing::StreamingBody>(
m_resources->getResourceStream("index.html")
);
return OutgoingResponse::createShared(Status::CODE_200, body);
v_char8 buffer[1024];
auto fileStream = m_resources->getResourceStream("index.html");
oatpp::data::stream::BufferOutputStream s(1024);
oatpp::data::stream::transfer(fileStream, &s, 0, buffer, 1024);
ui = s.toString();
} else {
ui = *m_resources->getResource("index.html"); // * - copy of the index.html
}
return createResponse(Status::CODE_200, m_resources->getResource("index.html"));
ui.replace(ui.find("%%API.JSON%%"), 12, m_paths.apiJson);
return createResponse(Status::CODE_200, ui);
}
ENDPOINT("GET", SWAGGER_ROOT_PATH "/{filename}", getUIResource, PATH(String, filename)) {
ENDPOINT("GET", m_paths.uiResources, getUIResource, PATH(String, filename)) {
if(m_resources->isStreaming()) {
auto body = std::make_shared<oatpp::web::protocol::http::outgoing::StreamingBody>(
m_resources->getResourceStream(filename->c_str())

View File

@ -0,0 +1,56 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi, <lganzzzo@gmail.com>
*
* 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.
*
***************************************************************************/
#ifndef oatpp_swagger_ControllerPaths_hpp
#define oatpp_swagger_ControllerPaths_hpp
#include "oatpp/core/Types.hpp"
namespace oatpp { namespace swagger {
/**
* Swagger Controller endpoints paths.
*/
struct ControllerPaths {
/**
* Path to generated API JSON.
*/
oatpp::String apiJson = "api-docs/oas-3.0.0.json";
/**
* Path to swagger UI (index.html).
*/
oatpp::String ui = "swagger/ui";
/**
* Path to other ui resources. MUST contain `/{filename}` at the end.
*/
oatpp::String uiResources = "swagger/{filename}";
};
}}
#endif //oatpp_swagger_ControllerPaths_hpp