diff --git a/bin/flaskConnexion.sh b/bin/flaskConnexion.sh new file mode 100755 index 000000000000..63f55d3471e0 --- /dev/null +++ b/bin/flaskConnexion.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +SCRIPT="$0" + +while [ -h "$SCRIPT" ] ; do + ls=`ls -ld "$SCRIPT"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + SCRIPT="$link" + else + SCRIPT=`dirname "$SCRIPT"`/"$link" + fi +done + +if [ ! -d "${APP_DIR}" ]; then + APP_DIR=`dirname "$SCRIPT"`/.. + APP_DIR=`cd "${APP_DIR}"; pwd` +fi + +executable="./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar" + +if [ ! -f "$executable" ] +then + mvn clean package +fi + +# if you've executed sbt assembly previously it will use that instead. +export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" +ags="$@ generate -i modules/swagger-codegen/src/test/resources/2_0/petstore.json -l flaskConnexion -o samples/server/petstore/flaskConnexion -t modules/swagger-codegen/src/main/resources/flaskConnexion" + +java $JAVA_OPTS -Dservice -jar $executable $ags diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/FlaskConnexionCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/FlaskConnexionCodegen.java new file mode 100644 index 000000000000..62972d5b3a34 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/FlaskConnexionCodegen.java @@ -0,0 +1,274 @@ +package io.swagger.codegen.languages; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Multimap; +import io.swagger.codegen.*; +import io.swagger.models.Operation; +import io.swagger.models.Path; +import io.swagger.models.Swagger; +import io.swagger.util.Yaml; + +import java.io.File; +import java.util.*; + +public class FlaskConnexionCodegen extends DefaultCodegen implements CodegenConfig { + protected String apiVersion = "1.0.0"; + protected int serverPort = 8080; + protected String projectName = "swagger-server"; + + public FlaskConnexionCodegen() { + super(); + + languageSpecificPrimitives.clear(); + languageSpecificPrimitives.add("int"); + languageSpecificPrimitives.add("float"); + languageSpecificPrimitives.add("list"); + languageSpecificPrimitives.add("bool"); + languageSpecificPrimitives.add("str"); + languageSpecificPrimitives.add("datetime"); + languageSpecificPrimitives.add("date"); + + typeMapping.clear(); + typeMapping.put("integer", "int"); + typeMapping.put("float", "float"); + typeMapping.put("number", "float"); + typeMapping.put("long", "int"); + typeMapping.put("double", "float"); + typeMapping.put("array", "list"); + typeMapping.put("map", "dict"); + typeMapping.put("boolean", "bool"); + typeMapping.put("string", "str"); + typeMapping.put("date", "date"); + typeMapping.put("DateTime", "datetime"); + typeMapping.put("object", "object"); + typeMapping.put("file", "file"); + + // set the output folder here + outputFolder = "generated-code/connexion"; + + /** + * Models. You can write model files using the modelTemplateFiles map. + * if you want to create one template for file, you can do so here. + * for multiple files for model, just put another entry in the `modelTemplateFiles` with + * a different extension + */ + modelTemplateFiles.clear(); + + /** + * Api classes. You can write classes for each Api file with the apiTemplateFiles map. + * as with models, add multiple entries with different extensions for multiple files per + * class + */ + apiTemplateFiles.put( + "controller.mustache", // the template to use + ".py"); // the extension for each file to write + + /** + * Template Location. This is the location which templates will be read from. The generator + * will use the resource stream to attempt to read the templates. + */ + embeddedTemplateDir = templateDir = "flaskConnexion"; + + // from https://docs.python.org/release/2.5.4/ref/keywords.html + reservedWords = new HashSet( + Arrays.asList( + "and", "del", "from", "not", "while", "as", "elif", "global", "or", "with", + "assert", "else", "if", "pass", "yield", "break", "except", "import", + "print", "class", "exec", "in", "raise", "continue", "finally", "is", + "return", "def", "for", "lambda", "try")); + + /** + * Additional Properties. These values can be passed to the templates and + * are available in models, apis, and supporting files + */ + additionalProperties.put("apiVersion", apiVersion); + additionalProperties.put("serverPort", serverPort); + + /** + * Supporting Files. You can write single files for the generator with the + * entire object tree available. If the input file has a suffix of `.mustache + * it will be processed by the template engine. Otherwise, it will be copied + */ + + supportingFiles.add(new SupportingFile("swagger.mustache", + "swagger", + "swagger.yaml") + ); + supportingFiles.add(new SupportingFile("app.mustache", + "", + "app.py") + ); + supportingFiles.add(new SupportingFile("README.mustache", + "", + "README.md") + ); + supportingFiles.add(new SupportingFile("controller.mustache", + "controllers", + "default_controller.py") + ); + } + + public String apiPackage() { + return "controllers"; + } + + /** + * Configures the type of generator. + * + * @return the CodegenType for this generator + * @see io.swagger.codegen.CodegenType + */ + public CodegenType getTag() { + return CodegenType.SERVER; + } + + /** + * Configures a friendly name for the generator. This will be used by the generator + * to select the library with the -l flag. + * + * @return the friendly name for the generator + */ + public String getName() { + return "flaskConnexion"; + } + + /** + * Returns human-friendly help for the generator. Provide the consumer with help + * tips, parameters here + * + * @return A string value for the help message + */ + public String getHelp() { + return "Generates a python server library using the connexion project. By default, " + + "it will also generate service classes--which you can disable with the `-Dnoservice` environment variable."; + } + + @Override + public String toApiName(String name) { + if (name.length() == 0) { + return "DefaultController"; + } + return initialCaps(name); + } + + @Override + public String toApiFilename(String name) { + return toApiName(name); + } + + /** + * 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 reseved words + * + * @return the escaped term + */ + @Override + public String escapeReservedWord(String name) { + return "_" + name; // add an underscore to the name + } + + /** + * Location to write api files. You can use the apiPackage() as defined when the class is + * instantiated + */ + @Override + public String apiFileFolder() { + return outputFolder + File.separator + apiPackage().replace('.', File.separatorChar); + } + + @Override + public void preprocessSwagger(Swagger swagger) { + if(swagger != null && swagger.getPaths() != null) { + for(String pathname : swagger.getPaths().keySet()) { + Path path = swagger.getPath(pathname); + if(path.getOperations() != null) { + for(Operation operation : path.getOperations()) { + String operationId = operation.getOperationId(); + if(operationId != null && operationId.indexOf(".") == -1) { + operation.setVendorExtension("x-operationId", underscore(sanitizeName(operationId))); + operationId = "controllers.default_controller." + underscore(sanitizeName(operationId)); + operation.setOperationId(operationId); + } + if(operation.getTags() != null) { + List> tags = new ArrayList>(); + for(String tag : operation.getTags()) { + Map value = new HashMap(); + value.put("tag", tag); + value.put("hasMore", "true"); + tags.add(value); + } + if(tags.size() > 0) { + tags.get(tags.size() - 1).remove("hasMore"); + } + if(operation.getTags().size() > 0) { + String tag = operation.getTags().get(0); + operation.setTags(Arrays.asList(tag)); + } + operation.setVendorExtension("x-tags", tags); + } + else { + String tag = "default_controller"; + operation.setTags(Arrays.asList(tag)); + } + } + } + } + } + } + + @SuppressWarnings("unchecked") + private List> getOperations(Map objs) { + List> result = new ArrayList>(); + Map apiInfo = (Map) objs.get("apiInfo"); + List> apis = (List>) apiInfo.get("apis"); + for (Map api : apis) { + result.add((Map) api.get("operations")); + } + return result; + } + + private List> sortOperationsByPath(List ops) { + Multimap opsByPath = ArrayListMultimap.create(); + + for (CodegenOperation op : ops) { + opsByPath.put(op.path, op); + } + + List> opsByPathList = new ArrayList>(); + for (Map.Entry> entry : opsByPath.asMap().entrySet()) { + Map opsByPathEntry = new HashMap(); + opsByPathList.add(opsByPathEntry); + opsByPathEntry.put("path", entry.getKey()); + opsByPathEntry.put("operation", entry.getValue()); + List operationsForThisPath = Lists.newArrayList(entry.getValue()); + operationsForThisPath.get(operationsForThisPath.size() - 1).hasMore = null; + if (opsByPathList.size() < opsByPath.asMap().size()) { + opsByPathEntry.put("hasMore", "true"); + } + } + + return opsByPathList; + } + + @Override + public Map postProcessSupportingFileData(Map objs) { + Swagger swagger = (Swagger)objs.get("swagger"); + if(swagger != null) { + try { + objs.put("swagger-yaml", Yaml.mapper().writeValueAsString(swagger)); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + for (Map operations : getOperations(objs)) { + @SuppressWarnings("unchecked") + List ops = (List) operations.get("operation"); + + List> opsByPathList = sortOperationsByPath(ops); + operations.put("operationsByPath", opsByPathList); + } + return super.postProcessSupportingFileData(objs); + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NodeJSServerCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NodeJSServerCodegen.java index 4dee5f6f2df6..163af1ed4920 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NodeJSServerCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NodeJSServerCodegen.java @@ -78,7 +78,7 @@ public class NodeJSServerCodegen extends DefaultCodegen implements CodegenConfig "api", "swagger.yaml") ); - supportingFiles.add(new SupportingFile("index.mustache", + supportingFiles.add(new SupportingFile("app.mustache", "", "index.js") ); diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SilexServerCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SilexServerCodegen.java index 2e35f412bbfb..c56242fdf830 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SilexServerCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SilexServerCodegen.java @@ -84,7 +84,7 @@ public class SilexServerCodegen extends DefaultCodegen implements CodegenConfig supportingFiles.add(new SupportingFile("README.mustache", packagePath.replace('/', File.separatorChar), "README.md")); supportingFiles.add(new SupportingFile("composer.json", packagePath.replace('/', File.separatorChar), "composer.json")); - supportingFiles.add(new SupportingFile("index.mustache", packagePath.replace('/', File.separatorChar), "index.php")); + supportingFiles.add(new SupportingFile("app.mustache", packagePath.replace('/', File.separatorChar), "index.php")); supportingFiles.add(new SupportingFile(".htaccess", packagePath.replace('/', File.separatorChar), ".htaccess")); } diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticDocCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticDocCodegen.java index b27ba23a4cd4..da683916ea4b 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticDocCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticDocCodegen.java @@ -43,7 +43,7 @@ public class StaticDocCodegen extends DefaultCodegen implements CodegenConfig { outputFolder + "/assets/js", "jquery-1.8.3.min.js")); supportingFiles.add(new SupportingFile("assets/js/main.js", outputFolder + "/assets/js", "main.js")); - supportingFiles.add(new SupportingFile("index.mustache", + supportingFiles.add(new SupportingFile("app.mustache", outputFolder, "index.html")); instantiationTypes.put("array", "ArrayList"); diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticHtmlGenerator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticHtmlGenerator.java index a86c2244995f..2382113c90fa 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticHtmlGenerator.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/StaticHtmlGenerator.java @@ -43,7 +43,7 @@ public class StaticHtmlGenerator extends DefaultCodegen implements CodegenConfig additionalProperties.put(CodegenConstants.ARTIFACT_ID, artifactId); additionalProperties.put(CodegenConstants.ARTIFACT_VERSION, artifactVersion); - supportingFiles.add(new SupportingFile("index.mustache", "", "index.html")); + supportingFiles.add(new SupportingFile("app.mustache", "", "index.html")); reservedWords = new HashSet(); languageSpecificPrimitives = new HashSet(); diff --git a/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig b/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig index 4cf785abbd8d..11283011a891 100644 --- a/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig +++ b/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig @@ -3,6 +3,7 @@ io.swagger.codegen.languages.AsyncScalaClientCodegen io.swagger.codegen.languages.CSharpClientCodegen io.swagger.codegen.languages.DartClientCodegen io.swagger.codegen.languages.FlashClientCodegen +io.swagger.codegen.languages.FlaskConnexionCodegen io.swagger.codegen.languages.JavaClientCodegen io.swagger.codegen.languages.JaxRSServerCodegen io.swagger.codegen.languages.JavaInflectorServerCodegen diff --git a/modules/swagger-codegen/src/main/resources/flaskConnexion/README.mustache b/modules/swagger-codegen/src/main/resources/flaskConnexion/README.mustache new file mode 100644 index 000000000000..5fdb984a9dc2 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flaskConnexion/README.mustache @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 + +import connexion + +# TODO: operations go here +def post_greeting(name: str) -> str: +return 'Hello {name}'.format(name=name) + +if __name__ == '__main__': + app = connexion.App(__name__, 9090, specification_dir='examples/helloworld/swagger/') + app.add_api('helloworld-api.yaml', arguments={'title': 'Hello World Example'}) + app.run() diff --git a/modules/swagger-codegen/src/main/resources/flaskConnexion/app.mustache b/modules/swagger-codegen/src/main/resources/flaskConnexion/app.mustache new file mode 100644 index 000000000000..14af64be6f9a --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flaskConnexion/app.mustache @@ -0,0 +1,9 @@ +#!/usr/bin/env python3 + +import connexion + +if __name__ == '__main__': + app = connexion.App(__name__, {{serverPort}}, + specification_dir='./swagger/') + app.add_api('swagger.yaml', arguments={'title': '{{appDescription}}'}) + app.run() diff --git a/modules/swagger-codegen/src/main/resources/flaskConnexion/controller.mustache b/modules/swagger-codegen/src/main/resources/flaskConnexion/controller.mustache new file mode 100644 index 000000000000..a4bb5b0c033a --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flaskConnexion/controller.mustache @@ -0,0 +1,11 @@ +{{#apiInfo}} +{{#apis}} +{{#operations}} +{{#operation}} + +def {{vendorExtensions.x-operationId}}({{#allParams}}{{paramName}}: ({{dataType}}){{/allParams}}) -> str: + return 'Hello {name}'.format(name=name) +{{/operation}} +{{/operations}} +{{/apis}} +{{/apiInfo}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/flaskConnexion/swagger.mustache b/modules/swagger-codegen/src/main/resources/flaskConnexion/swagger.mustache new file mode 100644 index 000000000000..51560926bba1 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flaskConnexion/swagger.mustache @@ -0,0 +1 @@ +{{{swagger-yaml}}} \ No newline at end of file