[TODO]OpenAPI client/server generator
First of all thank you for this great project!
Is there any plans to create REST API client/server genearator for Oatpp from OpenAPI/swagger files?
Hello @rhard ,
Thanks for writing!
Is there any plans to create REST API client/server genearator for Oatpp from OpenAPI/swagger files?
This is definitely what we want to have.
I'll prepare a list of tasks for the next milestone (1.3.0) in a few days, potentially it will be there - depends on the load and priorities. I'll update this issue.
Regards, Leonid
This is definitely what we want to have
This is great! Thank you!
Once the OpenAPI/Swagger spec is available, you may want to use OpenAPI Generator to generate API clients, server stubs, documentation, and more.
We also welcome contributions to add an Oat++ server stub generator. Let me know if anyone is interested and I can show some good starting points.
Disclosure: I'm the top contributor to OpenAPI Generator.
Hello @wing328 ,
We also welcome contributions to add an Oat++ server stub generator.
This feature is in the roadmap and already scheduled for development to be out together with the next release of Oat++. You can expect our contributions to OpenAPI Generator in the comparably near future.
Let me know if anyone is interested and I can show some good starting points.
I'm interested, it will be really helpful!
I'll see what I can do in the coming week. Will keep you posted.
I've created https://github.com/OpenAPITools/openapi-generator/pull/7903 to start with.
Got it!
Hi, any update on this feature? I think this could be very useful
I started using oatpp and it's very powerful!
this feature is wanted in my job. Because many REST-like service providers describe interfaces with OpenAPI
Hello guys,
Thanks for the comments and upvotes!
At the moment I have no free time to work on this issue. If someone is willing to contribute I will provide the necessary assistance oatpp-wise.
I am working on that issue on my free time. Hope to finish in couple of months (it is not much work, can be done in couple of weeks)
Question - would you like cpp-oatpp-server generator to generate normal or async controllers? i started with async.
creating cpp-oatpp-server generator more easy with reference project.i almost finished it. https://github.com/makru86/oatpp-petstore
check it and give a comment - i will appreciate.
@lganzzzo may i ask you to assign me to this issue on github? Or may i assign myself?
Hello @makru86 ,
I am working on that issue on my free time. Hope to finish in couple of months (it is not much work, can be done in couple of weeks)
These are great news! Please let me know in case you need any help.
Question - would you like cpp-oatpp-server generator to generate normal or async controllers? i started with async.
The Simple API is definitely a priority as it used much more often. Async API is just for some specific cases.
Regards, Leonid
@makru86 ,
https://github.com/makru86/oatpp-petstore/blob/888e08f003c7f27c8f18f94c7bbf75d700ace417/src/dto/UserDTO.hpp#L36
FYI:
For DTOs you can use DTO_HC_EQ it will define hashCode function and equals operator for objects to enable it to be stored in hash set/map. It also takes into account object hierarchy.
class UserDTO : public oatpp::DTO {
DTO_INIT(UserDTO, DTO)
DTO_FIELD(Int64, id);
DTO_FIELD(String, username);
DTO_FIELD(String, firstName);
DTO_FIELD(String, lastName);
DTO_FIELD(String, email);
DTO_FIELD(String, password);
DTO_FIELD(String, phone);
DTO_FIELD(Int32, userStatus);
DTO_HC_EQ(id, username, firstName, lastName, email, password, phone, userStatus);
};
Thanks, @lganzzzo.
I started new project with simple controllers instead of async. https://github.com/makru86/oatpp-petstore-2
Thanks for the hint to use DTO_HC_EQ.
Currently I don't have any questions. Maybe later.
I will post updates in this thread, especially when oatpp-petstore-2 is ready, before implementing generator
@lganzzzo , If you have, please share an example how to implement AuthorizationHandler for API-Key authorization scheme, with custom header name (api_key in case of petstore https://github.com/makru86/oatpp-petstore-2/blob/master/api/petstore.yaml#L623)
As I saw from examples, Basic and Bearer both use Authorization header. How to make oatpp to pass api_key header value into handleAuthorization override?
Hello @makru86 ,
It might be possible to do it like follows:
In swagger-component
auto ss = oatpp::swagger::SecurityScheme::createShared();
ss->type = "apiKey";
ss->name = "api_key";
ss->in = "header";
//ss->scheme = ???;
builder.addSecurityScheme("api_key", ss);
return builder.build();
In Endpoint
ENDPOINT_INFO(getInventory) {
auto authHandler = ApiController::getDefaultAuthorizationHandler();
if(authHandler) {
info->headers.add<oatpp::String>("api_key").description = authHandler->getScheme();
info->authorization = authHandler->getScheme();
}
}
ENDPOINT("GET", "store/inventory", getInventory,
BUNDLE(String, apiKey)) // pass auth payload as bundle from interceptor
{
...
}
In AuthInterceptor
For complete auth example with interceptor see https://github.com/oatpp/example-jwt/blob/master/src/interceptor/AuthInterceptor.cpp
auto authHeader = request->getHeader("api_key");
auto authObject = std::static_pointer_cast<MyAuthObject>(m_authHandler.handleAuthorization(authHeader));
if(authObject) {
request->putBundleData("apiKey", authObject->apiKey);
// TODO check API KEY
return nullptr; // Continue - API-KEY is valid.
}
Please let me know if this works
It works! Thanks!
D |2023-05-15 17:29:35 1684151975973748| ApiKeyInHeaderInterceptor:endpoint: GET /store/inventory
D |2023-05-15 17:29:35 1684151975973786| ApiKeyAuthHandler:authHeader: ***********
D |2023-05-15 17:29:35 1684151975973792| ApiKeyAuthHandler:allow access: uid-admin
D |2023-05-15 17:29:35 1684151975973797| ApiKeyInHeaderInterceptor:authorization granted: uid-admin
D |2023-05-15 17:29:35 1684151975973814| getInventory:apiKeyUserId=uid-admin
if(authObject) {
request->putBundleData("apiKey", authObject->apiKey);
// TODO check API KEY
return nullptr; // Continue - API-KEY is valid.
}
I did it little different - checking API key in handleAuthorization(), and bundling apiKeyUserId instead of apiKey. https://github.com/makru86/oatpp-petstore-2/blob/master/src/auth/ApiKeyAuth.hpp
@lganzzzo
I think the server is mostly finished and I plan to start working on generator soon. Remaining work for the server:
- add endpoints to the test/MyApiTestClient.hpp
- add tests for all controllers, like in https://github.com/makru86/oatpp-petstore-starter/blob/master/utility/test.sh but in C++
What do you think - maybe something is missing? Examles:
- CORS not enabled
- Swagger UI not enabled (ENDPOINT_INFOs are done partially, but project does not linked with
oatpp-swagger)
https://github.com/makru86/oatpp-petstore-starter/
Hello @makru86 ,
https://github.com/makru86/oatpp-petstore-starter/
A quick comment (https://github.com/makru86/oatpp-petstore-starter/blob/master/src/auth/ApiKeyAuth.hpp#L90): I think it's better not to explicitly list all auth-required endpoints. Instead just list non-auth endpoints and all others treat as auth-required.
What do you think - maybe something is missing?
As for the petstore example it looks great. However, as for "API first" generated project structure should be a bit different.
The general approach is that you want to have the API part to be generated separately from your business logic and then just implement interfaces provided.
So basically what you want to have is something like this:
Generated part
/**
Pet service interface
**/
class PetSerivce {
public:
virtual std::shared_ptr<OutgoingResponse> addPet(const Object<PetDTO>& body) = 0;
}
/**
Controller
**/
class PetController : public oatpp::web::server::api::ApiController {
private:
std::shared_ptr<PetService> m_service;
public:
explicit PetController(OATPP_COMPONENT(std::shared_ptr<PetService>, petService),
OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper)
, m_service(petService)
{}
ENDPOINT("POST", "/pet", addPet,
BODY_DTO(Object<PetDTO>, body))
{
return m_serivce->addPet(body);
}
};
User part
Then I can easily implement my logic by extending PetService:
class MyPetSerivce : public PetService {
public:
std::shared_ptr<OutgoingResponse> addPet(const Object<PetDTO>& body) override;
}
...
router->addController(std::make_shared<PetController>(std::make_shared<MyPetService>()));
Also, it's a good idea to have the generated part as a library with versions
Thanks for comments, @lganzzzo , It is interesting to learn Oat++ from you.
Changes:
- added tests for controllers using
MyApiTestClient - added service interfaces and implementations
- extracted a library with generated sources
- version property added to it.
Project needs to be cleaned:
- maybe merge ApiKeyInterceptor and OAuth2Interceptor
- parsing of content type 'x-www-form-urlencoded` not implemented (I saw https://github.com/oatpp/oatpp/issues/333).
Please comment if something can be improved.
About endpoint list in auth interceptor: given endpoints (https://github.com/makru86/oatpp-petstore-starter/blob/master/generated/auth/ApiKeyAuth.hpp#L90 )
m_authEndpoints.route("GET", "/user/logout", apiKeyAuth);
m_authEndpoints.route("GET", "/user/{username}", false);
I think it is unavoidable to list the first one as apiKeyAuth==true so that route GET:"/user/logout" does not match the second.
edit: library verison: https://github.com/makru86/oatpp-petstore-starter/blob/master/CMakeLists.txt#L21
edit: project layout: https://github.com/makru86/oatpp-petstore-starter/blob/master/README.md?plain=1#L67
another examples of C++ generators can be viewed here https://github.com/OpenAPITools/openapi-generator/tree/master/samples/server/petstore
I just started work on the generator cpp-oatpp-server https://github.com/makru86/openapi-generator
for information, @lganzzzo .
I must pause work on this for couple months - other work. Hope to finish it after.
Commented in https://github.com/OpenAPITools/openapi-generator/pull/7903