Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TODO]OpenAPI client/server generator #331

Open
rhard opened this issue Oct 29, 2020 · 24 comments
Open

[TODO]OpenAPI client/server generator #331

rhard opened this issue Oct 29, 2020 · 24 comments
Assignees
Labels
Enhancement New feature or request
Milestone

Comments

@rhard
Copy link

rhard commented Oct 29, 2020

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?

@lganzzzo
Copy link
Member

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

@lganzzzo lganzzzo added the Enhancement New feature or request label Oct 29, 2020
@rhard
Copy link
Author

rhard commented Oct 29, 2020

This is definitely what we want to have

This is great! Thank you!

@lganzzzo lganzzzo added this to the 1.3.0 milestone Nov 1, 2020
@lganzzzo lganzzzo changed the title OpenAPI client/server generator [TODO]OpenAPI client/server generator Nov 1, 2020
@wing328
Copy link

wing328 commented Nov 7, 2020

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.

@lganzzzo
Copy link
Member

lganzzzo commented Nov 7, 2020

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!

@wing328
Copy link

wing328 commented Nov 8, 2020

I'll see what I can do in the coming week. Will keep you posted.

@wing328
Copy link

wing328 commented Nov 9, 2020

I've created OpenAPITools/openapi-generator#7903 to start with.

@lganzzzo
Copy link
Member

lganzzzo commented Nov 9, 2020

Got it!

@marsiliano
Copy link

Hi, any update on this feature? I think this could be very useful

I started using oatpp and it's very powerful!

@makru86
Copy link

makru86 commented Nov 30, 2022

this feature is wanted in my job. Because many REST-like service providers describe interfaces with OpenAPI

@lganzzzo
Copy link
Member

lganzzzo commented Dec 9, 2022

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.

@makru86
Copy link

makru86 commented Apr 24, 2023

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.

@makru86
Copy link

makru86 commented Apr 24, 2023

@lganzzzo may i ask you to assign me to this issue on github? Or may i assign myself?

@lganzzzo
Copy link
Member

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

@lganzzzo
Copy link
Member

@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);

};

@lganzzzo lganzzzo modified the milestones: 1.3.0, 1.4.0 Apr 24, 2023
@makru86
Copy link

makru86 commented May 10, 2023

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

@makru86
Copy link

makru86 commented May 13, 2023

@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?

@lganzzzo
Copy link
Member

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

@makru86
Copy link

makru86 commented May 15, 2023

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

@makru86
Copy link

makru86 commented May 19, 2023

@lganzzzo

I think the server is mostly finished and I plan to start working on generator soon.
Remaining work for the server:

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/

@lganzzzo
Copy link
Member

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

@makru86
Copy link

makru86 commented Jun 2, 2023

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:

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

@makru86
Copy link

makru86 commented Jun 2, 2023

another examples of C++ generators can be viewed here https://github.com/OpenAPITools/openapi-generator/tree/master/samples/server/petstore

@makru86
Copy link

makru86 commented Jun 13, 2023

I just started work on the generator cpp-oatpp-server https://github.com/makru86/openapi-generator

for information, @lganzzzo .

@makru86
Copy link

makru86 commented Jun 24, 2023

I must pause work on this for couple months - other work.
Hope to finish it after.

Commented in OpenAPITools/openapi-generator#7903

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants