Skip to content

Commit

Permalink
[qt5 server] Improvement in response handling (OpenAPITools#675)
Browse files Browse the repository at this point in the history
* Remove warnings and add custom request sending

* Remove duplicate code from subclass and add missing setupRoutes

* Removed redundant override

* Add serialization of responses

* Fix CI failure

* Add inline function to duplicate code.

* Make const reference wherever possible

* Add support for Array of Primitive types.

* Add Array of Primitive support for Error response

* Update for multiple path params
  • Loading branch information
etherealjoy authored and wing328 committed Jul 30, 2018
1 parent 47269e2 commit 4706378
Show file tree
Hide file tree
Showing 33 changed files with 522 additions and 373 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.util.Set;

public class CppQt5QHttpEngineServerCodegen extends AbstractCppCodegen implements CodegenConfig {
@SuppressWarnings("unused")
private static final Logger LOGGER = LoggerFactory.getLogger(CppQt5QHttpEngineServerCodegen.class);

public static final String CPP_NAMESPACE = "cppNamespace";
Expand Down Expand Up @@ -234,7 +235,7 @@ public String getName() {
}

/**
* Returns human-friendly help for the generator. Provide the consumer with help
* Returns human-friendly help for the generator. Provide the consumer with help
* tips, parameters here
*
* @return A string value for the help message
Expand Down Expand Up @@ -262,21 +263,7 @@ public String toModelImport(String name) {

return "#include \"" + folder + name + ".h\"";
}

/**
* Escapes a reserved word as defined in the `reservedWords` array. Handle escaping
* those terms here. This logic is only called if a variable matches the reserved words
*
* @return the escaped term
*/
@Override
public String escapeReservedWord(String name) {
if (this.reservedWordsMappings().containsKey(name)) {
return this.reservedWordsMappings().get(name);
}
return "_" + name;
}


/**
* Location to write model files. You can use the modelPackage() as defined when the class is
* instantiated
Expand Down Expand Up @@ -327,6 +314,7 @@ public String toApiFilename(String name) {
* @return a string value used as the `dataType` field for model templates, `returnType` for api templates
*/
@Override
@SuppressWarnings("rawtypes")
public String getTypeDeclaration(Schema p) {
String openAPIType = getSchemaType(p);

Expand All @@ -352,6 +340,7 @@ public String getTypeDeclaration(Schema p) {
}

@Override
@SuppressWarnings("rawtypes")
public String toDefaultValue(Schema p) {
if (ModelUtils.isBooleanSchema(p)) {
return "false";
Expand Down Expand Up @@ -391,6 +380,7 @@ public String toDefaultValue(Schema p) {
* @return a string value of the type or complex model for this property
*/
@Override
@SuppressWarnings("rawtypes")
public String getSchemaType(Schema p) {
String openAPIType = super.getSchemaType(p);

Expand All @@ -409,24 +399,6 @@ public String getSchemaType(Schema p) {
return toModelName(type);
}

@Override
public String toModelName(String type) {
if (type == null) {
LOGGER.warn("Model name can't be null. Defaul to 'UnknownModel'.");
type = "UnknownModel";
}

if (typeMapping.keySet().contains(type) ||
typeMapping.values().contains(type) ||
importMapping.values().contains(type) ||
defaultIncludes.contains(type) ||
languageSpecificPrimitives.contains(type)) {
return type;
} else {
return modelNamePrefix + Character.toUpperCase(type.charAt(0)) + type.substring(1);
}
}

@Override
public String toVarName(String name) {
// sanitize name
Expand Down Expand Up @@ -455,22 +427,6 @@ public String toParamName(String name) {
return toVarName(name);
}

@Override
public String toApiName(String type) {
return modelNamePrefix + Character.toUpperCase(type.charAt(0)) + type.substring(1) + "Api";
}

@Override
public String escapeQuotationMark(String input) {
// remove " to avoid code injection
return input.replace("\"", "");
}

@Override
public String escapeUnsafeCharacters(String input) {
return input.replace("*/", "*_/").replace("/*", "/_*");
}

@Override
public String getTypeDeclaration(String str) {
return str;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{>licenseInfo}}
#ifndef _{{prefix}}_{{classname}}Handler_H_
#define _{{prefix}}_{{classname}}Handler_H_
#ifndef {{prefix}}_{{classname}}Handler_H
#define {{prefix}}_{{classname}}Handler_H

#include <QObject>

Expand Down Expand Up @@ -30,4 +30,4 @@ public slots:
}
{{/cppNamespaceDeclarations}}

#endif // _{{prefix}}_{{classname}}Handler_H_
#endif // {{prefix}}_{{classname}}Handler_H
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ namespace {{this}} {
{{/cppNamespaceDeclarations}}

{{classname}}Request::{{classname}}Request(QHttpEngine::Socket *s, {{classname}}Handler* hdl) : QObject(s), socket(s), handler(hdl) {
auto headers = s->headers();
for(auto itr = headers.begin(); itr != headers.end(); itr++) {
requestHeaders.insert(QString(itr.key()), QString(itr.value()));
}
}

{{classname}}Request::~{{classname}}Request(){
Expand All @@ -21,16 +25,23 @@ namespace {{this}} {
}

QMap<QString, QString>
{{classname}}Request::getDefaultHeaders(){
return defaultHeaders;
{{classname}}Request::getRequestHeaders() const {
return requestHeaders;
}

void {{classname}}Request::setResponseHeaders(const QMultiMap<QString, QString>& headers){
for(auto itr = headers.begin(); itr != headers.end(); ++itr) {
responseHeaders.insert(itr.key(), itr.value());
}
}


QHttpEngine::Socket* {{classname}}Request::getRawSocket(){
return socket;
}

{{#operations}}{{#operation}}
void {{classname}}Request::{{nickname}}Request({{#hasPathParams}}{{#pathParams}}QString {{{paramName}}}str{{/pathParams}}{{/hasPathParams}}){
void {{classname}}Request::{{nickname}}Request({{#hasPathParams}}{{#pathParams}}const QString& {{{paramName}}}str{{#hasMore}}, {{/hasMore}}{{/pathParams}}{{/hasPathParams}}){
qDebug() << "{{{basePathWithoutHost}}}{{{path}}}";
connect(this, &{{classname}}Request::{{nickname}}, handler, &{{classname}}Handler::{{nickname}});

Expand Down Expand Up @@ -64,10 +75,10 @@ void {{classname}}Request::{{nickname}}Request({{#hasPathParams}}{{#pathParams}}
{{/isListContainer}}
{{^isListContainer}}
{{^isMapContainer}}
{{#isPrimitive}}
{{#isPrimitiveType}}
{{{dataType}}} {{paramName}};
::{{cppNamespace}}::fromStringValue((QString(socket->readAll()), {{paramName}});
{{/isPrimitive}}
{{/isPrimitiveType}}
{{/isMapContainer}}
{{#isMapContainer}}
QJsonDocument doc;
Expand All @@ -81,13 +92,13 @@ void {{classname}}Request::{{nickname}}Request({{#hasPathParams}}{{#pathParams}}
}
{{/isMapContainer}}
{{^isMapContainer}}
{{^isPrimitive}}
{{^isPrimitiveType}}
QJsonDocument doc;
socket->readJson(doc);
QJsonObject obj = doc.object();
{{{dataType}}} {{paramName}};
::{{cppNamespace}}::fromJsonValue({{paramName}}, obj);
{{/isPrimitive}}
{{/isPrimitiveType}}
{{/isMapContainer}}
{{/isListContainer}}
{{/bodyParam}}{{/bodyParams}}
Expand All @@ -97,27 +108,42 @@ void {{classname}}Request::{{nickname}}Request({{#hasPathParams}}{{#pathParams}}

{{/operation}}{{/operations}}

{{#operations}}{{#operation}}void {{classname}}Request::{{nickname}}Response({{#returnType}}{{{returnType}}} res{{/returnType}}){
socket->setStatusCode(QHttpEngine::Socket::OK);
{{#operations}}{{#operation}}void {{classname}}Request::{{nickname}}Response({{#returnType}}const {{{returnType}}}& res{{/returnType}}){
writeResponseHeaders();{{#returnType}}{{^isPrimitiveType}}
QJsonDocument resDoc(::{{cppNamespace}}::toJsonValue(res).to{{^isListContainer}}Object{{/isListContainer}}{{#isListContainer}}Array{{/isListContainer}}());{{/isPrimitiveType}}
socket->writeJson(resDoc);{{#isPrimitiveType}}
socket->write({{#isListContainer}}QString("["+{{/isListContainer}}::{{cppNamespace}}::toStringValue(res){{#isListContainer}}+"]"){{/isListContainer}}.toUtf8());{{/isPrimitiveType}}{{/returnType}}{{^returnType}}
socket->setStatusCode(QHttpEngine::Socket::OK);{{/returnType}}
if(socket->isOpen()){
socket->writeHeaders();
socket->close();
}
}
{{/operation}}{{/operations}}

{{#operations}}{{#operation}}void {{classname}}Request::{{nickname}}Error({{#returnType}}{{{returnType}}} res, {{/returnType}}QNetworkReply::NetworkError error_type, QString& error_str){
Q_UNUSED(error_type);
Q_UNUSED(error_str);
{{/operation}}{{/operations}}
{{#operations}}{{#operation}}void {{classname}}Request::{{nickname}}Error({{#returnType}}const {{{returnType}}}& res, {{/returnType}}QNetworkReply::NetworkError error_type, QString& error_str){
Q_UNUSED(error_type); // TODO: Remap error_type to QHttpEngine::Socket errors
writeResponseHeaders();{{#returnType}}
Q_UNUSED(error_str); // response will be used instead of error string{{^isPrimitiveType}}
QJsonDocument resDoc(::{{cppNamespace}}::toJsonValue(res).to{{^isListContainer}}Object{{/isListContainer}}{{#isListContainer}}Array{{/isListContainer}}());{{/isPrimitiveType}}
socket->writeJson(resDoc);{{#isPrimitiveType}}
socket->write({{#isListContainer}}QString("["+{{/isListContainer}}::{{cppNamespace}}::toStringValue(res){{#isListContainer}}+"]"){{/isListContainer}}.toUtf8());{{/isPrimitiveType}}{{/returnType}}{{^returnType}}
socket->setStatusCode(QHttpEngine::Socket::NotFound);
socket->write(error_str.toUtf8());{{/returnType}}
if(socket->isOpen()){
socket->writeHeaders();
socket->close();
}
}
{{/operation}}{{/operations}}


{{/operation}}{{/operations}}
void {{classname}}Request::sendCustomResponse(QByteArray & res, QNetworkReply::NetworkError error_type){
Q_UNUSED(res); // TODO
Q_UNUSED(error_type); // TODO
}

void {{classname}}Request::sendCustomResponse(QIODevice *res, QNetworkReply::NetworkError error_type){
Q_UNUSED(res); // TODO
Q_UNUSED(error_type); // TODO
}

{{#cppNamespaceDeclarations}}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{{>licenseInfo}}
#ifndef _{{prefix}}_{{classname}}Request_H_
#define _{{prefix}}_{{classname}}Request_H_
#ifndef {{prefix}}_{{classname}}Request_H
#define {{prefix}}_{{classname}}Request_H

#include <QObject>
#include <QStringList>
#include <QMultiMap>
#include <QNetworkReply>
#include <QSharedPointer>

Expand All @@ -24,30 +25,47 @@ public:
{{classname}}Request(QHttpEngine::Socket *s, {{classname}}Handler* handler);
virtual ~{{classname}}Request();

{{#operations}}{{#operation}}void {{nickname}}Request({{#hasPathParams}}{{#pathParams}}QString {{{paramName}}}{{/pathParams}}{{/hasPathParams}});
{{#operations}}{{#operation}}void {{nickname}}Request({{#hasPathParams}}{{#pathParams}}const QString& {{{paramName}}}{{#hasMore}}, {{/hasMore}}{{/pathParams}}{{/hasPathParams}});
{{/operation}}{{/operations}}

{{#operations}}{{#operation}}void {{nickname}}Response({{#returnType}}{{{returnType}}} res{{/returnType}});
{{#operations}}{{#operation}}void {{nickname}}Response({{#returnType}}const {{{returnType}}}& res{{/returnType}});
{{/operation}}{{/operations}}

{{#operations}}{{#operation}}void {{nickname}}Error({{#returnType}}{{{returnType}}} res, {{/returnType}}QNetworkReply::NetworkError error_type, QString& error_str);
{{#operations}}{{#operation}}void {{nickname}}Error({{#returnType}}const {{{returnType}}}& res, {{/returnType}}QNetworkReply::NetworkError error_type, QString& error_str);
{{/operation}}{{/operations}}

QMap<QString, QString> getDefaultHeaders();
void sendCustomResponse(QByteArray & res, QNetworkReply::NetworkError error_type);

void sendCustomResponse(QIODevice *res, QNetworkReply::NetworkError error_type);

QMap<QString, QString> getRequestHeaders() const;

QHttpEngine::Socket* getRawSocket();

void setResponseHeaders(const QMultiMap<QString,QString>& headers);

signals:
{{#operations}}{{#operation}}void {{nickname}}({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
{{/operation}}{{/operations}}

private:
QMap<QString, QString> defaultHeaders;
QMap<QString, QString> requestHeaders;
QMap<QString, QString> responseHeaders;
QHttpEngine::Socket *socket;
{{classname}}Handler *handler;

inline void writeResponseHeaders(){
QHttpEngine::Socket::HeaderMap resHeaders;
for(auto itr = responseHeaders.begin(); itr != responseHeaders.end(); ++itr) {
resHeaders.insert(itr.key().toUtf8(), itr.value().toUtf8());
}
socket->setHeaders(resHeaders);
socket->writeHeaders();
}
};

{{#cppNamespaceDeclarations}}
}
{{/cppNamespaceDeclarations}}

#endif // _{{prefix}}_{{classname}}Request_H_
#endif // {{prefix}}_{{classname}}Request_H
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,8 @@ void ApiRouter::setUpRoutes() {

void ApiRouter::processRequest(QHttpEngine::Socket *socket){
if (Routes.contains(socket->path())) {
auto itr = Routes.find(socket->path());
while (itr != Routes.end() && itr.key() == socket->path()) {
itr.value().operator()(socket);
++itr;
for(auto endpoints : Routes.values(socket->path())) {
endpoints.operator()(socket);
}
} else
{ {{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}{{#pathParams}}
Expand All @@ -77,7 +75,7 @@ void ApiRouter::processRequest(QHttpEngine::Socket *socket){
if ((toQHttpEngineMethod("{{httpMethod}}") == socket->method()) && match.hasMatch() ) {
QString pathparam = match.captured(1);
auto reqObj = new {{classname}}Request(socket, {{classname}}ApiHandler);
reqObj->{{nickname}}Request({{#hasPathParams}}{{#pathParams}}pathparam{{/pathParams}}{{/hasPathParams}});;
reqObj->{{nickname}}Request({{#hasPathParams}}{{#pathParams}}pathparam{{/pathParams}}{{/hasPathParams}});
return;
}
}{{/pathParams}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,15 @@ namespace {{this}} {
QString toStringValue(const double &value);

template <typename T>
QList<QString> toStringValue(const QList<T> &val) {
QList<QString> strArray;
QString toStringValue(const QList<T> &val) {
QString strArray;
for(auto item : val) {
strArray.append(toStringValue(item));
strArray.append(toStringValue(item) + ",");
}
return strArray;
}

template <typename T>
QMap<QString, QString> toStringValue(const QMap<QString, T> &val) {
QMap<QString, QString> strMap;
for(auto itemkey : val.keys()) {
strMap.insert(itemkey, toStringValue(val.value(itemkey)));
if(val.count() > 0) {
strArray.chop(1);
}
return strMap;
return strArray;
}

QJsonValue toJsonValue(const QString &value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ int main(int argc, char * argv[])

QSharedPointer<{{cppNamespace}}::RequestHandler> handler(new {{cppNamespace}}::RequestHandler());
{{cppNamespace}}::ApiRouter router;
router.setUpRoutes();
QObject::connect(handler.data(), &{{cppNamespace}}::RequestHandler::requestReceived, [&](QHttpEngine::Socket *socket) {
router.processRequest(socket);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ QJsonObject

{{#vars}}
{{{dataType}}}
{{classname}}::{{getter}}() {
{{classname}}::{{getter}}() const {
return {{name}};
}
void
Expand Down
Loading

0 comments on commit 4706378

Please sign in to comment.