-
-
Notifications
You must be signed in to change notification settings - Fork 6.7k
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
[cpp-restbed] Added "out-of-the-box" functionality #4759
Conversation
* handling class dependencies * added method override to clean interfaces of ambiguity * added default values for shared pointers * fixed _name and name parameters generating the same getters and setters * updated enum handling * updated Petstore samples * updated templates for automated object generation
@AIexG thanks for the PR. Please have a look at the compilation errors. |
@wing328 as mentioned this PR requires the changes from my PR #4753, I've split them up as the PR does not contain not cpp-restbed specific changes. Edit: Should I instead delete the other PR and push it into this one? I think I had seen a checkbox to wait untill approved somewhere when I did the first PR, can't find it anywhere anymore, sorry for the inconvenience. |
...napi-generator/src/main/java/org/openapitools/codegen/languages/CppRestbedServerCodegen.java
Show resolved
Hide resolved
CIs report the compilation errors:
Let us know if you need help fixing it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine changes, but I'd change few things regarding model's members and their initialization
@@ -76,6 +76,10 @@ private: | |||
{{#allParams}}{{{dataType}}} const &{{#hasMore}}, {{/hasMore}}{{/allParams}} | |||
)> handler_{{httpMethod}}_; | |||
{{/vendorExtensions.x-codegen-otherMethods}} | |||
|
|||
{{#allParams}} | |||
{{{dataType}}} {{paramName}}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could initialize paramName with braces, so it would be
{{{dataType}}} {{paramName}}{};
which would result in:
int someParam{}
which results in initializing int as zero. This works for any type unless there are some special requirements when initializing it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could initialize paramName with braces, so it would be
{{{dataType}}} {{paramName}}{};
Edit: confused the api-header and model-header for a sec
By default there should be no special requirements on initialisation. Added in
feddd15
protected: | ||
{{#vars}} | ||
{{{dataType}}} m_{{name}}; | ||
{{/vars}} | ||
{{#vars}} | ||
{{#isEnum}} | ||
std::vector<{{{dataType}}}> m_{{enumName}}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could possibly be static const std::vector
, but that's just a suggestion (if our uses are rogue and do const_cast's then it could be better to have copies of our enums).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, makes sense.
In hindsight I could have created a member to save the value that is an actual ENUM instead, instead of keeping it as a std::string
, but that seemed just a tad easier.
{{#isEnum}} | ||
std::vector<{{{dataType}}}> m_{{enumName}}; | ||
{{/isEnum}} | ||
{{/vars}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole block could be simplified to:
{{#vars}}
{{{dataType}}} m_{{name}}{};
{{#isEnum}}
static const std::vector<{{{dataType}}}> m_{{enumName}} { {{#allowableValues}}{{#enumVars}}{{^-first}}, {{/-first}}{{{value}}}{{/enumVars}}{{/allowableValues}} };
{{/isEnum}}
{{/vars}}
and with it we could remove all initialization from model's constructor.
Note: I moved {{#isEnum}}
for shorter notation, but I'm completely fine with it being outside in a separate block.
{{/isEnum}} | ||
{{/isPrimitiveType}} | ||
{{/isContainer}} | ||
{{/vars}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of this could be removed if we use brace initialization, explained in my previous comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some schemas might contain self, cross or circular references. Which could initialize infinite objects when parsing the JSON, as objects inside members would also be initialized upon initialisation. For that reason I've decided to initialize models as obejcts when actually required in fromPropertyTree()
. Also most members will receive their {{{defaultValue}}}
if not supplied in the JSON.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some schemas might contain self, cross or circular references.
You're right, I forgot about that. I wonder if there is a requirement that self/cross/circular property cannot be set as required. Then some kind of optional class would help, but I guess we don't have such constraint.
Then I'm fine with it, I'm thinking if it's viable to implement copy/move constructors to avoid this problem with reference-copying.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if there is a requirement that self/cross/circular property cannot be set as required.
At least in the OpenAPI-Specification or in the Generator there is none. Then again the restbed generator currently doesn't validate if a passed value is writeable/readable/required.
@@ -48,6 +48,10 @@ void {{classname}}::stopService() { | |||
std::bind(&{{classname}}{{vendorExtensions.x-codegen-resourceName}}Resource::{{httpMethod}}_method_handler, this, | |||
std::placeholders::_1)); | |||
{{/vendorExtensions.x-codegen-otherMethods}} | |||
|
|||
{{#allParams}}{{#defaultValue}}{{^isListContainer}}{{paramName}} = {{{defaultValue}}}; | |||
{{/isListContainer}}{{/defaultValue}}{{^defaultValue}}{{#isModel}}{{paramName}} = std::make_shared<{{baseType}}>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason to make models std::shared_ptr
? This will cause problems with using it with no observable benefit (at least I don't see any).
Consider following yaml:
openapi: 3.0.0
info:
description: Some description
version: 0.0.1
title: Some title
tags:
- name: hello
paths:
"/there":
get:
operationId: helloThereGet
tags:
- hello
summary: Do something
responses:
200:
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/OurModel"
post:
requestBody:
description: json to deserialize then serialize
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OurModel"
operationId: helloTherePost
tags:
- hello
summary: Do something (receive)
responses:
200:
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/OurModel"
servers:
- url: http://localhost:8080
components:
schemas:
OurModel:
type: object
properties:
someints:
type: array
items:
type: integer
member:
$ref: '#/components/schemas/NestedMember'
strmem:
type: string
NestedMember:
type: object
properties:
number:
type: integer
text:
type: string
required:
- number
- text
test file:
#include <gtest/gtest.h>
#include "model/OurModel.h"
TEST(OurModel, SimpleTest)
{
using namespace org::openapitools::server::model;
OurModel model;
model.setSomeints({1, 2, 3});
auto nm = std::make_shared<NestedMember>();
nm->setNumber(10);
nm->setText("some text");
model.setMember(nm);
EXPECT_EQ((std::vector<int32_t>{1, 2, 3}), model.getSomeints()); // success
EXPECT_EQ(10, model.getMember()->getNumber()); // success
EXPECT_EQ("some text", model.getMember()->getText()); // success
OurModel copy = model;
copy.setSomeints({4, 5, 6});
copy.getMember()->setText("this modifies model->member->text too");
EXPECT_EQ((std::vector<int32_t>{1, 2, 3}), model.getSomeints()); // success
EXPECT_EQ(10, model.getMember()->getNumber()); // success
EXPECT_EQ("some text", model.getMember()->getText()); // fail, even though it got modified in other object
EXPECT_EQ((std::vector<int32_t>{4, 5, 6}), copy.getSomeints()); // success
EXPECT_EQ(10, copy.getMember()->getNumber()); // success
EXPECT_EQ("this modifies model->member->text too", copy.getMember()->getText()); // success
}
Output:
main.cpp:27: Failure
Expected equality of these values:
"some text"
model.getMember()->getText()
Which is: "this modifies model->member->text too"
I'd be fine with using shared_ptr
if every property would use it. But it's inconsistent, you can copy your model's object, modify any property except for nested models and it won't affect original object. Then you would modify nested object and it will modify any number of other objects, which probably isn't what we want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might just be due to lack of experience. I had this intentionally after it would not compile with my testing changes, seems to work just fine without. I've removed the lines in the commit ff780fa !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for not responding for 2 weeks, but I've been not using my PC recently.
I'm not exactly satisfied with this shared_ptr situation and inconsistent copying, but I guess we have to live it (since it was like that before this PR too).
Looks good to me!
CircleCI failure already fixed in the master. |
* master: (275 commits) Initial CODEOWNERS (OpenAPITools#4924) [scala] Support for Set when array has uniqueItems=true (OpenAPITools#4926) remove nodejs server samples, scripts (OpenAPITools#4919) Added ability to work with `defaultHeaders` and fixed authentication for code generated by openapi-generator for typescript-node (OpenAPITools#4896) replace petstore_api with packageName (OpenAPITools#4921) remove base_object_spec.mustache from ruby client (OpenAPITools#4918) Add an link to Ada article (OpenAPITools#4920) avoid using hardcode prefix in example (OpenAPITools#4917) [dart-dio] Fix basepath (OpenAPITools#4911) [java][client] jackson update (OpenAPITools#4907) [Swift] Minor improvements to swift 5 generator (OpenAPITools#4910) [cpp-restbed] Added "out-of-the-box" functionality (OpenAPITools#4759) New generator swift5 (OpenAPITools#4086) [dart-dio] Adds support for multipart form data post body (OpenAPITools#4797) [go][client] fix when schema have multiple servers (OpenAPITools#4901) Unables CI tests of python-flask-python2 (OpenAPITools#4889) [C-libcurl] The JSON key name in request/response body should not be escaped even though it is a C key word. (OpenAPITools#4893) upgrade to JUnit 4.13 (OpenAPITools#4899) [r] Ignoring README.md in Rbuildignore (OpenAPITools#4898) update samples ...
With those changes the cpp-restbed Codegen should generate a server which automatically stores data received through a request in objects and also creates necessary instances of objects.
The goal was to have the server compile out of the box, to offer a quick start with projects.
make_shared<Object>()
to shared pointers to allow automated object generationupdateAllModels()
to clean interfaces of ambiguityRequires the changes from my PRs #4753 and #4758.
PR checklist
./bin/
(or Windows batch scripts under.\bin\windows
) to update Petstore samples related to your fix. This is important, as CI jobs will verify all generator outputs of your HEAD commit, and these must match the expectations made by your contribution. You only need to run./bin/{LANG}-petstore.sh
,./bin/openapi3/{LANG}-petstore.sh
if updating the code or mustache templates for a language ({LANG}
) (e.g. php, ruby, python, etc).master
,4.3.x
,5.0.x
. Default:master
.Additional context
Not sure if I should commit the generated server files for the samples as well, please tell me or remove them if necessary.
Requires the changes from my PRs #4753 to compile.
First pull request(s), hopefully doing everything right!
technical committee
@ravinikam (2017/07) @stkrwork (2017/07) @etherealjoy (2018/02) @MartinDelille (2018/03) @muttleyxd (2019/08)