mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2025-07-02 21:50:55 +00:00
New generator - Scala Play Framework (#2421)
* Added new generator for Scala + Play Framework (WIP) * scala-play-framework: default values reintroduced (mostly); datatype -> dataType * reintroduced missing EOF newline * Support single/collection params for header/query params * Rename apiFutures > supportAsync, implStubs > skipStubs (opt-out instead of opt-in) * Deleted license and small fixes * Generate extraction of form parameters from request body * Added missing call to executeApi for unit methods when supportAsync=false * Polished some stuff and added routes, application.conf, logback.xml, better default responses * Disabled generation of Json.format for models with files * Added README * Multiple additions and improvements. - Fix Indentation using mustache lambdas - Option to set routes file name (default: routes) - allows uninterrupted manual maintenance of main routes file, which may include a subroute to the generated routes file - Move supporting file classes to a package and update application.conf generation accordingly - Option to generate custom exceptions (default: true) which are used in the controller to differentiate between API call exceptions and validation exceptions - Generate error handler with basic exception mapping - Option to generate API docs under /api route - Reorder routes file so parameter-less paths are given priority over parameterized paths. Prevents case like /v2/user/:username activating before /v2/user/login (thus shadowing the login route completely) as observed using v3 petstore.yaml - Option to set base package name (default: org.openapitools) to allow placing supporting files under a different package * Revert supportAsync default to false * Added binaries and default api/model packages * Added scala-play-framework sample * Add missing contextPath to README and controller comment
This commit is contained in:
parent
9e391efd1d
commit
28ae33cb13
32
bin/scala-play-framework-petstore.sh
Executable file
32
bin/scala-play-framework-petstore.sh
Executable file
@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
|
||||
SCRIPT="$0"
|
||||
echo "# START SCRIPT: $SCRIPT"
|
||||
|
||||
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/openapi-generator-cli/target/openapi-generator-cli.jar"
|
||||
|
||||
if [ ! -f "$executable" ]
|
||||
then
|
||||
mvn -B 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 -t modules/openapi-generator/src/main/resources/scala-play-framework -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g scala-play-framework -o samples/server/petstore/scala-play-framework $@"
|
||||
|
||||
java $JAVA_OPTS -jar $executable $ags
|
10
bin/windows/scala-play-framework-petstore.bat
Executable file
10
bin/windows/scala-play-framework-petstore.bat
Executable file
@ -0,0 +1,10 @@
|
||||
set executable=.\modules\openapi-generator-cli\target\openapi-generator-cli.jar
|
||||
|
||||
If Not Exist %executable% (
|
||||
mvn clean package
|
||||
)
|
||||
|
||||
REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M
|
||||
set ags=generate -i modules\openapi-generator\src\test\resources\2_0\petstore.yaml -g scala-play-framework -o samples\server\petstore\scala-play-framework
|
||||
|
||||
java %JAVA_OPTS% -jar %executable% %ags%
|
@ -0,0 +1,401 @@
|
||||
package org.openapitools.codegen.languages;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.samskivert.mustache.Mustache;
|
||||
import io.swagger.v3.oas.models.media.ArraySchema;
|
||||
import io.swagger.v3.oas.models.media.Schema;
|
||||
import org.openapitools.codegen.*;
|
||||
import org.openapitools.codegen.mustache.*;
|
||||
import org.openapitools.codegen.utils.ModelUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.rightPad;
|
||||
import static org.openapitools.codegen.utils.StringUtils.camelize;
|
||||
|
||||
public class ScalaPlayFrameworkServerCodegen extends AbstractScalaCodegen implements CodegenConfig {
|
||||
public static final String TITLE = "title";
|
||||
public static final String SKIP_STUBS = "skipStubs";
|
||||
public static final String SUPPORT_ASYNC = "supportAsync";
|
||||
public static final String GENERATE_CUSTOM_EXCEPTIONS = "generateCustomExceptions";
|
||||
public static final String USE_SWAGGER_UI = "useSwaggerUI";
|
||||
public static final String ROUTES_FILE_NAME = "routesFileName";
|
||||
public static final String BASE_PACKAGE = "basePackage";
|
||||
|
||||
static Logger LOGGER = LoggerFactory.getLogger(ScalaPlayFrameworkServerCodegen.class);
|
||||
|
||||
protected boolean skipStubs = false;
|
||||
protected boolean supportAsync = false;
|
||||
protected boolean generateCustomExceptions = true;
|
||||
protected boolean useSwaggerUI = true;
|
||||
protected String routesFileName = "routes";
|
||||
protected String basePackage = "org.openapitools";
|
||||
|
||||
public ScalaPlayFrameworkServerCodegen() {
|
||||
super();
|
||||
outputFolder = "generated-code" + File.separator + "scala-play-framework";
|
||||
modelTemplateFiles.put("model.mustache", ".scala");
|
||||
apiTemplateFiles.put("api.mustache", ".scala");
|
||||
embeddedTemplateDir = templateDir = "scala-play-framework";
|
||||
hideGenerationTimestamp = false;
|
||||
sourceFolder = "app";
|
||||
apiPackage = "api";
|
||||
modelPackage = "model";
|
||||
|
||||
instantiationTypes.put("map", "Map");
|
||||
instantiationTypes.put("array", "List");
|
||||
|
||||
typeMapping.put("DateTime", "OffsetDateTime");
|
||||
typeMapping.put("Date", "LocalDate");
|
||||
typeMapping.put("Integer", "Int");
|
||||
typeMapping.put("binary", "Array[Byte]");
|
||||
typeMapping.put("ByteArray", "Array[Byte]");
|
||||
typeMapping.put("object", "JsObject");
|
||||
typeMapping.put("file", "TemporaryFile");
|
||||
|
||||
importMapping.put("OffsetDateTime", "java.time.OffsetDateTime");
|
||||
importMapping.put("LocalDate", "java.time.LocalDate");
|
||||
importMapping.remove("BigDecimal");
|
||||
importMapping.put("TemporaryFile", "play.api.libs.Files.TemporaryFile");
|
||||
|
||||
cliOptions.add(new CliOption(ROUTES_FILE_NAME, "Name of the routes file to generate.").defaultValue(routesFileName));
|
||||
cliOptions.add(new CliOption(ROUTES_FILE_NAME, "Base package in which supporting classes are generated.").defaultValue(basePackage));
|
||||
|
||||
addCliOptionWithDefault(SKIP_STUBS, "If set, skips generation of stub classes.", skipStubs);
|
||||
addCliOptionWithDefault(SUPPORT_ASYNC, "If set, wraps API return types with Futures and generates async actions.", supportAsync);
|
||||
addCliOptionWithDefault(GENERATE_CUSTOM_EXCEPTIONS, "If set, generates custom exception types.", generateCustomExceptions);
|
||||
addCliOptionWithDefault(USE_SWAGGER_UI, "Add a route to /api which show your documentation in swagger-ui. Will also import needed dependencies", useSwaggerUI);
|
||||
}
|
||||
|
||||
public CodegenType getTag() {
|
||||
return CodegenType.SERVER;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "scala-play-framework";
|
||||
}
|
||||
|
||||
public String getHelp() {
|
||||
return "Generates a Scala server application with Play Framework.";
|
||||
}
|
||||
|
||||
public void setSupportAsync(boolean supportAsync) {
|
||||
this.supportAsync = supportAsync;
|
||||
}
|
||||
|
||||
public void setSkipStubs(boolean skipStubs) {
|
||||
this.skipStubs = skipStubs;
|
||||
}
|
||||
|
||||
public void setGenerateCustomExceptions(boolean generateCustomExceptions) {
|
||||
this.generateCustomExceptions = generateCustomExceptions;
|
||||
}
|
||||
|
||||
public void setRoutesFileName(String routesFileName) {
|
||||
this.routesFileName = routesFileName;
|
||||
}
|
||||
|
||||
public void setBasePackage(String basePackage) {
|
||||
this.basePackage = basePackage;
|
||||
}
|
||||
|
||||
public void setUseSwaggerUI(boolean useSwaggerUI) {
|
||||
this.useSwaggerUI = useSwaggerUI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processOpts() {
|
||||
super.processOpts();
|
||||
|
||||
if (additionalProperties.containsKey(SKIP_STUBS)) {
|
||||
this.setSkipStubs(convertPropertyToBoolean(SKIP_STUBS));
|
||||
}
|
||||
writePropertyBack(SKIP_STUBS, skipStubs);
|
||||
|
||||
if (additionalProperties.containsKey(SUPPORT_ASYNC)) {
|
||||
this.setSupportAsync(convertPropertyToBoolean(SUPPORT_ASYNC));
|
||||
}
|
||||
writePropertyBack(SUPPORT_ASYNC, supportAsync);
|
||||
|
||||
if (additionalProperties.containsKey(GENERATE_CUSTOM_EXCEPTIONS)) {
|
||||
this.setGenerateCustomExceptions(convertPropertyToBoolean(GENERATE_CUSTOM_EXCEPTIONS));
|
||||
}
|
||||
writePropertyBack(GENERATE_CUSTOM_EXCEPTIONS, generateCustomExceptions);
|
||||
|
||||
if (additionalProperties.containsKey(USE_SWAGGER_UI)) {
|
||||
this.setUseSwaggerUI(convertPropertyToBoolean(USE_SWAGGER_UI));
|
||||
}
|
||||
writePropertyBack(USE_SWAGGER_UI, useSwaggerUI);
|
||||
|
||||
if (additionalProperties.containsKey(ROUTES_FILE_NAME)) {
|
||||
this.setRoutesFileName((String)additionalProperties.get(ROUTES_FILE_NAME));
|
||||
} else {
|
||||
additionalProperties.put(ROUTES_FILE_NAME, routesFileName);
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(BASE_PACKAGE)) {
|
||||
this.setBasePackage((String)additionalProperties.get(BASE_PACKAGE));
|
||||
} else {
|
||||
additionalProperties.put(BASE_PACKAGE, basePackage);
|
||||
}
|
||||
|
||||
apiTemplateFiles.remove("api.mustache");
|
||||
|
||||
if (!skipStubs) {
|
||||
apiTemplateFiles.put("app/apiImplStubs.scala.mustache", "Impl.scala");
|
||||
}
|
||||
|
||||
apiTemplateFiles.put("app/apiTrait.scala.mustache", ".scala");
|
||||
apiTemplateFiles.put("app/apiController.scala.mustache", "Controller.scala");
|
||||
|
||||
supportingFiles.add(new SupportingFile("README.md.mustache", "", "README.md"));
|
||||
supportingFiles.add(new SupportingFile("build.sbt.mustache", "", "build.sbt"));
|
||||
supportingFiles.add(new SupportingFile("conf/application.conf.mustache", "conf", "application.conf"));
|
||||
supportingFiles.add(new SupportingFile("conf/logback.xml.mustache", "conf", "logback.xml"));
|
||||
supportingFiles.add(new SupportingFile("project/build.properties.mustache", "project", "build.properties"));
|
||||
supportingFiles.add(new SupportingFile("project/plugins.sbt.mustache", "project", "plugins.sbt"));
|
||||
supportingFiles.add(new SupportingFile("conf/routes.mustache", "conf", routesFileName));
|
||||
supportingFiles.add(new SupportingFile("app/module.scala.mustache", getBasePackagePath(), "Module.scala"));
|
||||
supportingFiles.add(new SupportingFile("app/errorHandler.scala.mustache", getBasePackagePath(), "ErrorHandler.scala"));
|
||||
|
||||
if (generateCustomExceptions) {
|
||||
supportingFiles.add(new SupportingFile("app/exceptions.scala.mustache", getBasePackagePath(), "OpenApiExceptions.scala"));
|
||||
}
|
||||
|
||||
if (this.useSwaggerUI) {
|
||||
//App/Controllers
|
||||
supportingFiles.add(new SupportingFile("public/openapi.json.mustache", "public", "openapi.json"));
|
||||
supportingFiles.add(new SupportingFile("app/apiDocController.scala.mustache", String.format(Locale.ROOT, "app/%s", apiPackage.replace(".", File.separator)), "ApiDocController.scala"));
|
||||
}
|
||||
addMustacheLambdas(additionalProperties);
|
||||
}
|
||||
|
||||
private void addMustacheLambdas(Map<String, Object> objs) {
|
||||
Map<String, Mustache.Lambda> lambdas = new ImmutableMap.Builder<String, Mustache.Lambda>()
|
||||
.put("indented_4", new IndentedLambda(4, " "))
|
||||
.put("indented_8", new IndentedLambda(8, " "))
|
||||
.build();
|
||||
objs.put("lambda", lambdas);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
|
||||
Map<String, CodegenModel> models = new HashMap<>();
|
||||
|
||||
for (Object _mo : allModels) {
|
||||
CodegenModel model = (CodegenModel)((Map<String, Object>)_mo).get("model");
|
||||
models.put(model.classname, model);
|
||||
}
|
||||
|
||||
Map<String, Object> operations = (Map<String, Object>)objs.get("operations");
|
||||
if (operations != null) {
|
||||
List<CodegenOperation> ops = (List<CodegenOperation>)operations.get("operation");
|
||||
for (CodegenOperation operation : ops) {
|
||||
Pattern pathVariableMatcher = Pattern.compile("\\{([^}]+)}");
|
||||
Matcher match = pathVariableMatcher.matcher(operation.path);
|
||||
while (match.find()) {
|
||||
String completeMatch = match.group();
|
||||
String replacement = ":" + camelize(match.group(1), true);
|
||||
operation.path = operation.path.replace(completeMatch, replacement);
|
||||
}
|
||||
|
||||
if ("null".equals(operation.defaultResponse) && models.containsKey(operation.returnType)) {
|
||||
operation.defaultResponse = models.get(operation.returnType).defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return objs;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Map<String, Object> postProcessAllModels(Map<String, Object> objs) {
|
||||
objs = super.postProcessAllModels(objs);
|
||||
Map<String, CodegenModel> modelsByClassName = new HashMap<>();
|
||||
|
||||
for (Object _outer : objs.values()) {
|
||||
Map<String, Object> outer = (Map<String, Object>)_outer;
|
||||
List<Map<String, Object>> models = (List<Map<String, Object>>)outer.get("models");
|
||||
|
||||
for (Map<String, Object> mo : models) {
|
||||
CodegenModel cm = (CodegenModel)mo.get("model");
|
||||
postProcessModelsEnum(outer);
|
||||
cm.classVarName = camelize(cm.classVarName, true);
|
||||
modelsByClassName.put(cm.classname, cm);
|
||||
boolean hasFiles = cm.vars.stream().anyMatch(var -> var.isFile);
|
||||
cm.vendorExtensions.put("hasFiles", hasFiles);
|
||||
}
|
||||
}
|
||||
|
||||
for (CodegenModel model : modelsByClassName.values()) {
|
||||
model.defaultValue = generateModelDefaultValue(model, modelsByClassName);
|
||||
}
|
||||
|
||||
return objs;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
|
||||
objs = super.postProcessSupportingFileData(objs);
|
||||
generateJSONSpecFile(objs);
|
||||
|
||||
// Prettify routes file
|
||||
Map<String, Object> apiInfo = (Map<String, Object>)objs.get("apiInfo");
|
||||
List<Map<String, Object>> apis = (List<Map<String, Object>>)apiInfo.get("apis");
|
||||
List<CodegenOperation> ops = apis.stream()
|
||||
.map(api -> (Map<String, Object>)api.get("operations"))
|
||||
.flatMap(operations -> ((List<CodegenOperation>)operations.get("operation")).stream())
|
||||
.collect(Collectors.toList());
|
||||
int maxPathLength = ops.stream()
|
||||
.mapToInt(op -> op.httpMethod.length() + op.path.length())
|
||||
.reduce(0, Integer::max);
|
||||
ops.forEach(op -> op.vendorExtensions.put("paddedPath", rightPad(op.path, maxPathLength - op.httpMethod.length())));
|
||||
ops.forEach(op -> op.vendorExtensions.put("hasPathParams", op.getHasPathParams()));
|
||||
|
||||
return objs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSchemaType(Schema p) {
|
||||
String openAPIType = super.getSchemaType(p);
|
||||
openAPIType = getAlias(openAPIType);
|
||||
|
||||
// don't apply renaming on types from the typeMapping
|
||||
if (typeMapping.containsKey(openAPIType)) {
|
||||
return typeMapping.get(openAPIType);
|
||||
}
|
||||
|
||||
if (null == openAPIType) {
|
||||
LOGGER.error("No Type defined for Schema " + p);
|
||||
}
|
||||
return toModelName(openAPIType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toDefaultValue(Schema p) {
|
||||
if (p.getRequired() != null && p.getRequired().contains(p.getName())) {
|
||||
return "None";
|
||||
}
|
||||
|
||||
if (p.getDefault() != null) {
|
||||
return p.getDefault().toString();
|
||||
}
|
||||
|
||||
if (ModelUtils.isBooleanSchema(p)) {
|
||||
return "false";
|
||||
}
|
||||
|
||||
if (ModelUtils.isDateSchema(p)) {
|
||||
return "LocalDate.now";
|
||||
}
|
||||
|
||||
if (ModelUtils.isDateTimeSchema(p)) {
|
||||
return "OffsetDateTime.now";
|
||||
}
|
||||
|
||||
if (ModelUtils.isDoubleSchema(p)) {
|
||||
return "0.0";
|
||||
}
|
||||
|
||||
if (ModelUtils.isFloatSchema(p)) {
|
||||
return "0.0F";
|
||||
}
|
||||
|
||||
if (ModelUtils.isIntegerSchema(p)) {
|
||||
return "0";
|
||||
}
|
||||
|
||||
if (ModelUtils.isLongSchema(p)) {
|
||||
return "0L";
|
||||
}
|
||||
|
||||
if (ModelUtils.isStringSchema(p)) {
|
||||
return "\"\"";
|
||||
}
|
||||
|
||||
if (ModelUtils.isMapSchema(p)) {
|
||||
Schema ap = ModelUtils.getAdditionalProperties(p);
|
||||
String inner = getSchemaType(ap);
|
||||
return "Map.empty[String, " + inner + "]";
|
||||
}
|
||||
|
||||
if (ModelUtils.isArraySchema(p)) {
|
||||
Schema items = ((ArraySchema)p).getItems();
|
||||
String inner = getSchemaType(items);
|
||||
return "List.empty[" + inner + "]";
|
||||
}
|
||||
|
||||
return "null";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toEnumName(CodegenProperty property) {
|
||||
return camelize(property.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toEnumVarName(String value, String datatype) {
|
||||
if (value.length() == 0) {
|
||||
return "EMPTY";
|
||||
}
|
||||
|
||||
String var = camelize(value.replaceAll("\\W+", "_"));
|
||||
if (var.matches("\\d.*")) {
|
||||
return "_" + var;
|
||||
} else {
|
||||
return var;
|
||||
}
|
||||
}
|
||||
|
||||
private void addCliOptionWithDefault(String name, String description, boolean defaultValue) {
|
||||
cliOptions.add(CliOption.newBoolean(name, description).defaultValue(Boolean.toString(defaultValue)));
|
||||
}
|
||||
|
||||
private String getBasePackagePath() {
|
||||
return String.format(Locale.ROOT, "%s/%s", sourceFolder, basePackage.replace(".", File.separator));
|
||||
}
|
||||
|
||||
private String generateModelDefaultValue(CodegenModel cm, Map<String, CodegenModel> models) {
|
||||
StringBuilder defaultValue = new StringBuilder();
|
||||
defaultValue.append(cm.classname).append('(');
|
||||
|
||||
for (CodegenProperty var : cm.vars) {
|
||||
if (!var.required) {
|
||||
defaultValue.append("None");
|
||||
} else if (models.containsKey(var.dataType)) {
|
||||
defaultValue.append(generateModelDefaultValue(models.get(var.dataType), models));
|
||||
} else if (var.defaultValue != null) {
|
||||
defaultValue.append(var.defaultValue);
|
||||
} else if (var.isEnum) {
|
||||
defaultValue.append(cm.classname).append('.').append(var.enumName).append(".values.head");
|
||||
} else {
|
||||
LOGGER.warn("Unknown default value for var {0} in class {1}", var.name, cm.classname);
|
||||
defaultValue.append("null");
|
||||
}
|
||||
|
||||
if (var.hasMore) {
|
||||
defaultValue.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
if (cm.isMapModel) {
|
||||
defaultValue.append(", Map.empty");
|
||||
}
|
||||
|
||||
defaultValue.append(')');
|
||||
|
||||
return defaultValue.toString();
|
||||
}
|
||||
}
|
@ -88,6 +88,7 @@ org.openapitools.codegen.languages.ScalaAkkaClientCodegen
|
||||
org.openapitools.codegen.languages.ScalaHttpClientCodegen
|
||||
org.openapitools.codegen.languages.ScalaGatlingCodegen
|
||||
org.openapitools.codegen.languages.ScalaLagomServerCodegen
|
||||
org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen
|
||||
org.openapitools.codegen.languages.ScalazClientCodegen
|
||||
org.openapitools.codegen.languages.SpringCodegen
|
||||
org.openapitools.codegen.languages.StaticDocCodegen
|
||||
|
32
modules/openapi-generator/src/main/resources/scala-play-framework/README.md.mustache
vendored
Normal file
32
modules/openapi-generator/src/main/resources/scala-play-framework/README.md.mustache
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
# {{&appName}}
|
||||
|
||||
{{&appDescription}}
|
||||
|
||||
{{^hideGenerationTimestamp}}
|
||||
This Scala Play Framework project was generated by the OpenAPI generator tool at {{generatedDate}}.
|
||||
{{/hideGenerationTimestamp}}
|
||||
|
||||
{{#generateApis}}
|
||||
## API
|
||||
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
### {{baseName}}
|
||||
|
||||
|Name|Role|
|
||||
|----|----|
|
||||
|`{{importPath}}Controller`|Play Framework API controller|
|
||||
|`{{importPath}}Api`|Representing trait|
|
||||
{{^skipStubs}}
|
||||
|`{{importPath}}ApiImpl`|Default implementation|
|
||||
{{/skipStubs}}
|
||||
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
* `{{httpMethod}} {{contextPath}}{{path}}{{#queryParams.0}}?{{/queryParams.0}}{{#queryParams}}{{paramName}}=[value]{{#hasMore}}&{{/hasMore}}{{/queryParams}}` - {{summary}}
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
{{/generateApis}}
|
108
modules/openapi-generator/src/main/resources/scala-play-framework/app/apiController.scala.mustache
vendored
Normal file
108
modules/openapi-generator/src/main/resources/scala-play-framework/app/apiController.scala.mustache
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
package {{package}}
|
||||
|
||||
{{#generateCustomExceptions}}
|
||||
import {{basePackage}}.OpenApiExceptions
|
||||
{{/generateCustomExceptions}}
|
||||
import javax.inject.{Inject, Singleton}
|
||||
import play.api.libs.json._
|
||||
import play.api.mvc._
|
||||
{{#supportAsync}}
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
{{/supportAsync}}
|
||||
{{#imports}}
|
||||
import {{import}}
|
||||
{{/imports}}
|
||||
{{#operations}}
|
||||
|
||||
{{>generatedAnnotation}}
|
||||
@Singleton
|
||||
class {{classname}}Controller @Inject()(cc: ControllerComponents, api: {{classname}}){{#supportAsync}}(implicit executionContext: ExecutionContext){{/supportAsync}} extends AbstractController(cc) {
|
||||
{{#operation}}
|
||||
/**
|
||||
* {{httpMethod}} {{contextPath}}{{path}}{{#queryParams.0}}?{{/queryParams.0}}{{#queryParams}}{{paramName}}=[value]{{#hasMore}}&{{/hasMore}}{{/queryParams}}
|
||||
{{#pathParams}}
|
||||
{{#description}}
|
||||
* @param {{paramName}} {{description}}
|
||||
{{/description}}
|
||||
{{/pathParams}}
|
||||
*/
|
||||
def {{operationId}}({{#pathParams}}{{paramName}}: {{dataType}}{{#hasMore}}, {{/hasMore}}{{/pathParams}}): Action[AnyContent] = Action{{#supportAsync}}.async{{/supportAsync}} { request =>
|
||||
{{! Keep the execution result in its own block to prevent redeclaration of parameter names (however unlikely that might be). }}
|
||||
def executeApi(): {{>returnTypeOrUnit}} = {
|
||||
{{#bodyParams}}
|
||||
val {{paramName}} = request.body.asJson.map(_.as[{{dataType}}]){{#required}}.getOrElse {
|
||||
{{#generateCustomExceptions}}
|
||||
throw new OpenApiExceptions.MissingRequiredParameterException("body", "{{paramName}}")
|
||||
{{/generateCustomExceptions}}
|
||||
{{^generateCustomExceptions}}
|
||||
throw new IllegalArgumentException("Missing required body parameter.")
|
||||
{{/generateCustomExceptions}}
|
||||
}{{/required}}
|
||||
{{/bodyParams}}
|
||||
{{#headerParams}}
|
||||
val {{paramName}} = request.headers.get("{{baseName}}")
|
||||
{{#lambda.indented_8}}{{>app/transformParamValues}}{{/lambda.indented_8}}
|
||||
{{/headerParams}}
|
||||
{{#queryParams}}
|
||||
val {{paramName}} = request.{{#isCollectionFormatMulti}}queryString.get("{{baseName}}"){{/isCollectionFormatMulti}}{{^isCollectionFormatMulti}}getQueryString("{{baseName}}"){{/isCollectionFormatMulti}}
|
||||
{{#lambda.indented_8}}{{>app/transformParamValues}}{{/lambda.indented_8}}
|
||||
{{/queryParams}}
|
||||
{{#formParams}}
|
||||
{{#isFile}}
|
||||
val {{paramName}} = request.body.asMultipartFormData.flatMap(_.file("{{baseName}}").map(_.ref: {{dataType}}))
|
||||
{{#lambda.indented_8}}{{>app/transformParamValues}}{{/lambda.indented_8}}
|
||||
{{/isFile}}
|
||||
{{^isFile}}
|
||||
{{! TODO: Check if this fallback is required }}
|
||||
val {{paramName}} = (request.body.asMultipartFormData.map(_.asFormUrlEncoded) orElse request.body.asFormUrlEncoded)
|
||||
.flatMap(_.get("{{baseName}}"))
|
||||
{{^isCollectionFormatMulti}}
|
||||
.flatMap(_.headOption)
|
||||
{{/isCollectionFormatMulti}}
|
||||
{{#lambda.indented_8}}{{>app/transformParamValues}}{{/lambda.indented_8}}
|
||||
{{/isFile}}
|
||||
{{/formParams}}
|
||||
api.{{operationId}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
}
|
||||
|
||||
{{#supportAsync}}
|
||||
executeApi().map { {{#returnType}}result{{/returnType}}{{^returnType}}_{{/returnType}} =>
|
||||
{{/supportAsync}}
|
||||
{{^supportAsync}}
|
||||
{{#returnType}}
|
||||
val result = executeApi()
|
||||
{{/returnType}}
|
||||
{{^returnType}}
|
||||
executeApi()
|
||||
{{/returnType}}
|
||||
{{/supportAsync}}
|
||||
{{#returnType}}
|
||||
{{#supportAsync}} {{/supportAsync}}val json = Json.toJson(result)
|
||||
{{#supportAsync}} {{/supportAsync}}Ok(json)
|
||||
{{/returnType}}
|
||||
{{^returnType}}
|
||||
{{#supportAsync}} {{/supportAsync}}Ok
|
||||
{{/returnType}}
|
||||
{{#supportAsync}}
|
||||
}
|
||||
{{/supportAsync}}
|
||||
}{{#hasMore}}
|
||||
|
||||
{{/hasMore}}
|
||||
{{/operation}}
|
||||
|
||||
|
||||
private def splitCollectionParam(paramValues: String, collectionFormat: String): List[String] = {
|
||||
{{! Note: `+` is used to filter empty values when splitting }}
|
||||
val splitBy =
|
||||
collectionFormat match {
|
||||
case "csv" => ",+"
|
||||
case "tsv" => "\t+"
|
||||
case "ssv" => " +"
|
||||
case "pipes" => "|+"
|
||||
}
|
||||
|
||||
paramValues.split(splitBy).toList
|
||||
}
|
||||
}
|
||||
{{/operations}}
|
@ -0,0 +1,11 @@
|
||||
package {{apiPackage}}
|
||||
|
||||
import javax.inject.{Inject, Singleton}
|
||||
import play.api.mvc._
|
||||
|
||||
@Singleton
|
||||
class ApiDocController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
|
||||
def api: Action[AnyContent] = Action {
|
||||
Redirect("/assets/lib/swagger-ui/index.html?/url=/assets/openapi.json")
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package {{package}}
|
||||
|
||||
{{#supportAsync}}
|
||||
import scala.concurrent.Future
|
||||
{{/supportAsync}}
|
||||
{{#imports}}
|
||||
import {{import}}
|
||||
{{/imports}}
|
||||
{{#operations}}
|
||||
|
||||
/**
|
||||
* Provides a default implementation for [[{{classname}}]].
|
||||
*/
|
||||
{{>generatedAnnotation}}
|
||||
class {{classname}}Impl extends {{classname}} {
|
||||
{{#operation}}
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override {{>app/defOperationSignature}} = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
{{#supportAsync}}Future.successful({{/supportAsync}}{{^returnType}}{{#supportAsync}}(): Unit{{/supportAsync}}{{/returnType}}{{#returnType}}{{&defaultResponse}}{{/returnType}}{{#supportAsync}}){{/supportAsync}}
|
||||
}
|
||||
{{#hasMore}}
|
||||
|
||||
{{/hasMore}}
|
||||
{{/operation}}
|
||||
}
|
||||
{{/operations}}
|
33
modules/openapi-generator/src/main/resources/scala-play-framework/app/apiTrait.scala.mustache
vendored
Normal file
33
modules/openapi-generator/src/main/resources/scala-play-framework/app/apiTrait.scala.mustache
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
package {{package}}
|
||||
|
||||
{{#supportAsync}}
|
||||
import scala.concurrent.Future
|
||||
{{/supportAsync}}
|
||||
{{#imports}}
|
||||
import {{import}}
|
||||
{{/imports}}
|
||||
{{#operations}}
|
||||
|
||||
{{>generatedAnnotation}}
|
||||
trait {{classname}} {
|
||||
{{#operation}}
|
||||
/**
|
||||
{{#summary}}
|
||||
* {{summary}}
|
||||
{{/summary}}
|
||||
{{#notes}}
|
||||
* {{notes}}
|
||||
{{/notes}}
|
||||
{{#allParams}}
|
||||
{{#description}}
|
||||
* @param {{paramName}} {{description}}
|
||||
{{/description}}
|
||||
{{/allParams}}
|
||||
*/
|
||||
{{>app/defOperationSignature}}
|
||||
{{#hasMore}}
|
||||
|
||||
{{/hasMore}}
|
||||
{{/operation}}
|
||||
}
|
||||
{{/operations}}
|
@ -0,0 +1 @@
|
||||
def {{operationId}}({{#allParams}}{{paramName}}: {{^required}}Option[{{/required}}{{dataType}}{{^required}}]{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}): {{>returnTypeOrUnit}}
|
@ -0,0 +1,25 @@
|
||||
package {{basePackage}}
|
||||
|
||||
import play.api.http.DefaultHttpErrorHandler
|
||||
import play.api.libs.json.JsResultException
|
||||
import play.api.mvc.Results._
|
||||
import play.api.mvc.{RequestHeader, Result}
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
class ErrorHandler extends DefaultHttpErrorHandler {
|
||||
override def onServerError(request: RequestHeader, e: Throwable): Future[Result] = e match {
|
||||
{{#generateCustomExceptions}}
|
||||
case _: OpenApiExceptions.MissingRequiredParameterException =>
|
||||
{{/generateCustomExceptions}}
|
||||
{{^generateCustomExceptions}}
|
||||
case _: IllegalArgumentException =>
|
||||
{{/generateCustomExceptions}}
|
||||
Future.successful(BadRequest(e.getMessage))
|
||||
case _: JsResultException =>
|
||||
Future.successful(BadRequest(e.getMessage))
|
||||
case _ =>
|
||||
// Handles dev mode properly, or otherwise returns internal server error in production mode
|
||||
super.onServerError(request, e)
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package {{basePackage}}
|
||||
|
||||
object OpenApiExceptions {
|
||||
class MissingRequiredParameterException(paramName: String, paramType: String) extends Exception(s"Missing required $paramType parameter `$paramName`.")
|
||||
}
|
16
modules/openapi-generator/src/main/resources/scala-play-framework/app/module.scala.mustache
vendored
Normal file
16
modules/openapi-generator/src/main/resources/scala-play-framework/app/module.scala.mustache
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
package {{basePackage}}
|
||||
|
||||
import {{apiPackage}}._
|
||||
import play.api.inject.{Binding, Module => PlayModule}
|
||||
import play.api.{Configuration, Environment}
|
||||
|
||||
{{>generatedAnnotation}}
|
||||
class Module extends PlayModule {
|
||||
override def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]] = Seq(
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
bind[{{classname}}].to[{{classname}}Impl]{{#hasMore}},{{/hasMore}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
)
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
{{^isFile}}
|
||||
{{#collectionFormat}}
|
||||
{{^isCollectionFormatMulti}}
|
||||
.map(values => splitCollectionParam(values, "{{collectionFormat}}"))
|
||||
{{/isCollectionFormatMulti}}
|
||||
{{#isCollectionFormatMulti}}
|
||||
.map(_.toList)
|
||||
{{/isCollectionFormatMulti}}
|
||||
{{#items}}
|
||||
{{^isString}}
|
||||
.map(_.map(value => {{>convertParam}})
|
||||
{{/isString}}
|
||||
{{/items}}
|
||||
{{/collectionFormat}}
|
||||
{{^collectionFormat}}
|
||||
{{^isString}}
|
||||
.map(value => {{>convertParam}})
|
||||
{{/isString}}
|
||||
{{/collectionFormat}}
|
||||
{{/isFile}}
|
||||
{{#required}}
|
||||
.getOrElse {
|
||||
{{#generateCustomExceptions}}
|
||||
throw new OpenApiExceptions.MissingRequiredParameterException("{{baseName}}", "{{#isHeaderParam}}header{{/isHeaderParam}}{{#isQueryParam}}query string{{/isQueryParam}}{{#isFormParam}}form{{/isFormParam}}")
|
||||
{{/generateCustomExceptions}}
|
||||
{{^generateCustomExceptions}}
|
||||
throw new IllegalArgumentException("Missing {{#isHeaderParam}}header{{/isHeaderParam}}{{#isQueryParam}}query string{{/isQueryParam}}{{#isFormParam}}form{{/isFormParam}} parameter `{{baseName}}`.")
|
||||
{{/generateCustomExceptions}}
|
||||
}
|
||||
{{/required}}
|
7
modules/openapi-generator/src/main/resources/scala-play-framework/arrayCaseClass.mustache
vendored
Normal file
7
modules/openapi-generator/src/main/resources/scala-play-framework/arrayCaseClass.mustache
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
case class {{classname}}(items: {{parent}})
|
||||
|
||||
object {{classname}} {
|
||||
implicit lazy val {{classVarName}}JsonFormat: Format[{{classname}}] = {
|
||||
{{#lambda.indented_4}}{{>simpleParentJsonFormat}}{{/lambda.indented_4}}
|
||||
}
|
||||
}
|
16
modules/openapi-generator/src/main/resources/scala-play-framework/build.sbt.mustache
vendored
Normal file
16
modules/openapi-generator/src/main/resources/scala-play-framework/build.sbt.mustache
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
organization := "{{groupId}}"
|
||||
version := "{{artifactVersion}}"
|
||||
name := "{{artifactId}}"
|
||||
scalaVersion := "2.12.6"
|
||||
|
||||
enablePlugins(PlayScala)
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
guice,
|
||||
ws,
|
||||
{{#useSwaggerUI}}
|
||||
"org.webjars" % "swagger-ui" % "3.1.5",
|
||||
{{/useSwaggerUI}}
|
||||
"org.scalatest" %% "scalatest" % "3.0.4" % Test,
|
||||
"org.scalatestplus.play" %% "scalatestplus-play" % "3.1.2" % Test
|
||||
)
|
35
modules/openapi-generator/src/main/resources/scala-play-framework/caseClass.mustache
vendored
Normal file
35
modules/openapi-generator/src/main/resources/scala-play-framework/caseClass.mustache
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
case class {{classname}}(
|
||||
{{#vars}}
|
||||
{{&name}}: {{^required}}Option[{{/required}}{{#isEnum}}{{classname}}.{{enumName}}.Value{{/isEnum}}{{^isEnum}}{{dataType}}{{/isEnum}}{{^required}}]{{/required}}{{#hasMore}},{{/hasMore}}{{^hasMore}}{{#isMapModel}},{{/isMapModel}}{{/hasMore}}
|
||||
{{/vars}}
|
||||
{{#isMapModel}}
|
||||
additionalProperties: {{parent}}
|
||||
{{/isMapModel}}
|
||||
)
|
||||
|
||||
object {{classname}} {
|
||||
{{^vendorExtensions.hasFiles}}
|
||||
implicit lazy val {{classVarName}}JsonFormat: Format[{{classname}}] = {{^isMapModel}}Json.format[{{classname}}]{{/isMapModel}}{{#isMapModel}}{
|
||||
{{#lambda.indented_4}}{{>extensibleObjectJsonFormat}}{{/lambda.indented_4}}
|
||||
}{{/isMapModel}}
|
||||
{{/vendorExtensions.hasFiles}}
|
||||
{{#vendorExtensions.hasFiles}}
|
||||
// NOTE: The JSON format for {{classname}} was not generated because it contains a file variable which cannot be encoded to JSON.
|
||||
{{/vendorExtensions.hasFiles}}
|
||||
{{#vars}}
|
||||
{{#isEnum}}
|
||||
|
||||
// noinspection TypeAnnotation
|
||||
object {{enumName}} extends Enumeration {
|
||||
{{#allowableValues}}
|
||||
{{#enumVars}}
|
||||
val {{name}} = Value({{&value}})
|
||||
{{/enumVars}}
|
||||
{{/allowableValues}}
|
||||
|
||||
type {{enumName}} = Value
|
||||
implicit lazy val {{enumName}}JsonFormat: Format[Value] = Format(Reads.enumNameReads(this), Writes.enumNameWrites[this.type])
|
||||
}
|
||||
{{/isEnum}}
|
||||
{{/vars}}
|
||||
}
|
17
modules/openapi-generator/src/main/resources/scala-play-framework/conf/application.conf.mustache
vendored
Normal file
17
modules/openapi-generator/src/main/resources/scala-play-framework/conf/application.conf.mustache
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
# This is the main configuration file for the application.
|
||||
# Refer to https://www.playframework.com/documentation/latest/ConfigFile for more information.
|
||||
|
||||
play {
|
||||
filters.headers.contentSecurityPolicy = null
|
||||
modules.enabled += "{{basePackage}}.Module"
|
||||
|
||||
http {
|
||||
secret.key = "changeme"
|
||||
errorHandler = "{{basePackage}}.ErrorHandler"
|
||||
}
|
||||
|
||||
assets {
|
||||
path = "/public"
|
||||
urlPrefix = "/assets"
|
||||
}
|
||||
}
|
41
modules/openapi-generator/src/main/resources/scala-play-framework/conf/logback.xml.mustache
vendored
Normal file
41
modules/openapi-generator/src/main/resources/scala-play-framework/conf/logback.xml.mustache
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
<!-- https://www.playframework.com/documentation/latest/SettingsLogger -->
|
||||
<configuration>
|
||||
|
||||
<conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel" />
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||
<file>${application.home:-.}/logs/application.log</file>
|
||||
<encoder>
|
||||
<pattern>%date [%level] from %logger in %thread - %message%n%xException</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%coloredLevel %logger{15} - %message%n%xException{10}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<appender-ref ref="FILE" />
|
||||
</appender>
|
||||
|
||||
<appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</appender>
|
||||
|
||||
<logger name="play" level="INFO" />
|
||||
<logger name="application" level="DEBUG" />
|
||||
|
||||
<!-- Off these ones as they are annoying, and anyway we manage configuration ourselves -->
|
||||
<logger name="com.avaje.ebean.config.PropertyMapLoader" level="OFF" />
|
||||
<logger name="com.avaje.ebeaninternal.server.core.XmlConfigLoader" level="OFF" />
|
||||
<logger name="com.avaje.ebeaninternal.server.lib.BackgroundThread" level="OFF" />
|
||||
<logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF" />
|
||||
|
||||
<root level="WARN">
|
||||
<appender-ref ref="ASYNCFILE" />
|
||||
<appender-ref ref="ASYNCSTDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
35
modules/openapi-generator/src/main/resources/scala-play-framework/conf/routes.mustache
vendored
Normal file
35
modules/openapi-generator/src/main/resources/scala-play-framework/conf/routes.mustache
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
# Routes
|
||||
# This file defines all application routes (Higher priority routes first)
|
||||
# ~~~~
|
||||
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
|
||||
# Routes for {{{baseName}}} API
|
||||
{{! Note: operations with path parameters are emitted last to give them lower priority than operations with possibly more specific paths. }}
|
||||
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
{{^vendorExtensions.hasPathParams}}
|
||||
{{httpMethod}} {{{contextPath}}}{{{vendorExtensions.paddedPath}}} {{apiPackage}}.{{classname}}Controller.{{operationId}}()
|
||||
{{/vendorExtensions.hasPathParams}}
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
{{#vendorExtensions.hasPathParams}}
|
||||
{{httpMethod}} {{{contextPath}}}{{{vendorExtensions.paddedPath}}} {{apiPackage}}.{{classname}}Controller.{{operationId}}({{#pathParams}}{{paramName}}: {{#isUuid}}java.util.UUID{{/isUuid}}{{^isUuid}}{{{dataType}}}{{/isUuid}}{{#hasMore}}, {{/hasMore}}{{/pathParams}})
|
||||
{{/vendorExtensions.hasPathParams}}
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
|
||||
# Map static resources from the /public folder to the /assets URL path
|
||||
GET /assets/*file controllers.Assets.at(file)
|
||||
GET /versionedAssets/*file controllers.Assets.versioned(file)
|
||||
|
||||
{{#useSwaggerUI}}
|
||||
# Swagger UI
|
||||
GET /api {{apiPackage}}.ApiDocController.api
|
||||
{{/useSwaggerUI}}
|
1
modules/openapi-generator/src/main/resources/scala-play-framework/convertParam.mustache
vendored
Normal file
1
modules/openapi-generator/src/main/resources/scala-play-framework/convertParam.mustache
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{#isBoolean}}value.toBoolean{{/isBoolean}}{{#isInteger}}value.toInt{{/isInteger}}{{#isDouble}}value.toDouble{{/isDouble}}{{#isLong}}value.toLong{{/isLong}}{{#isFloat}}value.toFloat{{/isFloat}}{{#isUuid}}UUID.fromString(value){{/isUuid}}{{#isDateTime}}OffsetDateTime.parse(value){{/isDateTime}}{{#isDate}}LocalDate.parse(value){{/isDate}}{{#isByteArray}}value.getBytes(){{/isByteArray}}{{#isNumber}}BigDecimal(value){{/isNumber}}
|
1
modules/openapi-generator/src/main/resources/scala-play-framework/dataTypeOption.mustache
vendored
Normal file
1
modules/openapi-generator/src/main/resources/scala-play-framework/dataTypeOption.mustache
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{^required}}Option[{{/required}}{{dataType}}{{^required}}]{{/required}}
|
@ -0,0 +1,25 @@
|
||||
{{#hasVars}}
|
||||
val realJsonFormat = Json.format[{{classname}}]
|
||||
val declaredPropNames = Set({{#vars}}"{{&name}}"{{#hasMore}}, {{/hasMore}}{{/vars}})
|
||||
|
||||
Format(
|
||||
Reads {
|
||||
case JsObject(xs) =>
|
||||
val declaredProps = xs.filterKeys(declaredPropNames)
|
||||
val additionalProps = JsObject(xs -- declaredPropNames)
|
||||
val restructuredProps = declaredProps + ("additionalProperties" -> additionalProps)
|
||||
val newObj = JsObject(restructuredProps)
|
||||
realJsonFormat.reads(newObj)
|
||||
case _ =>
|
||||
JsError("error.expected.jsobject")
|
||||
},
|
||||
Writes { {{classVarName}} =>
|
||||
val jsObj = realJsonFormat.writes({{classVarName}})
|
||||
val additionalProps = jsObj.value("additionalProperties").as[JsObject]
|
||||
val declaredProps = jsObj - "additionalProperties"
|
||||
val newObj = declaredProps ++ additionalProps
|
||||
newObj
|
||||
}
|
||||
){{/hasVars}}{{^hasVars}}
|
||||
{{>simpleParentJsonFormat}}
|
||||
{{/hasVars}}
|
@ -0,0 +1 @@
|
||||
{{^hideGenerationTimestamp}}@javax.annotation.Generated(value = Array("{{generatorClass}}"), date = "{{generatedDate}}"){{/hideGenerationTimestamp}}
|
28
modules/openapi-generator/src/main/resources/scala-play-framework/model.mustache
vendored
Normal file
28
modules/openapi-generator/src/main/resources/scala-play-framework/model.mustache
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
package {{package}}
|
||||
|
||||
import play.api.libs.json._
|
||||
{{#imports}}
|
||||
import {{import}}
|
||||
{{/imports}}
|
||||
{{#models}}
|
||||
{{#model}}
|
||||
|
||||
/**
|
||||
* {{#description}}{{&.}}{{/description}}{{^description}}Represents the Swagger definition for {{name}}.{{/description}}{{#vars}}{{#description}}
|
||||
* @param {{&name}} {{&description}}{{/description}}{{/vars}}
|
||||
{{#isArrayModel}}
|
||||
* @param items The items of this array-like object.
|
||||
{{/isArrayModel}}
|
||||
{{#isMapModel}}
|
||||
* @param additionalProperties Any additional properties this model may have.
|
||||
{{/isMapModel}}
|
||||
*/
|
||||
{{>generatedAnnotation}}
|
||||
{{^isArrayModel}}
|
||||
{{>caseClass}}
|
||||
{{/isArrayModel}}
|
||||
{{#isArrayModel}}
|
||||
{{>arrayCaseClass}}
|
||||
{{/isArrayModel}}
|
||||
{{/model}}
|
||||
{{/models}}
|
@ -0,0 +1 @@
|
||||
sbt.version=1.2.4
|
@ -0,0 +1 @@
|
||||
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.18")
|
@ -0,0 +1 @@
|
||||
{{{openapi-json}}}
|
1
modules/openapi-generator/src/main/resources/scala-play-framework/returnTypeOrUnit.mustache
vendored
Normal file
1
modules/openapi-generator/src/main/resources/scala-play-framework/returnTypeOrUnit.mustache
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{#supportAsync}}Future[{{/supportAsync}}{{^returnType}}Unit{{/returnType}}{{#returnType}}{{returnType}}{{/returnType}}{{#supportAsync}}]{{/supportAsync}}
|
@ -0,0 +1,6 @@
|
||||
val innerFormat = Format.of[{{parent}}]
|
||||
|
||||
Format(
|
||||
innerFormat.map(inner => {{classname}}(inner)),
|
||||
{{classVarName}} => innerFormat.writes({{classVarName}}.{{#isArrayModel}}items{{/isArrayModel}}{{#isMapModel}}additionalProperties{{/isMapModel}}
|
||||
)
|
@ -0,0 +1,23 @@
|
||||
# OpenAPI Generator Ignore
|
||||
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||
|
||||
# Use this file to prevent files from being overwritten by the generator.
|
||||
# The patterns follow closely to .gitignore or .dockerignore.
|
||||
|
||||
# As an example, the C# client generator defines ApiClient.cs.
|
||||
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||
#ApiClient.cs
|
||||
|
||||
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||
#foo/*/qux
|
||||
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||
|
||||
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||
#foo/**/qux
|
||||
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||
|
||||
# You can also negate patterns with an exclamation (!).
|
||||
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||
#docs/*.md
|
||||
# Then explicitly reverse the ignore rule for a single file:
|
||||
#!docs/README.md
|
@ -0,0 +1 @@
|
||||
4.0.0-SNAPSHOT
|
55
samples/server/petstore/scala-play-framework/README.md
Normal file
55
samples/server/petstore/scala-play-framework/README.md
Normal file
@ -0,0 +1,55 @@
|
||||
# OpenAPI Petstore
|
||||
|
||||
This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
|
||||
|
||||
This Scala Play Framework project was generated by the OpenAPI generator tool at 2019-03-26T02:45:22.426+02:00[Asia/Jerusalem].
|
||||
|
||||
## API
|
||||
|
||||
### Pet
|
||||
|
||||
|Name|Role|
|
||||
|----|----|
|
||||
|`api.PetController`|Play Framework API controller|
|
||||
|`api.PetApi`|Representing trait|
|
||||
|`api.PetApiImpl`|Default implementation|
|
||||
|
||||
* `POST /pet` - Add a new pet to the store
|
||||
* `DELETE /pet/:petId` - Deletes a pet
|
||||
* `GET /pet/findByStatus?status=[value]` - Finds Pets by status
|
||||
* `GET /pet/findByTags?tags=[value]` - Finds Pets by tags
|
||||
* `GET /pet/:petId` - Find pet by ID
|
||||
* `PUT /pet` - Update an existing pet
|
||||
* `POST /pet/:petId` - Updates a pet in the store with form data
|
||||
* `POST /pet/:petId/uploadImage` - uploads an image
|
||||
|
||||
### Store
|
||||
|
||||
|Name|Role|
|
||||
|----|----|
|
||||
|`api.StoreController`|Play Framework API controller|
|
||||
|`api.StoreApi`|Representing trait|
|
||||
|`api.StoreApiImpl`|Default implementation|
|
||||
|
||||
* `DELETE /store/order/:orderId` - Delete purchase order by ID
|
||||
* `GET /store/inventory` - Returns pet inventories by status
|
||||
* `GET /store/order/:orderId` - Find purchase order by ID
|
||||
* `POST /store/order` - Place an order for a pet
|
||||
|
||||
### User
|
||||
|
||||
|Name|Role|
|
||||
|----|----|
|
||||
|`api.UserController`|Play Framework API controller|
|
||||
|`api.UserApi`|Representing trait|
|
||||
|`api.UserApiImpl`|Default implementation|
|
||||
|
||||
* `POST /user` - Create user
|
||||
* `POST /user/createWithArray` - Creates list of users with given input array
|
||||
* `POST /user/createWithList` - Creates list of users with given input array
|
||||
* `DELETE /user/:username` - Delete user
|
||||
* `GET /user/:username` - Get user by user name
|
||||
* `GET /user/login?username=[value]&password=[value]` - Logs user into the system
|
||||
* `GET /user/logout` - Logs out current logged in user session
|
||||
* `PUT /user/:username` - Updated user
|
||||
|
@ -0,0 +1,11 @@
|
||||
package api
|
||||
|
||||
import javax.inject.{Inject, Singleton}
|
||||
import play.api.mvc._
|
||||
|
||||
@Singleton
|
||||
class ApiDocController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
|
||||
def api: Action[AnyContent] = Action {
|
||||
Redirect("/assets/lib/swagger-ui/index.html?/url=/assets/openapi.json")
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package api
|
||||
|
||||
import model.ApiResponse
|
||||
import model.Pet
|
||||
import play.api.libs.Files.TemporaryFile
|
||||
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
trait PetApi {
|
||||
/**
|
||||
* Add a new pet to the store
|
||||
* @param body Pet object that needs to be added to the store
|
||||
*/
|
||||
def addPet(body: Pet): Unit
|
||||
|
||||
/**
|
||||
* Deletes a pet
|
||||
* @param petId Pet id to delete
|
||||
*/
|
||||
def deletePet(petId: Long, apiKey: Option[String]): Unit
|
||||
|
||||
/**
|
||||
* Finds Pets by status
|
||||
* Multiple status values can be provided with comma separated strings
|
||||
* @param status Status values that need to be considered for filter
|
||||
*/
|
||||
def findPetsByStatus(status: List[String]): List[Pet]
|
||||
|
||||
/**
|
||||
* Finds Pets by tags
|
||||
* Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.
|
||||
* @param tags Tags to filter by
|
||||
*/
|
||||
def findPetsByTags(tags: List[String]): List[Pet]
|
||||
|
||||
/**
|
||||
* Find pet by ID
|
||||
* Returns a single pet
|
||||
* @param petId ID of pet to return
|
||||
*/
|
||||
def getPetById(petId: Long): Pet
|
||||
|
||||
/**
|
||||
* Update an existing pet
|
||||
* @param body Pet object that needs to be added to the store
|
||||
*/
|
||||
def updatePet(body: Pet): Unit
|
||||
|
||||
/**
|
||||
* Updates a pet in the store with form data
|
||||
* @param petId ID of pet that needs to be updated
|
||||
* @param name Updated name of the pet
|
||||
* @param status Updated status of the pet
|
||||
*/
|
||||
def updatePetWithForm(petId: Long, name: Option[String], status: Option[String]): Unit
|
||||
|
||||
/**
|
||||
* uploads an image
|
||||
* @param petId ID of pet to update
|
||||
* @param additionalMetadata Additional data to pass to server
|
||||
* @param file file to upload
|
||||
*/
|
||||
def uploadFile(petId: Long, additionalMetadata: Option[String], file: Option[TemporaryFile]): ApiResponse
|
||||
}
|
@ -0,0 +1,161 @@
|
||||
package api
|
||||
|
||||
import org.openapitools.OpenApiExceptions
|
||||
import javax.inject.{Inject, Singleton}
|
||||
import play.api.libs.json._
|
||||
import play.api.mvc._
|
||||
import model.ApiResponse
|
||||
import model.Pet
|
||||
import play.api.libs.Files.TemporaryFile
|
||||
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
@Singleton
|
||||
class PetApiController @Inject()(cc: ControllerComponents, api: PetApi) extends AbstractController(cc) {
|
||||
/**
|
||||
* POST /pet
|
||||
*/
|
||||
def addPet(): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): Unit = {
|
||||
val body = request.body.asJson.map(_.as[Pet]).getOrElse {
|
||||
throw new OpenApiExceptions.MissingRequiredParameterException("body", "body")
|
||||
}
|
||||
api.addPet(body)
|
||||
}
|
||||
|
||||
executeApi()
|
||||
Ok
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /pet/:petId
|
||||
* @param petId Pet id to delete
|
||||
*/
|
||||
def deletePet(petId: Long): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): Unit = {
|
||||
val apiKey = request.headers.get("api_key")
|
||||
|
||||
api.deletePet(petId, apiKey)
|
||||
}
|
||||
|
||||
executeApi()
|
||||
Ok
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /pet/findByStatus?status=[value]
|
||||
*/
|
||||
def findPetsByStatus(): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): List[Pet] = {
|
||||
val status = request.getQueryString("status")
|
||||
.map(values => splitCollectionParam(values, "csv"))
|
||||
.getOrElse {
|
||||
throw new OpenApiExceptions.MissingRequiredParameterException("status", "query string")
|
||||
}
|
||||
api.findPetsByStatus(status)
|
||||
}
|
||||
|
||||
val result = executeApi()
|
||||
val json = Json.toJson(result)
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /pet/findByTags?tags=[value]
|
||||
*/
|
||||
def findPetsByTags(): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): List[Pet] = {
|
||||
val tags = request.getQueryString("tags")
|
||||
.map(values => splitCollectionParam(values, "csv"))
|
||||
.getOrElse {
|
||||
throw new OpenApiExceptions.MissingRequiredParameterException("tags", "query string")
|
||||
}
|
||||
api.findPetsByTags(tags)
|
||||
}
|
||||
|
||||
val result = executeApi()
|
||||
val json = Json.toJson(result)
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /pet/:petId
|
||||
* @param petId ID of pet to return
|
||||
*/
|
||||
def getPetById(petId: Long): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): Pet = {
|
||||
api.getPetById(petId)
|
||||
}
|
||||
|
||||
val result = executeApi()
|
||||
val json = Json.toJson(result)
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /pet
|
||||
*/
|
||||
def updatePet(): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): Unit = {
|
||||
val body = request.body.asJson.map(_.as[Pet]).getOrElse {
|
||||
throw new OpenApiExceptions.MissingRequiredParameterException("body", "body")
|
||||
}
|
||||
api.updatePet(body)
|
||||
}
|
||||
|
||||
executeApi()
|
||||
Ok
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /pet/:petId
|
||||
* @param petId ID of pet that needs to be updated
|
||||
*/
|
||||
def updatePetWithForm(petId: Long): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): Unit = {
|
||||
val name = (request.body.asMultipartFormData.map(_.asFormUrlEncoded) orElse request.body.asFormUrlEncoded)
|
||||
.flatMap(_.get("name"))
|
||||
.flatMap(_.headOption)
|
||||
|
||||
val status = (request.body.asMultipartFormData.map(_.asFormUrlEncoded) orElse request.body.asFormUrlEncoded)
|
||||
.flatMap(_.get("status"))
|
||||
.flatMap(_.headOption)
|
||||
|
||||
api.updatePetWithForm(petId, name, status)
|
||||
}
|
||||
|
||||
executeApi()
|
||||
Ok
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /pet/:petId/uploadImage
|
||||
* @param petId ID of pet to update
|
||||
*/
|
||||
def uploadFile(petId: Long): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): ApiResponse = {
|
||||
val additionalMetadata = (request.body.asMultipartFormData.map(_.asFormUrlEncoded) orElse request.body.asFormUrlEncoded)
|
||||
.flatMap(_.get("additionalMetadata"))
|
||||
.flatMap(_.headOption)
|
||||
|
||||
val file = request.body.asMultipartFormData.flatMap(_.file("file").map(_.ref: TemporaryFile))
|
||||
|
||||
api.uploadFile(petId, additionalMetadata, file)
|
||||
}
|
||||
|
||||
val result = executeApi()
|
||||
val json = Json.toJson(result)
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
private def splitCollectionParam(paramValues: String, collectionFormat: String): List[String] = {
|
||||
val splitBy =
|
||||
collectionFormat match {
|
||||
case "csv" => ",+"
|
||||
case "tsv" => "\t+"
|
||||
case "ssv" => " +"
|
||||
case "pipes" => "|+"
|
||||
}
|
||||
|
||||
paramValues.split(splitBy).toList
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package api
|
||||
|
||||
import model.ApiResponse
|
||||
import model.Pet
|
||||
import play.api.libs.Files.TemporaryFile
|
||||
|
||||
/**
|
||||
* Provides a default implementation for [[PetApi]].
|
||||
*/
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
class PetApiImpl extends PetApi {
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def addPet(body: Pet): Unit = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def deletePet(petId: Long, apiKey: Option[String]): Unit = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def findPetsByStatus(status: List[String]): List[Pet] = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
List.empty[Pet]
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def findPetsByTags(tags: List[String]): List[Pet] = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
List.empty[Pet]
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def getPetById(petId: Long): Pet = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
Pet(None, None, "", List.empty[String], None, None)
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def updatePet(body: Pet): Unit = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def updatePetWithForm(petId: Long, name: Option[String], status: Option[String]): Unit = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def uploadFile(petId: Long, additionalMetadata: Option[String], file: Option[TemporaryFile]): ApiResponse = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
ApiResponse(None, None, None)
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package api
|
||||
|
||||
import model.Order
|
||||
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
trait StoreApi {
|
||||
/**
|
||||
* Delete purchase order by ID
|
||||
* For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
|
||||
* @param orderId ID of the order that needs to be deleted
|
||||
*/
|
||||
def deleteOrder(orderId: String): Unit
|
||||
|
||||
/**
|
||||
* Returns pet inventories by status
|
||||
* Returns a map of status codes to quantities
|
||||
*/
|
||||
def getInventory(): Map[String, Int]
|
||||
|
||||
/**
|
||||
* Find purchase order by ID
|
||||
* For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions
|
||||
* @param orderId ID of pet that needs to be fetched
|
||||
*/
|
||||
def getOrderById(orderId: Long): Order
|
||||
|
||||
/**
|
||||
* Place an order for a pet
|
||||
* @param body order placed for purchasing the pet
|
||||
*/
|
||||
def placeOrder(body: Order): Order
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package api
|
||||
|
||||
import org.openapitools.OpenApiExceptions
|
||||
import javax.inject.{Inject, Singleton}
|
||||
import play.api.libs.json._
|
||||
import play.api.mvc._
|
||||
import model.Order
|
||||
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
@Singleton
|
||||
class StoreApiController @Inject()(cc: ControllerComponents, api: StoreApi) extends AbstractController(cc) {
|
||||
/**
|
||||
* DELETE /store/order/:orderId
|
||||
* @param orderId ID of the order that needs to be deleted
|
||||
*/
|
||||
def deleteOrder(orderId: String): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): Unit = {
|
||||
api.deleteOrder(orderId)
|
||||
}
|
||||
|
||||
executeApi()
|
||||
Ok
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /store/inventory
|
||||
*/
|
||||
def getInventory(): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): Map[String, Int] = {
|
||||
api.getInventory()
|
||||
}
|
||||
|
||||
val result = executeApi()
|
||||
val json = Json.toJson(result)
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /store/order/:orderId
|
||||
* @param orderId ID of pet that needs to be fetched
|
||||
*/
|
||||
def getOrderById(orderId: Long): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): Order = {
|
||||
api.getOrderById(orderId)
|
||||
}
|
||||
|
||||
val result = executeApi()
|
||||
val json = Json.toJson(result)
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /store/order
|
||||
*/
|
||||
def placeOrder(): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): Order = {
|
||||
val body = request.body.asJson.map(_.as[Order]).getOrElse {
|
||||
throw new OpenApiExceptions.MissingRequiredParameterException("body", "body")
|
||||
}
|
||||
api.placeOrder(body)
|
||||
}
|
||||
|
||||
val result = executeApi()
|
||||
val json = Json.toJson(result)
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
private def splitCollectionParam(paramValues: String, collectionFormat: String): List[String] = {
|
||||
val splitBy =
|
||||
collectionFormat match {
|
||||
case "csv" => ",+"
|
||||
case "tsv" => "\t+"
|
||||
case "ssv" => " +"
|
||||
case "pipes" => "|+"
|
||||
}
|
||||
|
||||
paramValues.split(splitBy).toList
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package api
|
||||
|
||||
import model.Order
|
||||
|
||||
/**
|
||||
* Provides a default implementation for [[StoreApi]].
|
||||
*/
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
class StoreApiImpl extends StoreApi {
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def deleteOrder(orderId: String): Unit = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def getInventory(): Map[String, Int] = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
Map.empty[String, Int]
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def getOrderById(orderId: Long): Order = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
Order(None, None, None, None, None, None)
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def placeOrder(body: Order): Order = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
Order(None, None, None, None, None, None)
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package api
|
||||
|
||||
import model.User
|
||||
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
trait UserApi {
|
||||
/**
|
||||
* Create user
|
||||
* This can only be done by the logged in user.
|
||||
* @param body Created user object
|
||||
*/
|
||||
def createUser(body: User): Unit
|
||||
|
||||
/**
|
||||
* Creates list of users with given input array
|
||||
* @param body List of user object
|
||||
*/
|
||||
def createUsersWithArrayInput(body: List[User]): Unit
|
||||
|
||||
/**
|
||||
* Creates list of users with given input array
|
||||
* @param body List of user object
|
||||
*/
|
||||
def createUsersWithListInput(body: List[User]): Unit
|
||||
|
||||
/**
|
||||
* Delete user
|
||||
* This can only be done by the logged in user.
|
||||
* @param username The name that needs to be deleted
|
||||
*/
|
||||
def deleteUser(username: String): Unit
|
||||
|
||||
/**
|
||||
* Get user by user name
|
||||
* @param username The name that needs to be fetched. Use user1 for testing.
|
||||
*/
|
||||
def getUserByName(username: String): User
|
||||
|
||||
/**
|
||||
* Logs user into the system
|
||||
* @param username The user name for login
|
||||
* @param password The password for login in clear text
|
||||
*/
|
||||
def loginUser(username: String, password: String): String
|
||||
|
||||
/**
|
||||
* Logs out current logged in user session
|
||||
*/
|
||||
def logoutUser(): Unit
|
||||
|
||||
/**
|
||||
* Updated user
|
||||
* This can only be done by the logged in user.
|
||||
* @param username name that need to be deleted
|
||||
* @param body Updated user object
|
||||
*/
|
||||
def updateUser(username: String, body: User): Unit
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
package api
|
||||
|
||||
import org.openapitools.OpenApiExceptions
|
||||
import javax.inject.{Inject, Singleton}
|
||||
import play.api.libs.json._
|
||||
import play.api.mvc._
|
||||
import model.User
|
||||
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
@Singleton
|
||||
class UserApiController @Inject()(cc: ControllerComponents, api: UserApi) extends AbstractController(cc) {
|
||||
/**
|
||||
* POST /user
|
||||
*/
|
||||
def createUser(): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): Unit = {
|
||||
val body = request.body.asJson.map(_.as[User]).getOrElse {
|
||||
throw new OpenApiExceptions.MissingRequiredParameterException("body", "body")
|
||||
}
|
||||
api.createUser(body)
|
||||
}
|
||||
|
||||
executeApi()
|
||||
Ok
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /user/createWithArray
|
||||
*/
|
||||
def createUsersWithArrayInput(): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): Unit = {
|
||||
val body = request.body.asJson.map(_.as[List[User]]).getOrElse {
|
||||
throw new OpenApiExceptions.MissingRequiredParameterException("body", "body")
|
||||
}
|
||||
api.createUsersWithArrayInput(body)
|
||||
}
|
||||
|
||||
executeApi()
|
||||
Ok
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /user/createWithList
|
||||
*/
|
||||
def createUsersWithListInput(): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): Unit = {
|
||||
val body = request.body.asJson.map(_.as[List[User]]).getOrElse {
|
||||
throw new OpenApiExceptions.MissingRequiredParameterException("body", "body")
|
||||
}
|
||||
api.createUsersWithListInput(body)
|
||||
}
|
||||
|
||||
executeApi()
|
||||
Ok
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /user/:username
|
||||
* @param username The name that needs to be deleted
|
||||
*/
|
||||
def deleteUser(username: String): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): Unit = {
|
||||
api.deleteUser(username)
|
||||
}
|
||||
|
||||
executeApi()
|
||||
Ok
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /user/:username
|
||||
* @param username The name that needs to be fetched. Use user1 for testing.
|
||||
*/
|
||||
def getUserByName(username: String): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): User = {
|
||||
api.getUserByName(username)
|
||||
}
|
||||
|
||||
val result = executeApi()
|
||||
val json = Json.toJson(result)
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /user/login?username=[value]&password=[value]
|
||||
*/
|
||||
def loginUser(): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): String = {
|
||||
val username = request.getQueryString("username")
|
||||
.getOrElse {
|
||||
throw new OpenApiExceptions.MissingRequiredParameterException("username", "query string")
|
||||
}
|
||||
val password = request.getQueryString("password")
|
||||
.getOrElse {
|
||||
throw new OpenApiExceptions.MissingRequiredParameterException("password", "query string")
|
||||
}
|
||||
api.loginUser(username, password)
|
||||
}
|
||||
|
||||
val result = executeApi()
|
||||
val json = Json.toJson(result)
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /user/logout
|
||||
*/
|
||||
def logoutUser(): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): Unit = {
|
||||
api.logoutUser()
|
||||
}
|
||||
|
||||
executeApi()
|
||||
Ok
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /user/:username
|
||||
* @param username name that need to be deleted
|
||||
*/
|
||||
def updateUser(username: String): Action[AnyContent] = Action { request =>
|
||||
def executeApi(): Unit = {
|
||||
val body = request.body.asJson.map(_.as[User]).getOrElse {
|
||||
throw new OpenApiExceptions.MissingRequiredParameterException("body", "body")
|
||||
}
|
||||
api.updateUser(username, body)
|
||||
}
|
||||
|
||||
executeApi()
|
||||
Ok
|
||||
}
|
||||
|
||||
private def splitCollectionParam(paramValues: String, collectionFormat: String): List[String] = {
|
||||
val splitBy =
|
||||
collectionFormat match {
|
||||
case "csv" => ",+"
|
||||
case "tsv" => "\t+"
|
||||
case "ssv" => " +"
|
||||
case "pipes" => "|+"
|
||||
}
|
||||
|
||||
paramValues.split(splitBy).toList
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package api
|
||||
|
||||
import model.User
|
||||
|
||||
/**
|
||||
* Provides a default implementation for [[UserApi]].
|
||||
*/
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
class UserApiImpl extends UserApi {
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def createUser(body: User): Unit = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def createUsersWithArrayInput(body: List[User]): Unit = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def createUsersWithListInput(body: List[User]): Unit = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def deleteUser(username: String): Unit = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def getUserByName(username: String): User = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
User(None, None, None, None, None, None, None, None)
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def loginUser(username: String, password: String): String = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
""
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def logoutUser(): Unit = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
override def updateUser(username: String, body: User): Unit = {
|
||||
// TODO: Implement better logic
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package model
|
||||
|
||||
import play.api.libs.json._
|
||||
|
||||
/**
|
||||
* Describes the result of uploading an image resource
|
||||
*/
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
case class ApiResponse(
|
||||
code: Option[Int],
|
||||
`type`: Option[String],
|
||||
message: Option[String]
|
||||
)
|
||||
|
||||
object ApiResponse {
|
||||
implicit lazy val apiResponseJsonFormat: Format[ApiResponse] = Json.format[ApiResponse]
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
package model
|
||||
|
||||
import play.api.libs.json._
|
||||
|
||||
/**
|
||||
* A category for a pet
|
||||
*/
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
case class Category(
|
||||
id: Option[Long],
|
||||
name: Option[String]
|
||||
)
|
||||
|
||||
object Category {
|
||||
implicit lazy val categoryJsonFormat: Format[Category] = Json.format[Category]
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
package model
|
||||
|
||||
import play.api.libs.json._
|
||||
import java.time.OffsetDateTime
|
||||
|
||||
/**
|
||||
* An order for a pets from the pet store
|
||||
* @param status Order Status
|
||||
*/
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
case class Order(
|
||||
id: Option[Long],
|
||||
petId: Option[Long],
|
||||
quantity: Option[Int],
|
||||
shipDate: Option[OffsetDateTime],
|
||||
status: Option[Order.Status.Value],
|
||||
complete: Option[Boolean]
|
||||
)
|
||||
|
||||
object Order {
|
||||
implicit lazy val orderJsonFormat: Format[Order] = Json.format[Order]
|
||||
|
||||
// noinspection TypeAnnotation
|
||||
object Status extends Enumeration {
|
||||
val Placed = Value("placed")
|
||||
val Approved = Value("approved")
|
||||
val Delivered = Value("delivered")
|
||||
|
||||
type Status = Value
|
||||
implicit lazy val StatusJsonFormat: Format[Value] = Format(Reads.enumNameReads(this), Writes.enumNameWrites[this.type])
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
package model
|
||||
|
||||
import play.api.libs.json._
|
||||
|
||||
/**
|
||||
* A pet for sale in the pet store
|
||||
* @param status pet status in the store
|
||||
*/
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
case class Pet(
|
||||
id: Option[Long],
|
||||
category: Option[Category],
|
||||
name: String,
|
||||
photoUrls: List[String],
|
||||
tags: Option[List[Tag]],
|
||||
status: Option[Pet.Status.Value]
|
||||
)
|
||||
|
||||
object Pet {
|
||||
implicit lazy val petJsonFormat: Format[Pet] = Json.format[Pet]
|
||||
|
||||
// noinspection TypeAnnotation
|
||||
object Status extends Enumeration {
|
||||
val Available = Value("available")
|
||||
val Pending = Value("pending")
|
||||
val Sold = Value("sold")
|
||||
|
||||
type Status = Value
|
||||
implicit lazy val StatusJsonFormat: Format[Value] = Format(Reads.enumNameReads(this), Writes.enumNameWrites[this.type])
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
package model
|
||||
|
||||
import play.api.libs.json._
|
||||
|
||||
/**
|
||||
* A tag for a pet
|
||||
*/
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
case class Tag(
|
||||
id: Option[Long],
|
||||
name: Option[String]
|
||||
)
|
||||
|
||||
object Tag {
|
||||
implicit lazy val tagJsonFormat: Format[Tag] = Json.format[Tag]
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
package model
|
||||
|
||||
import play.api.libs.json._
|
||||
|
||||
/**
|
||||
* A User who is purchasing from the pet store
|
||||
* @param userStatus User Status
|
||||
*/
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
case class User(
|
||||
id: Option[Long],
|
||||
username: Option[String],
|
||||
firstName: Option[String],
|
||||
lastName: Option[String],
|
||||
email: Option[String],
|
||||
password: Option[String],
|
||||
phone: Option[String],
|
||||
userStatus: Option[Int]
|
||||
)
|
||||
|
||||
object User {
|
||||
implicit lazy val userJsonFormat: Format[User] = Json.format[User]
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package org.openapitools
|
||||
|
||||
import play.api.http.DefaultHttpErrorHandler
|
||||
import play.api.libs.json.JsResultException
|
||||
import play.api.mvc.Results._
|
||||
import play.api.mvc.{RequestHeader, Result}
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
class ErrorHandler extends DefaultHttpErrorHandler {
|
||||
override def onServerError(request: RequestHeader, e: Throwable): Future[Result] = e match {
|
||||
case _: OpenApiExceptions.MissingRequiredParameterException =>
|
||||
Future.successful(BadRequest(e.getMessage))
|
||||
case _: JsResultException =>
|
||||
Future.successful(BadRequest(e.getMessage))
|
||||
case _ =>
|
||||
// Handles dev mode properly, or otherwise returns internal server error in production mode
|
||||
super.onServerError(request, e)
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package org.openapitools
|
||||
|
||||
import api._
|
||||
import play.api.inject.{Binding, Module => PlayModule}
|
||||
import play.api.{Configuration, Environment}
|
||||
|
||||
@javax.annotation.Generated(value = Array("org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen"), date = "2019-03-26T02:45:22.426+02:00[Asia/Jerusalem]")
|
||||
class Module extends PlayModule {
|
||||
override def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]] = Seq(
|
||||
bind[PetApi].to[PetApiImpl],
|
||||
bind[StoreApi].to[StoreApiImpl],
|
||||
bind[UserApi].to[UserApiImpl]
|
||||
)
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package org.openapitools
|
||||
|
||||
object OpenApiExceptions {
|
||||
class MissingRequiredParameterException(paramName: String, paramType: String) extends Exception(s"Missing required $paramType parameter `$paramName`.")
|
||||
}
|
14
samples/server/petstore/scala-play-framework/build.sbt
Normal file
14
samples/server/petstore/scala-play-framework/build.sbt
Normal file
@ -0,0 +1,14 @@
|
||||
organization := ""
|
||||
version := ""
|
||||
name := ""
|
||||
scalaVersion := "2.12.6"
|
||||
|
||||
enablePlugins(PlayScala)
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
guice,
|
||||
ws,
|
||||
"org.webjars" % "swagger-ui" % "3.1.5",
|
||||
"org.scalatest" %% "scalatest" % "3.0.4" % Test,
|
||||
"org.scalatestplus.play" %% "scalatestplus-play" % "3.1.2" % Test
|
||||
)
|
@ -0,0 +1,17 @@
|
||||
# This is the main configuration file for the application.
|
||||
# Refer to https://www.playframework.com/documentation/latest/ConfigFile for more information.
|
||||
|
||||
play {
|
||||
filters.headers.contentSecurityPolicy = null
|
||||
modules.enabled += "org.openapitools.Module"
|
||||
|
||||
http {
|
||||
secret.key = "changeme"
|
||||
errorHandler = "org.openapitools.ErrorHandler"
|
||||
}
|
||||
|
||||
assets {
|
||||
path = "/public"
|
||||
urlPrefix = "/assets"
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
<!-- https://www.playframework.com/documentation/latest/SettingsLogger -->
|
||||
<configuration>
|
||||
|
||||
<conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel" />
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||
<file>${application.home:-.}/logs/application.log</file>
|
||||
<encoder>
|
||||
<pattern>%date [%level] from %logger in %thread - %message%n%xException</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%coloredLevel %logger{15} - %message%n%xException{10}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<appender-ref ref="FILE" />
|
||||
</appender>
|
||||
|
||||
<appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</appender>
|
||||
|
||||
<logger name="play" level="INFO" />
|
||||
<logger name="application" level="DEBUG" />
|
||||
|
||||
<!-- Off these ones as they are annoying, and anyway we manage configuration ourselves -->
|
||||
<logger name="com.avaje.ebean.config.PropertyMapLoader" level="OFF" />
|
||||
<logger name="com.avaje.ebeaninternal.server.core.XmlConfigLoader" level="OFF" />
|
||||
<logger name="com.avaje.ebeaninternal.server.lib.BackgroundThread" level="OFF" />
|
||||
<logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF" />
|
||||
|
||||
<root level="WARN">
|
||||
<appender-ref ref="ASYNCFILE" />
|
||||
<appender-ref ref="ASYNCSTDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
40
samples/server/petstore/scala-play-framework/conf/routes
Normal file
40
samples/server/petstore/scala-play-framework/conf/routes
Normal file
@ -0,0 +1,40 @@
|
||||
# Routes
|
||||
# This file defines all application routes (Higher priority routes first)
|
||||
# ~~~~
|
||||
|
||||
|
||||
# Routes for Pet API
|
||||
|
||||
POST /v2/pet api.PetApiController.addPet()
|
||||
GET /v2/pet/findByStatus api.PetApiController.findPetsByStatus()
|
||||
GET /v2/pet/findByTags api.PetApiController.findPetsByTags()
|
||||
PUT /v2/pet api.PetApiController.updatePet()
|
||||
DELETE /v2/pet/:petId api.PetApiController.deletePet(petId: Long)
|
||||
GET /v2/pet/:petId api.PetApiController.getPetById(petId: Long)
|
||||
POST /v2/pet/:petId api.PetApiController.updatePetWithForm(petId: Long)
|
||||
POST /v2/pet/:petId/uploadImage api.PetApiController.uploadFile(petId: Long)
|
||||
|
||||
# Routes for Store API
|
||||
|
||||
GET /v2/store/inventory api.StoreApiController.getInventory()
|
||||
POST /v2/store/order api.StoreApiController.placeOrder()
|
||||
DELETE /v2/store/order/:orderId api.StoreApiController.deleteOrder(orderId: String)
|
||||
GET /v2/store/order/:orderId api.StoreApiController.getOrderById(orderId: Long)
|
||||
|
||||
# Routes for User API
|
||||
|
||||
POST /v2/user api.UserApiController.createUser()
|
||||
POST /v2/user/createWithArray api.UserApiController.createUsersWithArrayInput()
|
||||
POST /v2/user/createWithList api.UserApiController.createUsersWithListInput()
|
||||
GET /v2/user/login api.UserApiController.loginUser()
|
||||
GET /v2/user/logout api.UserApiController.logoutUser()
|
||||
DELETE /v2/user/:username api.UserApiController.deleteUser(username: String)
|
||||
GET /v2/user/:username api.UserApiController.getUserByName(username: String)
|
||||
PUT /v2/user/:username api.UserApiController.updateUser(username: String)
|
||||
|
||||
# Map static resources from the /public folder to the /assets URL path
|
||||
GET /assets/*file controllers.Assets.at(file)
|
||||
GET /versionedAssets/*file controllers.Assets.versioned(file)
|
||||
|
||||
# Swagger UI
|
||||
GET /api api.ApiDocController.api
|
@ -0,0 +1 @@
|
||||
sbt.version=1.2.4
|
@ -0,0 +1 @@
|
||||
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.18")
|
1012
samples/server/petstore/scala-play-framework/public/openapi.json
Normal file
1012
samples/server/petstore/scala-play-framework/public/openapi.json
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user