diff --git a/bin/configs/scala-cask-petstore.yaml b/bin/configs/scala-cask-petstore.yaml
index bb37d3587e7..283d643de95 100644
--- a/bin/configs/scala-cask-petstore.yaml
+++ b/bin/configs/scala-cask-petstore.yaml
@@ -1,6 +1,6 @@
generatorName: scala-cask
outputDir: samples/server/petstore/scala-cask
-inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
+inputSpec: modules/openapi-generator/src/test/resources/3_0/scala-cask/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/scala-cask
additionalProperties:
hideGenerationTimestamp: "true"
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ScalaCaskServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ScalaCaskServerCodegen.java
index 1ac6e0a3fea..b257e2eba22 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ScalaCaskServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ScalaCaskServerCodegen.java
@@ -18,6 +18,7 @@ package org.openapitools.codegen.languages;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.media.Schema;
+import io.swagger.v3.oas.models.parameters.RequestBody;
import org.apache.commons.io.FileUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.model.ModelMap;
@@ -394,6 +395,12 @@ public class ScalaCaskServerCodegen extends AbstractScalaCodegen implements Code
}
+ /**
+ * This class is used in pathExtractorParams.mustache.
+ *
+ * It exposes some methods which make it more readable
+ * for that mustache snippet, and also isolates the logic needed for the path extractors
+ */
public static class ParamPart {
final CodegenParameter param;
final String name;
@@ -416,7 +423,9 @@ public class ScalaCaskServerCodegen extends AbstractScalaCodegen implements Code
}
/**
- * Cask will compile but 'initialize' can throw a route overlap exception:
+ * This data structure is here to manually identify and fix routes which will overlap (e.g. GET /foo/bar and GET /foo/bazz)
+ *
+ * If we added these as individual routes, then Cask itself will compile, but calling 'initialize' throws a route overlap exception:
*
* {{{
* Routes overlap with wildcards: get /user/logout, get /user/:username, get /user/login
@@ -672,9 +681,12 @@ public class ScalaCaskServerCodegen extends AbstractScalaCodegen implements Code
model.getVars().forEach(this::postProcessProperty);
model.getAllVars().forEach(this::postProcessProperty);
+
+
+ model.vendorExtensions.put("x-has-one-of", model.oneOf != null && !model.oneOf.isEmpty());
}
- private static void postProcessOperation(CodegenOperation op) {
+ private static void postProcessOperation(final CodegenOperation op) {
// force http method to lower case
op.httpMethod = op.httpMethod.toLowerCase(Locale.ROOT);
@@ -710,9 +722,33 @@ public class ScalaCaskServerCodegen extends AbstractScalaCodegen implements Code
.collect(Collectors.toCollection(LinkedHashSet::new));
var responseType = responses.isEmpty() ? "Unit" : String.join(" | ", responses);
+ op.vendorExtensions.put("x-import-response-implicits", importResponseImplicits(op));
op.vendorExtensions.put("x-response-type", responseType);
}
+ /**
+ * We need to bring the response type into scope in order to use the upickle implicits
+ * only if the response type has a 'oneOf' type, which means it's a union type with a
+ * companion object containing the ReadWriter
+ *
+ * @param op
+ * @return true if we need to provide an import
+ */
+ private static boolean importResponseImplicits(final CodegenOperation op) {
+ final Set importBlacklist = Set.of("File");
+
+ boolean doImport = false;
+ for (var response : op.responses) {
+ // we should ignore generic types like Seq[...] or Map[..] types
+ var isPolymorphic = response.dataType != null && response.dataType.contains("[");
+ if (response.isModel && !importBlacklist.contains(response.dataType) && !isPolymorphic) {
+ doImport = true;
+ break;
+ }
+ }
+ return doImport;
+ }
+
/**
* primitive or enum types don't have Data representations
* @param p the property
@@ -747,6 +783,10 @@ public class ScalaCaskServerCodegen extends AbstractScalaCodegen implements Code
return "byte".equalsIgnoreCase(p.dataFormat); // &&
}
+ private static boolean wrapInOptional(CodegenProperty p) {
+ return !p.required && !p.isArray && !p.isMap;
+ }
+
/**
* this parameter is used to create the function:
* {{{
@@ -761,19 +801,18 @@ public class ScalaCaskServerCodegen extends AbstractScalaCodegen implements Code
* and then back again
*/
private static String asDataCode(final CodegenProperty p, final Set typesWhichDoNotNeedMapping) {
- final var wrapInOptional = !p.required && !p.isArray && !p.isMap;
String code = "";
String dv = defaultValueNonOption(p, p.defaultValue);
if (doesNotNeedMapping(p, typesWhichDoNotNeedMapping)) {
- if (wrapInOptional) {
+ if (wrapInOptional(p)) {
code = String.format(Locale.ROOT, "%s.getOrElse(%s) /* 1 */", p.name, dv);
} else {
code = String.format(Locale.ROOT, "%s /* 2 */", p.name);
}
} else {
- if (wrapInOptional) {
+ if (wrapInOptional(p)) {
if (isByteArray(p)) {
code = String.format(Locale.ROOT, "%s.getOrElse(%s) /* 3 */", p.name, dv);
} else {
@@ -782,11 +821,15 @@ public class ScalaCaskServerCodegen extends AbstractScalaCodegen implements Code
} else if (p.isArray) {
if (isByteArray(p)) {
code = String.format(Locale.ROOT, "%s /* 5 */", p.name);
+ } else if (!isObjectArray(p)) {
+ code = String.format(Locale.ROOT, "%s /* 5.1 */", p.name);
} else {
code = String.format(Locale.ROOT, "%s.map(_.asData) /* 6 */", p.name);
}
+ } else if (p.isMap) {
+ code = String.format(Locale.ROOT, "%s /* 7 */", p.name);
} else {
- code = String.format(Locale.ROOT, "%s.asData /* 7 */", p.name);
+ code = String.format(Locale.ROOT, "%s.asData /* 8 */", p.name);
}
}
return code;
@@ -807,17 +850,16 @@ public class ScalaCaskServerCodegen extends AbstractScalaCodegen implements Code
* @return
*/
private static String asModelCode(final CodegenProperty p, final Set typesWhichDoNotNeedMapping) {
- final var wrapInOptional = !p.required && !p.isArray && !p.isMap;
String code = "";
if (doesNotNeedMapping(p, typesWhichDoNotNeedMapping)) {
- if (wrapInOptional) {
+ if (wrapInOptional(p)) {
code = String.format(Locale.ROOT, "Option(%s) /* 1 */", p.name);
} else {
code = String.format(Locale.ROOT, "%s /* 2 */", p.name);
}
} else {
- if (wrapInOptional) {
+ if (wrapInOptional(p)) {
if (isByteArray(p)) {
code = String.format(Locale.ROOT, "Option(%s) /* 3 */", p.name);
} else {
@@ -825,6 +867,8 @@ public class ScalaCaskServerCodegen extends AbstractScalaCodegen implements Code
}
} else if (p.isArray) {
code = String.format(Locale.ROOT, "%s.map(_.asModel) /* 5 */", p.name);
+ } else if (p.isMap) {
+ code = String.format(Locale.ROOT, "%s /* 5.1 */", p.name);
} else {
code = String.format(Locale.ROOT, "%s.asModel /* 6 */", p.name);
}
@@ -863,8 +907,17 @@ public class ScalaCaskServerCodegen extends AbstractScalaCodegen implements Code
return text;
}
+ private static boolean hasItemModel(final CodegenProperty p) {
+ return p.items != null && p.items.isModel;
+ }
+
+ private static boolean isObjectArray(final CodegenProperty p) {
+ return p.isArray && hasItemModel(p);
+ }
+
private void postProcessProperty(final CodegenProperty p) {
- p.vendorExtensions.put("x-datatype-model", asScalaDataType(p, p.required, false));
+
+ p.vendorExtensions.put("x-datatype-model", asScalaDataType(p, p.required, false, wrapInOptional(p)));
p.vendorExtensions.put("x-defaultValue-model", defaultValue(p, p.required, p.defaultValue));
final String dataTypeData = asScalaDataType(p, p.required, true);
p.vendorExtensions.put("x-datatype-data", dataTypeData);
@@ -878,7 +931,7 @@ public class ScalaCaskServerCodegen extends AbstractScalaCodegen implements Code
p._enum = p._enum.stream().map(this::ensureNonKeyword).collect(Collectors.toList());
}
- /**
+ /*
* This is a fix for the enum property "type" declared like this:
* {{{
* type:
@@ -908,6 +961,9 @@ public class ScalaCaskServerCodegen extends AbstractScalaCodegen implements Code
)).collect(Collectors.toSet());
typesWhichShouldNotBeMapped.add("byte");
+ // when deserialising map objects, the logic is tricky.
+ p.vendorExtensions.put("x-deserialize-asModelMap", p.isMap && hasItemModel(p));
+
// the 'asModel' logic for modelData.mustache
//
// if it's optional (not required), then wrap the value in Option()
@@ -916,16 +972,6 @@ public class ScalaCaskServerCodegen extends AbstractScalaCodegen implements Code
p.vendorExtensions.put("x-asData", asDataCode(p, typesWhichShouldNotBeMapped));
p.vendorExtensions.put("x-asModel", asModelCode(p, typesWhichShouldNotBeMapped));
- // if it's an array or optional, we need to map it as a model -- unless it's a map,
- // in which case we have to map the values
- boolean hasItemModel = p.items != null && p.items.isModel;
- boolean isObjectArray = p.isArray && hasItemModel;
- boolean isOptionalObj = !p.required && p.isModel;
- p.vendorExtensions.put("x-map-asModel", (isOptionalObj || isObjectArray) && !p.isMap);
-
- // when deserialising map objects, the logic is tricky.
- p.vendorExtensions.put("x-deserialize-asModelMap", p.isMap && hasItemModel);
-
// for some reason, an openapi spec with pattern field like this:
// pattern: '^[A-Za-z]+$'
// will result in the pattern property text of
@@ -934,6 +980,20 @@ public class ScalaCaskServerCodegen extends AbstractScalaCodegen implements Code
p.pattern = p.pattern.substring(1, p.pattern.length() - 1);
}
+ // in our model class definition laid out in modelClass.mustache, we use 'Option' for non-required
+ // properties only when they don't have a sensible 'empty' value (e.g. maps and lists).
+ //
+ // that is to say, we're trying to avoid having:
+ //
+ // someOptionalField : Option[Seq[Foo]]
+ //
+ // when we could just have e.g.
+ //
+ // someOptionalField : Seq[Foo]
+ //
+ // with an empty value
+ p.vendorExtensions.put("x-model-needs-option", wrapInOptional(p));
+
}
diff --git a/modules/openapi-generator/src/main/resources/scala-cask/apiRoutes.mustache b/modules/openapi-generator/src/main/resources/scala-cask/apiRoutes.mustache
index 53dc0710494..b2167d0cd53 100644
--- a/modules/openapi-generator/src/main/resources/scala-cask/apiRoutes.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-cask/apiRoutes.mustache
@@ -45,6 +45,10 @@ class {{classname}}Routes(service : {{classname}}Service[Try]) extends cask.Rout
val result = {{>parseHttpParams}}
+ {{#vendorExtensions.x-import-response-implicits}}
+ import {{vendorExtensions.x-response-type}}.{given, *} // this brings in upickle in the case of union (oneOf) types
+ {{/vendorExtensions.x-import-response-implicits}}
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
{{#responses}}
diff --git a/modules/openapi-generator/src/main/resources/scala-cask/model.mustache b/modules/openapi-generator/src/main/resources/scala-cask/model.mustache
index 6e8551c5b05..31b48759877 100644
--- a/modules/openapi-generator/src/main/resources/scala-cask/model.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-cask/model.mustache
@@ -13,12 +13,24 @@ import upickle.default.*
{{#models}}
{{#model}}
-{{#isEnum}}
-{{>modelEnum}}
-{{/isEnum}}
-{{^isEnum}}
-{{>modelClass}}
-{{/isEnum}}
+{{#vendorExtensions.x-has-one-of}}
+
+type {{classname}} = {{#oneOf}}{{{.}}}{{^-last}} | {{/-last}}{{/oneOf}}
+object {{{classname}}} {
+
+ given RW[{{{classname}}}] = RW.merge({{#oneOf}}summon[RW[{{{.}}}]]{{^-last}}, {{/-last}}{{/oneOf}})
+}
+
+{{/vendorExtensions.x-has-one-of}}
+{{^vendorExtensions.x-has-one-of}}
+ {{#isEnum}}
+ {{>modelEnum}}
+ {{/isEnum}}
+ {{^isEnum}}
+ {{>modelClass}}
+ {{/isEnum}}
+{{/vendorExtensions.x-has-one-of}}
+
{{/model}}
{{/models}}
diff --git a/modules/openapi-generator/src/main/resources/scala-cask/modelClass.mustache b/modules/openapi-generator/src/main/resources/scala-cask/modelClass.mustache
index 9cf9cf3102f..12f4ced6b08 100644
--- a/modules/openapi-generator/src/main/resources/scala-cask/modelClass.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-cask/modelClass.mustache
@@ -4,7 +4,7 @@ case class {{classname}}(
{{#description}}
/* {{{description}}} */
{{/description}}
- {{name}}: {{#isEnum}}{{^required}}Option[{{/required}}{{classname}}.{{datatypeWithEnum}}{{^required}}]{{/required}}{{/isEnum}}{{^isEnum}}{{{vendorExtensions.x-datatype-model}}}{{/isEnum}}{{^required}} = {{{vendorExtensions.x-defaultValue-model}}} {{/required}}{{^-last}},{{/-last}}
+ {{name}}: {{#isEnum}}{{#vendorExtensions.x-model-needs-option}}Option[{{/vendorExtensions.x-model-needs-option}}{{classname}}.{{datatypeWithEnum}}{{#vendorExtensions.x-model-needs-option}}]{{/vendorExtensions.x-model-needs-option}}{{/isEnum}}{{^isEnum}}{{{vendorExtensions.x-datatype-model}}}{{/isEnum}}{{^required}} = {{{vendorExtensions.x-defaultValue-model}}} {{/required}}{{^-last}},{{/-last}}
{{/vars}}
{{#isAdditionalPropertiesTrue}}, additionalProperties : ujson.Value = ujson.Null{{/isAdditionalPropertiesTrue}}
diff --git a/modules/openapi-generator/src/main/resources/scala-cask/modelData.mustache b/modules/openapi-generator/src/main/resources/scala-cask/modelData.mustache
index 14a8e12ee91..91c580352a1 100644
--- a/modules/openapi-generator/src/main/resources/scala-cask/modelData.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-cask/modelData.mustache
@@ -13,11 +13,40 @@ import upickle.default.*
{{#models}}
{{#model}}
+{{#vendorExtensions.x-has-one-of}}
+type {{{classname}}}Data = {{#oneOf}}{{{.}}}Data{{^-last}} | {{/-last}}{{/oneOf}}
+
+object {{{classname}}}Data {
+
+ def validated(d8a : {{{classname}}}Data, failFast: Boolean) : Try[{{{classname}}}] = {
+ d8a match {
+ {{#oneOf}}
+ case value : {{{.}}}Data => value.validated(failFast)
+ {{/oneOf}}
+ }
+ }
+
+ def fromJsonString(jason : String) = fromJson {
+ try {
+ read[ujson.Value](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason': $e")
+ }
+ }
+
+ def fromJson(jason : ujson.Value) : {{{classname}}}Data = {
+ val attempt = {{#oneOf}}{{^-first}}.orElse({{/-first}} Try({{{.}}}Data.fromJson(jason)) {{^-first}}) /* not first */{{/-first}} {{/oneOf}}
+ attempt.get
+ }
+}
+{{/vendorExtensions.x-has-one-of}}
+{{^vendorExtensions.x-has-one-of}}
{{#isEnum}}
{{>modelDataEnum}}
{{/isEnum}}
{{^isEnum}}
{{>modelDataClass}}
{{/isEnum}}
+{{/vendorExtensions.x-has-one-of}}
{{/model}}
{{/models}}
diff --git a/modules/openapi-generator/src/main/resources/scala-cask/modelDataClass.mustache b/modules/openapi-generator/src/main/resources/scala-cask/modelDataClass.mustache
index 72017e63563..a61b223fb1d 100644
--- a/modules/openapi-generator/src/main/resources/scala-cask/modelDataClass.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-cask/modelDataClass.mustache
@@ -26,73 +26,73 @@ case class {{classname}}Data(
}
def validationErrors(path : Seq[Field], failFast : Boolean) : Seq[ValidationError] = {
- val errors = scala.collection.mutable.ListBuffer[ValidationError]()
+ val _allValidationErrors = scala.collection.mutable.ListBuffer[ValidationError]()
{{#vars}}
// ================== {{name}} validation ==================
{{#pattern}}
// validate against pattern '{{{pattern}}}'
- if (errors.isEmpty || !failFast) {
+ if (_allValidationErrors.isEmpty || !failFast) {
val regex = """{{{pattern}}}"""
if {{name}} == null || !regex.r.matches({{name}}) then
- errors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"value '${{name}}' doesn't match pattern $regex")
+ _allValidationErrors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"value '${{name}}' doesn't match pattern $regex")
}
{{/pattern}}
{{#minimum}}
// validate against {{#exclusiveMinimum}}exclusive {{/exclusiveMinimum}}minimum {{minimum}}
- if (errors.isEmpty || !failFast) {
+ if (_allValidationErrors.isEmpty || !failFast) {
if !({{name}} >{{^exclusiveMinimum}}={{/exclusiveMinimum}} {{minimum}}) then
- errors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"value '${{name}}' is not greater than the {{#exclusiveMinimum}}exclusive {{/exclusiveMinimum}}minimum value {{minimum}}")
+ _allValidationErrors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"value '${{name}}' is not greater than the {{#exclusiveMinimum}}exclusive {{/exclusiveMinimum}}minimum value {{minimum}}")
}
{{/minimum}}
{{#maximum}}
// validate against {{#exclusiveMaximum}}exclusive {{/exclusiveMaximum}}maximum {{maximum}}
- if (errors.isEmpty || !failFast) {
+ if (_allValidationErrors.isEmpty || !failFast) {
if !({{name}} <{{^exclusiveMaximum}}={{/exclusiveMaximum}} {{maximum}}) then
- errors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"value '${{name}}' is not greater than the {{#exclusiveMaximum}}exclusive {{/exclusiveMaximum}}maximum value {{maximum}}")
+ _allValidationErrors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"value '${{name}}' is not greater than the {{#exclusiveMaximum}}exclusive {{/exclusiveMaximum}}maximum value {{maximum}}")
}
{{/maximum}}
{{#minLength}}
// validate min length {{minLength}}
- if (errors.isEmpty || !failFast) {
+ if (_allValidationErrors.isEmpty || !failFast) {
val len = if {{name}} == null then 0 else {{name}}.length
if (len < {{minLength}}) {
- errors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"length $len is shorter than the min length {{minLength}}")
+ _allValidationErrors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"length $len is shorter than the min length {{minLength}}")
}
}
{{/minLength}}
{{#maxLength}}
// validate max length {{maxLength}}
- if (errors.isEmpty || !failFast) {
+ if (_allValidationErrors.isEmpty || !failFast) {
val len = if {{name}} == null then 0 else {{name}}.length
if (len < {{maxLength}}) {
- errors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"length $len is longer than the max length {{maxLength}}")
+ _allValidationErrors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"length $len is longer than the max length {{maxLength}}")
}
}
{{/maxLength}}
{{#isEmail}}
// validate {{name}} is a valid email address
- if (errors.isEmpty || !failFast) {
+ if (_allValidationErrors.isEmpty || !failFast) {
val emailRegex = """^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"""
// validate {{name}} is email
if ({{name}} == null || !emailRegex.r.matches({{name}})) {
- errors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"${{name}} is not a valid email address according to the pattern $emailRegex")
+ _allValidationErrors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"${{name}} is not a valid email address according to the pattern $emailRegex")
}
}
{{/isEmail}}
{{#required}}{{^isPrimitiveType}}
- if (errors.isEmpty || !failFast) {
+ if (_allValidationErrors.isEmpty || !failFast) {
if ({{name}} == null) {
- errors += ValidationError(path :+ {{classname}}.Fields.{{name}}, "{{name}} is a required field and cannot be null")
+ _allValidationErrors += ValidationError(path :+ {{classname}}.Fields.{{name}}, "{{name}} is a required field and cannot be null")
}
}
{{/isPrimitiveType}}{{/required}}
{{#uniqueItems}}
// validate {{name}} has unique items
- if (errors.isEmpty || !failFast) {
+ if (_allValidationErrors.isEmpty || !failFast) {
if ({{name}} != null) {
{{name}}.foldLeft(Set[{{{vendorExtensions.x-containertype-data}}}]()) {
case (set, next) if set.contains(next) =>
- errors += ValidationError(
+ _allValidationErrors += ValidationError(
path :+ {{classname}}.Fields.{{name}},
s"duplicate value: $next"
)
@@ -103,10 +103,10 @@ case class {{classname}}Data(
}
{{/uniqueItems}}
{{#multipleOf}}
- if (errors.isEmpty || !failFast) {
+ if (_allValidationErrors.isEmpty || !failFast) {
// validate {{name}} multiple of {{multipleOf}}
if ({{name}} % {{multipleOf}} != 0) {
- errors += ValidationError(
+ _allValidationErrors += ValidationError(
path :+ {{classname}}.Fields.{{name}},
s"${{name}} is not a multiple of {{multipleOf}}"
)
@@ -115,30 +115,30 @@ case class {{classname}}Data(
{{/multipleOf}}
{{#minItems}}
// validate min items {{minItems}}
- if (errors.isEmpty || !failFast) {
+ if (_allValidationErrors.isEmpty || !failFast) {
val len = if {{name}} == null then 0 else {{name}}.size
if (len < {{minItems}}) {
- errors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"{{name}} has $len, which is less than the min items {{minItems}}")
+ _allValidationErrors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"{{name}} has $len, which is less than the min items {{minItems}}")
}
}
{{/minItems}}
{{#maxItems}}
// validate min items {{maxItems}}
- if (errors.isEmpty || !failFast) {
+ if (_allValidationErrors.isEmpty || !failFast) {
val len = if {{name}} == null then 0 else {{name}}.size
if (len > {{maxItems}}) {
- errors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"{{name}} has $len, which is greater than the max items {{maxItems}}")
+ _allValidationErrors += ValidationError(path :+ {{classname}}.Fields.{{name}}, s"{{name}} has $len, which is greater than the max items {{maxItems}}")
}
}
{{/maxItems}}
{{#minProperties}} TODO - minProperties {{/minProperties}}
{{#maxProperties}} TODO - maxProperties {{/maxProperties}}
{{#items}}{{#isModel}}
- if (errors.isEmpty || !failFast) {
+ if (_allValidationErrors.isEmpty || !failFast) {
if ({{name}} != null) {
{{name}}.zipWithIndex.foreach {
- case (value, i) if errors.isEmpty || !failFast =>
- errors ++= value.validationErrors(
+ case (value, i) if _allValidationErrors.isEmpty || !failFast =>
+ _allValidationErrors ++= value.validationErrors(
path :+ {{classname}}.Fields.{{name}} :+ Field(i.toString),
failFast)
case (value, i) =>
@@ -148,13 +148,13 @@ case class {{classname}}Data(
{{/isModel}}{{/items}}
{{#isModel}}
// validating {{name}}
- if (errors.isEmpty || !failFast) {
- if {{name}} != null then errors ++= {{name}}.validationErrors(path :+ {{classname}}.Fields.{{name}}, failFast)
+ if (_allValidationErrors.isEmpty || !failFast) {
+ if {{name}} != null then _allValidationErrors ++= {{name}}.validationErrors(path :+ {{classname}}.Fields.{{name}}, failFast)
}
{{/isModel}}
{{/vars}}
- errors.toSeq
+ _allValidationErrors.toSeq
}
/**
@@ -180,6 +180,8 @@ case class {{classname}}Data(
object {{classname}}Data {
+ def validated(d8a : {{classname}}Data, failFast : Boolean) : scala.util.Try[{{classname}}] = d8a.validated(failFast)
+
def fromJson(jason : ujson.Value) : {{classname}}Data = try {
val data = read[{{classname}}Data](jason)
{{^isAdditionalPropertiesTrue}}
diff --git a/modules/openapi-generator/src/main/resources/scala-cask/modelTest.mustache b/modules/openapi-generator/src/main/resources/scala-cask/modelTest.mustache
index 7b1d95b5aab..bed1a908d2e 100644
--- a/modules/openapi-generator/src/main/resources/scala-cask/modelTest.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-cask/modelTest.mustache
@@ -28,7 +28,8 @@ class {{classname}}Test extends AnyWordSpec with Matchers {
err.getMessage should startWith ("Error parsing json 'invalid jason'")
}
"""parse {{example}}""" ignore {
- val Failure(err : ValidationErrors) = {{classname}}Data.fromJsonString("""{{example}}""").validated()
+ val d8a = {{classname}}Data.fromJsonString("""{{example}}""")
+ val Failure(err : ValidationErrors) = {{classname}}Data.validated(d8a, true)
sys.error("TODO")
}
diff --git a/modules/openapi-generator/src/main/resources/scala-cask/parseHttpParams.mustache b/modules/openapi-generator/src/main/resources/scala-cask/parseHttpParams.mustache
index ebbd63e2c05..7957edeb5bb 100644
--- a/modules/openapi-generator/src/main/resources/scala-cask/parseHttpParams.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-cask/parseHttpParams.mustache
@@ -40,7 +40,10 @@
{{^isMap}}
{{paramName}}Json <- Parsed.fromTry(request.bodyAsJson)
{{paramName}}Data <- Parsed.eval({{vendorExtensions.x-container-type}}Data.fromJson({{paramName}}Json)) /* not array or map */
- {{paramName}} <- Parsed.fromTry({{paramName}}Data.validated(failFast))
+ {{paramName}}{{^required}}Opt{{/required}} <- Parsed.fromTry({{vendorExtensions.x-container-type}}Data.validated({{paramName}}Data, failFast))
+ {{^required}}
+ {{paramName}} = Option({{paramName}}Opt)
+ {{/required}}
{{/isMap}}
{{/isArray}}
{{/vendorExtensions.x-consumes-json}}
diff --git a/modules/openapi-generator/src/main/resources/scala-cask/project/build.properties b/modules/openapi-generator/src/main/resources/scala-cask/project/build.properties
index 04267b14af6..bc7390601f4 100644
--- a/modules/openapi-generator/src/main/resources/scala-cask/project/build.properties
+++ b/modules/openapi-generator/src/main/resources/scala-cask/project/build.properties
@@ -1 +1 @@
-sbt.version=1.9.9
+sbt.version=1.10.3
diff --git a/modules/openapi-generator/src/main/resources/scala-cask/project/plugins.sbt b/modules/openapi-generator/src/main/resources/scala-cask/project/plugins.sbt
index ece317dfad9..9c4d009e290 100644
--- a/modules/openapi-generator/src/main/resources/scala-cask/project/plugins.sbt
+++ b/modules/openapi-generator/src/main/resources/scala-cask/project/plugins.sbt
@@ -1,4 +1,4 @@
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0")
-addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0")
+addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.17.0")
addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.2.0")
\ No newline at end of file
diff --git a/modules/openapi-generator/src/test/resources/3_0/scala-cask/petstore.yaml b/modules/openapi-generator/src/test/resources/3_0/scala-cask/petstore.yaml
new file mode 100644
index 00000000000..2249f5342c8
--- /dev/null
+++ b/modules/openapi-generator/src/test/resources/3_0/scala-cask/petstore.yaml
@@ -0,0 +1,905 @@
+openapi: 3.0.0
+servers:
+ - url: 'http://petstore.swagger.io/v2'
+info:
+ description: >-
+ This is a sample server Petstore server. For this sample, you can use the api key
+ `special-key` to test the authorization filters.
+ version: 1.0.0
+ title: OpenAPI Petstore
+ license:
+ name: Apache-2.0
+ url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
+tags:
+ - name: pet
+ description: Everything about your Pets
+ - name: store
+ description: Access to Petstore orders
+ - name: user
+ description: Operations about user
+paths:
+ /complex-types:
+ post:
+ tags:
+ - complexRoute
+ operationId: oneOfRequestAndResponse
+ summary: Example route with 'oneOf' content and response
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ oneOf:
+ - $ref: '#/components/schemas/ComplexRequest'
+ - $ref: '#/components/schemas/AllOfRequest'
+ responses:
+ '200':
+ description: Success
+ content:
+ application/json:
+ schema:
+ oneOf:
+ - $ref: '#/components/schemas/SomeResponse1'
+ - $ref: '#/components/schemas/SomeResponse2'
+ /pet:
+ post:
+ tags:
+ - pet
+ summary: Add a new pet to the store
+ description: ''
+ operationId: addPet
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ '405':
+ description: Invalid input
+ security:
+ - petstore_auth:
+ - 'write:pets'
+ - 'read:pets'
+ requestBody:
+ $ref: '#/components/requestBodies/Pet'
+ put:
+ tags:
+ - pet
+ summary: Update an existing pet
+ description: ''
+ operationId: updatePet
+ externalDocs:
+ url: "http://petstore.swagger.io/v2/doc/updatePet"
+ description: "API documentation for the updatePet operation"
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ '400':
+ description: Invalid ID supplied
+ '404':
+ description: Pet not found
+ '405':
+ description: Validation exception
+ security:
+ - petstore_auth:
+ - 'write:pets'
+ - 'read:pets'
+ requestBody:
+ $ref: '#/components/requestBodies/Pet'
+ /pet/findByStatus:
+ get:
+ tags:
+ - pet
+ summary: Finds Pets by status
+ description: Multiple status values can be provided with comma separated strings
+ operationId: findPetsByStatus
+ parameters:
+ - name: status
+ in: query
+ description: Status values that need to be considered for filter
+ required: true
+ style: form
+ explode: false
+ deprecated: true
+ schema:
+ type: array
+ items:
+ type: string
+ enum:
+ - available
+ - pending
+ - sold
+ default: available
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ '400':
+ description: Invalid status value
+ security:
+ - petstore_auth:
+ - 'read:pets'
+ /pet/findByTags:
+ get:
+ tags:
+ - pet
+ summary: Finds Pets by tags
+ description: >-
+ Multiple tags can be provided with comma separated strings. Use tag1,
+ tag2, tag3 for testing.
+ operationId: findPetsByTags
+ parameters:
+ - name: tags
+ in: query
+ description: Tags to filter by
+ required: true
+ style: form
+ explode: false
+ schema:
+ type: array
+ items:
+ type: string
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ '400':
+ description: Invalid tag value
+ security:
+ - petstore_auth:
+ - 'read:pets'
+ deprecated: true
+ '/pet/{petId}':
+ get:
+ tags:
+ - pet
+ summary: Find pet by ID
+ description: Returns a single pet
+ operationId: getPetById
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to return
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ '400':
+ description: Invalid ID supplied
+ '404':
+ description: Pet not found
+ security:
+ - api_key: []
+ post:
+ tags:
+ - pet
+ summary: Updates a pet in the store with form data
+ description: ''
+ operationId: updatePetWithForm
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet that needs to be updated
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '405':
+ description: Invalid input
+ security:
+ - petstore_auth:
+ - 'write:pets'
+ - 'read:pets'
+ requestBody:
+ content:
+ application/x-www-form-urlencoded:
+ schema:
+ type: object
+ properties:
+ name:
+ description: Updated name of the pet
+ type: string
+ status:
+ description: Updated status of the pet
+ type: string
+ delete:
+ tags:
+ - pet
+ summary: Deletes a pet
+ description: ''
+ operationId: deletePet
+ parameters:
+ - name: api_key
+ in: header
+ required: false
+ schema:
+ type: string
+ - name: petId
+ in: path
+ description: Pet id to delete
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '400':
+ description: Invalid pet value
+ security:
+ - petstore_auth:
+ - 'write:pets'
+ - 'read:pets'
+ '/pet/{petId}/uploadImage':
+ post:
+ tags:
+ - pet
+ summary: uploads an image
+ description: ''
+ operationId: uploadFile
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to update
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ApiResponse'
+ security:
+ - petstore_auth:
+ - 'write:pets'
+ - 'read:pets'
+ requestBody:
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ properties:
+ additionalMetadata:
+ description: Additional data to pass to server
+ type: string
+ file:
+ description: file to upload
+ type: string
+ format: binary
+ /store/inventory:
+ get:
+ tags:
+ - store
+ summary: Returns pet inventories by status
+ description: Returns a map of status codes to quantities
+ operationId: getInventory
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties:
+ type: integer
+ format: int32
+ security:
+ - api_key: []
+ /store/order:
+ post:
+ tags:
+ - store
+ summary: Place an order for a pet
+ description: ''
+ operationId: placeOrder
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ '400':
+ description: Invalid Order
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ description: order placed for purchasing the pet
+ required: true
+ '/store/order/{orderId}':
+ get:
+ tags:
+ - store
+ summary: Find purchase order by ID
+ description: >-
+ For valid response try integer IDs with value <= 5 or > 10. Other values
+ will generate exceptions
+ operationId: getOrderById
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of pet that needs to be fetched
+ required: true
+ schema:
+ type: integer
+ format: int64
+ minimum: 1
+ maximum: 5
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ '400':
+ description: Invalid ID supplied
+ '404':
+ description: Order not found
+ delete:
+ tags:
+ - store
+ summary: Delete purchase order by ID
+ description: >-
+ For valid response try integer IDs with value < 1000. Anything above
+ 1000 or nonintegers will generate API errors
+ operationId: deleteOrder
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of the order that needs to be deleted
+ required: true
+ schema:
+ type: string
+ responses:
+ '400':
+ description: Invalid ID supplied
+ '404':
+ description: Order not found
+ /user:
+ post:
+ tags:
+ - user
+ summary: Create user
+ description: This can only be done by the logged in user.
+ operationId: createUser
+ responses:
+ default:
+ description: successful operation
+ security:
+ - api_key: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ description: Created user object
+ required: true
+ /user/createWithArray:
+ post:
+ tags:
+ - user
+ summary: Creates list of users with given input array
+ description: ''
+ operationId: createUsersWithArrayInput
+ responses:
+ default:
+ description: successful operation
+ security:
+ - api_key: []
+ requestBody:
+ $ref: '#/components/requestBodies/UserArray'
+ /user/createWithList:
+ post:
+ tags:
+ - user
+ summary: Creates list of users with given input array
+ description: ''
+ operationId: createUsersWithListInput
+ responses:
+ default:
+ description: successful operation
+ security:
+ - api_key: []
+ requestBody:
+ $ref: '#/components/requestBodies/UserArray'
+ /user/login:
+ get:
+ tags:
+ - user
+ summary: Logs user into the system
+ description: ''
+ operationId: loginUser
+ parameters:
+ - name: username
+ in: query
+ description: The user name for login
+ required: true
+ schema:
+ type: string
+ pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$'
+ - name: password
+ in: query
+ description: The password for login in clear text
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: successful operation
+ headers:
+ Set-Cookie:
+ description: >-
+ Cookie authentication key for use with the `api_key`
+ apiKey authentication.
+ schema:
+ type: string
+ example: AUTH_KEY=abcde12345; Path=/; HttpOnly
+ X-Rate-Limit:
+ description: calls per hour allowed by the user
+ schema:
+ type: integer
+ format: int32
+ X-Expires-After:
+ description: date in UTC when token expires
+ schema:
+ type: string
+ format: date-time
+ content:
+ application/xml:
+ schema:
+ type: string
+ application/json:
+ schema:
+ type: string
+ '400':
+ description: Invalid username/password supplied
+ /user/logout:
+ get:
+ tags:
+ - user
+ summary: Logs out current logged in user session
+ description: ''
+ operationId: logoutUser
+ responses:
+ default:
+ description: successful operation
+ security:
+ - api_key: []
+ '/user/{username}':
+ get:
+ tags:
+ - user
+ summary: Get user by user name
+ description: ''
+ operationId: getUserByName
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be fetched. Use user1 for testing.
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ '400':
+ description: Invalid username supplied
+ '404':
+ description: User not found
+ put:
+ tags:
+ - user
+ summary: Updated user
+ description: This can only be done by the logged in user.
+ operationId: updateUser
+ parameters:
+ - name: username
+ in: path
+ description: name that need to be deleted
+ required: true
+ schema:
+ type: string
+ responses:
+ '400':
+ description: Invalid user supplied
+ '404':
+ description: User not found
+ security:
+ - api_key: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ description: Updated user object
+ required: true
+ delete:
+ tags:
+ - user
+ summary: Delete user
+ description: This can only be done by the logged in user.
+ operationId: deleteUser
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be deleted
+ required: true
+ schema:
+ type: string
+ responses:
+ '400':
+ description: Invalid username supplied
+ '404':
+ description: User not found
+ security:
+ - api_key: []
+externalDocs:
+ description: Find out more about Swagger
+ url: 'http://swagger.io'
+components:
+ requestBodies:
+ UserArray:
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ description: List of user object
+ required: true
+ Pet:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ description: Pet object that needs to be added to the store
+ required: true
+ securitySchemes:
+ petstore_auth:
+ type: oauth2
+ flows:
+ implicit:
+ authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog'
+ scopes:
+ 'write:pets': modify pets in your account
+ 'read:pets': read your pets
+ api_key:
+ type: apiKey
+ name: api_key
+ in: header
+ schemas:
+ Order:
+ title: Pet Order
+ description: An order for a pets from the pet store
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ petId:
+ type: integer
+ format: int64
+ quantity:
+ type: integer
+ format: int32
+ shipDate:
+ type: string
+ format: date-time
+ status:
+ type: string
+ description: Order Status
+ enum:
+ - placed
+ - approved
+ - delivered
+ complete:
+ type: boolean
+ default: false
+ xml:
+ name: Order
+ Category:
+ title: Pet category
+ description: A category for a pet
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$'
+ xml:
+ name: Category
+ User:
+ title: a User
+ description: A User who is purchasing from the pet store
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ username:
+ type: string
+ firstName:
+ type: string
+ lastName:
+ type: string
+ email:
+ type: string
+ password:
+ type: string
+ phone:
+ type: string
+ userStatus:
+ type: integer
+ format: int32
+ description: User Status
+ xml:
+ name: User
+ Tag:
+ title: Pet Tag
+ description: A tag for a pet
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ xml:
+ name: Tag
+ Pet:
+ title: a Pet
+ description: A pet for sale in the pet store
+ type: object
+ required:
+ - name
+ - photoUrls
+ properties:
+ id:
+ type: integer
+ format: int64
+ category:
+ $ref: '#/components/schemas/Category'
+ name:
+ type: string
+ example: doggie
+ photoUrls:
+ type: array
+ xml:
+ name: photoUrl
+ wrapped: true
+ items:
+ type: string
+ tags:
+ type: array
+ xml:
+ name: tag
+ wrapped: true
+ items:
+ $ref: '#/components/schemas/Tag'
+ status:
+ type: string
+ description: pet status in the store
+ deprecated: true
+ enum:
+ - available
+ - pending
+ - sold
+ xml:
+ name: Pet
+ ApiResponse:
+ title: An uploaded response
+ description: Describes the result of uploading an image resource
+ type: object
+ properties:
+ code:
+ type: integer
+ format: int32
+ type:
+ type: string
+ message:
+ type: string
+ ComplexRequest:
+ type: object
+ required:
+ - type
+ - requiredField
+ properties:
+ type:
+ type: string
+ enum:
+ - someEnum
+ requiredField:
+ type: string
+ description: A required string field
+ stringField:
+ type: string
+ minLength: 5
+ maxLength: 100
+ description: String with length constraints
+ integerField:
+ type: integer
+ minimum: 1
+ maximum: 100
+ description: Integer with a range from 1 to 100
+ numberField:
+ type: number
+ exclusiveMinimum: 0.0
+ exclusiveMaximum: 100.0
+ description: Number with exclusive minimum and maximum constraints
+ booleanField:
+ type: boolean
+ description: A boolean field
+ emailField:
+ type: string
+ format: email
+ description: A valid email address
+ uuidField:
+ type: string
+ format: uuid
+ description: A valid UUID
+ dateField:
+ type: string
+ format: date
+ description: A date field (YYYY-MM-DD)
+ dateTimeField:
+ type: string
+ format: date-time
+ description: A date-time field (RFC 3339 format)
+ arrayField:
+ type: array
+ items:
+ type: string
+ minItems: 1
+ maxItems: 10
+ description: An array of strings with min and max items constraints
+ enumField:
+ type: string
+ enum:
+ - value1
+ - value2
+ - value3
+ description: A string field with enum validation
+ nestedObject:
+ type: object
+ properties:
+ nestedField1:
+ type: string
+ description: A field within a nested object
+ nestedField2:
+ type: integer
+ description: Another field in a nested object
+ arrayOfObjectsField:
+ type: array
+ items:
+ type: object
+ properties:
+ objectField1:
+ type: string
+ objectField2:
+ type: integer
+ description: An array of objects
+ patternField:
+ type: string
+ pattern: '^[a-zA-Z0-9]{3,10}$'
+ description: A string field with regex pattern validation
+ nullableField:
+ type: string
+ nullable: true
+ description: A string field that allows null values
+ additionalProperties:
+ type: object
+ description: Additional properties are allowed beyond the defined fields
+
+ AllOfRequest:
+ type: object
+ properties:
+ name:
+ type: string
+ age:
+ type: integer
+ details:
+ allOf:
+ - type: object
+ properties:
+ address:
+ type: string
+ - type: object
+ properties:
+ contact_number:
+ type: string
+ required:
+ - name
+ - age
+ SomeResponse1:
+ type: object
+ properties:
+ status:
+ type: string
+ message:
+ type: string
+ required:
+ - status
+ - message
+
+ SomeResponse2:
+ type: object
+ properties:
+ id:
+ type: string
+ created_at:
+ type: string
+ format: date-time
+ details:
+ type: object
+ properties:
+ description:
+ type: string
+ status:
+ type: string
+ required:
+ - id
+ - created_at
\ No newline at end of file
diff --git a/samples/server/petstore/scala-cask/.openapi-generator/FILES b/samples/server/petstore/scala-cask/.openapi-generator/FILES
index e3a6308f3d2..f3d799a105c 100644
--- a/samples/server/petstore/scala-cask/.openapi-generator/FILES
+++ b/samples/server/petstore/scala-cask/.openapi-generator/FILES
@@ -10,6 +10,8 @@ example/Server.scala
jvm/src/main/scala/sample/cask/AppRoutes.scala
jvm/src/main/scala/sample/cask/BaseApp.scala
jvm/src/main/scala/sample/cask/ExampleApp.scala
+jvm/src/main/scala/sample/cask/api/ComplexRouteRoutes.scala
+jvm/src/main/scala/sample/cask/api/ComplexRouteRoutes.scala
jvm/src/main/scala/sample/cask/api/OpenApiRoutes.scala
jvm/src/main/scala/sample/cask/api/PetRoutes.scala
jvm/src/main/scala/sample/cask/api/PetRoutes.scala
@@ -19,19 +21,50 @@ jvm/src/main/scala/sample/cask/api/UserRoutes.scala
jvm/src/main/scala/sample/cask/api/UserRoutes.scala
jvm/src/main/scala/sample/cask/api/package.scala
jvm/src/main/scala/sample/cask/package.scala
+jvm/src/test/scala/sample/cask/model/AllOfRequestDetailsTest.scala
+jvm/src/test/scala/sample/cask/model/AllOfRequestTest.scala
+jvm/src/test/scala/sample/cask/model/ComplexRequestArrayOfObjectsFieldInnerTest.scala
+jvm/src/test/scala/sample/cask/model/ComplexRequestNestedObjectTest.scala
+jvm/src/test/scala/sample/cask/model/ComplexRequestTest.scala
+jvm/src/test/scala/sample/cask/model/OneOfRequestAndResponse200ResponseTest.scala
+jvm/src/test/scala/sample/cask/model/OneOfRequestAndResponseRequestTest.scala
+jvm/src/test/scala/sample/cask/model/SomeResponse1Test.scala
+jvm/src/test/scala/sample/cask/model/SomeResponse2DetailsTest.scala
+jvm/src/test/scala/sample/cask/model/SomeResponse2Test.scala
project/build.properties
project/plugins.sbt
+shared/src/main/scala/sample/cask/api/ComplexRouteService.scala
shared/src/main/scala/sample/cask/api/PetService.scala
shared/src/main/scala/sample/cask/api/StoreService.scala
shared/src/main/scala/sample/cask/api/UserService.scala
+shared/src/main/scala/sample/cask/model/AllOfRequest.scala
+shared/src/main/scala/sample/cask/model/AllOfRequestData.scala
+shared/src/main/scala/sample/cask/model/AllOfRequestDetails.scala
+shared/src/main/scala/sample/cask/model/AllOfRequestDetailsData.scala
shared/src/main/scala/sample/cask/model/ApiResponse.scala
shared/src/main/scala/sample/cask/model/ApiResponseData.scala
shared/src/main/scala/sample/cask/model/Category.scala
shared/src/main/scala/sample/cask/model/CategoryData.scala
+shared/src/main/scala/sample/cask/model/ComplexRequest.scala
+shared/src/main/scala/sample/cask/model/ComplexRequestArrayOfObjectsFieldInner.scala
+shared/src/main/scala/sample/cask/model/ComplexRequestArrayOfObjectsFieldInnerData.scala
+shared/src/main/scala/sample/cask/model/ComplexRequestData.scala
+shared/src/main/scala/sample/cask/model/ComplexRequestNestedObject.scala
+shared/src/main/scala/sample/cask/model/ComplexRequestNestedObjectData.scala
+shared/src/main/scala/sample/cask/model/OneOfRequestAndResponse200Response.scala
+shared/src/main/scala/sample/cask/model/OneOfRequestAndResponse200ResponseData.scala
+shared/src/main/scala/sample/cask/model/OneOfRequestAndResponseRequest.scala
+shared/src/main/scala/sample/cask/model/OneOfRequestAndResponseRequestData.scala
shared/src/main/scala/sample/cask/model/Order.scala
shared/src/main/scala/sample/cask/model/OrderData.scala
shared/src/main/scala/sample/cask/model/Pet.scala
shared/src/main/scala/sample/cask/model/PetData.scala
+shared/src/main/scala/sample/cask/model/SomeResponse1.scala
+shared/src/main/scala/sample/cask/model/SomeResponse1Data.scala
+shared/src/main/scala/sample/cask/model/SomeResponse2.scala
+shared/src/main/scala/sample/cask/model/SomeResponse2Data.scala
+shared/src/main/scala/sample/cask/model/SomeResponse2Details.scala
+shared/src/main/scala/sample/cask/model/SomeResponse2DetailsData.scala
shared/src/main/scala/sample/cask/model/Tag.scala
shared/src/main/scala/sample/cask/model/TagData.scala
shared/src/main/scala/sample/cask/model/User.scala
diff --git a/samples/server/petstore/scala-cask/example/Server.scala b/samples/server/petstore/scala-cask/example/Server.scala
index cd6650b83a4..99ba19e0d46 100644
--- a/samples/server/petstore/scala-cask/example/Server.scala
+++ b/samples/server/petstore/scala-cask/example/Server.scala
@@ -47,6 +47,7 @@ import sample.cask.model.*
import java.io.File
// TODO - write your business logic for your services here (the defaults all return 'not implemented'):
+val myComplexRouteService : ComplexRouteService = ComplexRouteService() // <-- replace this with your implementation
val myPetService : PetService = PetService() // <-- replace this with your implementation
val myStoreService : StoreService = StoreService() // <-- replace this with your implementation
val myUserService : UserService = UserService() // <-- replace this with your implementation
@@ -54,7 +55,8 @@ val myUserService : UserService = UserService() // <-- replace this with your im
/** This is your main entry point for your REST service
* It extends BaseApp which defines the business logic for your services
*/
-object Server extends BaseApp(appPetService = myPetService,
+object Server extends BaseApp(appComplexRouteService = myComplexRouteService,
+appPetService = myPetService,
appStoreService = myStoreService,
appUserService = myUserService):
start()
diff --git a/samples/server/petstore/scala-cask/jvm/src/main/resources/openapi.json b/samples/server/petstore/scala-cask/jvm/src/main/resources/openapi.json
index 5c3f8dec9aa..6ef6a493170 100644
--- a/samples/server/petstore/scala-cask/jvm/src/main/resources/openapi.json
+++ b/samples/server/petstore/scala-cask/jvm/src/main/resources/openapi.json
@@ -27,6 +27,35 @@
"name" : "user"
} ],
"paths" : {
+ "/complex-types" : {
+ "post" : {
+ "operationId" : "oneOfRequestAndResponse",
+ "requestBody" : {
+ "content" : {
+ "application/json" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/oneOfRequestAndResponse_request"
+ }
+ }
+ },
+ "required" : true
+ },
+ "responses" : {
+ "200" : {
+ "content" : {
+ "application/json" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/oneOfRequestAndResponse_200_response"
+ }
+ }
+ },
+ "description" : "Success"
+ }
+ },
+ "summary" : "Example route with 'oneOf' content and response",
+ "tags" : [ "complexRoute" ]
+ }
+ },
"/pet" : {
"post" : {
"description" : "",
@@ -981,6 +1010,154 @@
"title" : "An uploaded response",
"type" : "object"
},
+ "ComplexRequest" : {
+ "additionalProperties" : {
+ "description" : "Additional properties are allowed beyond the defined fields",
+ "type" : "object"
+ },
+ "properties" : {
+ "type" : {
+ "enum" : [ "someEnum" ],
+ "type" : "string"
+ },
+ "requiredField" : {
+ "description" : "A required string field",
+ "type" : "string"
+ },
+ "stringField" : {
+ "description" : "String with length constraints",
+ "maxLength" : 100,
+ "minLength" : 5,
+ "type" : "string"
+ },
+ "integerField" : {
+ "description" : "Integer with a range from 1 to 100",
+ "maximum" : 100,
+ "minimum" : 1,
+ "type" : "integer"
+ },
+ "numberField" : {
+ "description" : "Number with exclusive minimum and maximum constraints",
+ "type" : "number"
+ },
+ "booleanField" : {
+ "description" : "A boolean field",
+ "type" : "boolean"
+ },
+ "emailField" : {
+ "description" : "A valid email address",
+ "format" : "email",
+ "type" : "string"
+ },
+ "uuidField" : {
+ "description" : "A valid UUID",
+ "format" : "uuid",
+ "type" : "string"
+ },
+ "dateField" : {
+ "description" : "A date field (YYYY-MM-DD)",
+ "format" : "date",
+ "type" : "string"
+ },
+ "dateTimeField" : {
+ "description" : "A date-time field (RFC 3339 format)",
+ "format" : "date-time",
+ "type" : "string"
+ },
+ "arrayField" : {
+ "description" : "An array of strings with min and max items constraints",
+ "items" : {
+ "type" : "string"
+ },
+ "maxItems" : 10,
+ "minItems" : 1,
+ "type" : "array"
+ },
+ "enumField" : {
+ "description" : "A string field with enum validation",
+ "enum" : [ "value1", "value2", "value3" ],
+ "type" : "string"
+ },
+ "nestedObject" : {
+ "$ref" : "#/components/schemas/ComplexRequest_nestedObject"
+ },
+ "arrayOfObjectsField" : {
+ "items" : {
+ "$ref" : "#/components/schemas/ComplexRequest_arrayOfObjectsField_inner"
+ },
+ "type" : "array"
+ },
+ "patternField" : {
+ "description" : "A string field with regex pattern validation",
+ "pattern" : "^[a-zA-Z0-9]{3,10}$",
+ "type" : "string"
+ },
+ "nullableField" : {
+ "description" : "A string field that allows null values",
+ "nullable" : true,
+ "type" : "string"
+ }
+ },
+ "required" : [ "requiredField", "type" ],
+ "type" : "object"
+ },
+ "AllOfRequest" : {
+ "properties" : {
+ "name" : {
+ "type" : "string"
+ },
+ "age" : {
+ "type" : "integer"
+ },
+ "details" : {
+ "$ref" : "#/components/schemas/AllOfRequest_details"
+ }
+ },
+ "required" : [ "age", "name" ],
+ "type" : "object"
+ },
+ "SomeResponse1" : {
+ "properties" : {
+ "status" : {
+ "type" : "string"
+ },
+ "message" : {
+ "type" : "string"
+ }
+ },
+ "required" : [ "message", "status" ],
+ "type" : "object"
+ },
+ "SomeResponse2" : {
+ "properties" : {
+ "id" : {
+ "type" : "string"
+ },
+ "created_at" : {
+ "format" : "date-time",
+ "type" : "string"
+ },
+ "details" : {
+ "$ref" : "#/components/schemas/SomeResponse2_details"
+ }
+ },
+ "required" : [ "created_at", "id" ],
+ "type" : "object"
+ },
+ "oneOfRequestAndResponse_request" : {
+ "oneOf" : [ {
+ "$ref" : "#/components/schemas/ComplexRequest"
+ }, {
+ "$ref" : "#/components/schemas/AllOfRequest"
+ } ]
+ },
+ "oneOfRequestAndResponse_200_response" : {
+ "oneOf" : [ {
+ "$ref" : "#/components/schemas/SomeResponse1"
+ }, {
+ "$ref" : "#/components/schemas/SomeResponse2"
+ } ]
+ },
"updatePetWithForm_request" : {
"properties" : {
"name" : {
@@ -1007,6 +1184,59 @@
}
},
"type" : "object"
+ },
+ "ComplexRequest_nestedObject" : {
+ "properties" : {
+ "nestedField1" : {
+ "description" : "A field within a nested object",
+ "type" : "string"
+ },
+ "nestedField2" : {
+ "description" : "Another field in a nested object",
+ "type" : "integer"
+ }
+ },
+ "type" : "object"
+ },
+ "ComplexRequest_arrayOfObjectsField_inner" : {
+ "description" : "An array of objects",
+ "properties" : {
+ "objectField1" : {
+ "type" : "string"
+ },
+ "objectField2" : {
+ "type" : "integer"
+ }
+ },
+ "type" : "object"
+ },
+ "AllOfRequest_details" : {
+ "allOf" : [ {
+ "properties" : {
+ "address" : {
+ "type" : "string"
+ }
+ },
+ "type" : "object"
+ }, {
+ "properties" : {
+ "contact_number" : {
+ "type" : "string"
+ }
+ },
+ "type" : "object"
+ } ]
+ },
+ "SomeResponse2_details" : {
+ "properties" : {
+ "description" : {
+ "type" : "string"
+ },
+ "status" : {
+ "type" : "string"
+ }
+ },
+ "type" : "object"
}
},
"securitySchemes" : {
diff --git a/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/AppRoutes.scala b/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/AppRoutes.scala
index f519b3ca30f..07a0586bd3c 100644
--- a/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/AppRoutes.scala
+++ b/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/AppRoutes.scala
@@ -37,6 +37,9 @@ import _root_.sample.cask.api.*
* More typically, however, you would extend the 'BaseApp' class
*/
trait AppRoutes {
+ def appComplexRouteService : ComplexRouteService[Try] = ComplexRouteService()
+ def routeForComplexRoute : ComplexRouteRoutes = ComplexRouteRoutes(appComplexRouteService)
+
def appPetService : PetService[Try] = PetService()
def routeForPet : PetRoutes = PetRoutes(appPetService)
@@ -48,6 +51,7 @@ trait AppRoutes {
def appRoutes = Seq(
+ routeForComplexRoute ,
routeForPet ,
routeForStore ,
routeForUser
diff --git a/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/BaseApp.scala b/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/BaseApp.scala
index 7ed98e88bc9..e4aa3992979 100644
--- a/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/BaseApp.scala
+++ b/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/BaseApp.scala
@@ -27,6 +27,8 @@ import _root_.sample.cask.api.*
* passing in the custom business logic services
*/
class BaseApp(
+ override val appComplexRouteService : ComplexRouteService[Try] = ComplexRouteService(),
+
override val appPetService : PetService[Try] = PetService(),
override val appStoreService : StoreService[Try] = StoreService(),
diff --git a/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/api/ComplexRouteRoutes.scala b/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/api/ComplexRouteRoutes.scala
new file mode 100644
index 00000000000..cb77f67ee8b
--- /dev/null
+++ b/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/api/ComplexRouteRoutes.scala
@@ -0,0 +1,59 @@
+//> using scala "3.3.1"
+//> using lib "com.lihaoyi::cask:0.8.3"
+//> using lib "com.lihaoyi::scalatags:0.12.0"
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+
+// this is generated from apiRoutes.mustache
+package sample.cask.api
+
+import sample.cask.model.*
+
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+import scala.util.Try
+
+import sample.cask.model.OneOfRequestAndResponse200Response
+import sample.cask.model.OneOfRequestAndResponseRequest
+
+class ComplexRouteRoutes(service : ComplexRouteService[Try]) extends cask.Routes {
+
+
+ /** Example route with 'oneOf' content and response
+ *
+ */
+ @cask.post("/complex-types")
+ def oneOfRequestAndResponse(request: cask.Request) = {
+
+ def failFast = request.queryParams.keySet.contains("failFast")
+
+ val result = for {
+ oneOfRequestAndResponseRequestJson <- Parsed.fromTry(request.bodyAsJson)
+ oneOfRequestAndResponseRequestData <- Parsed.eval(OneOfRequestAndResponseRequestData.fromJson(oneOfRequestAndResponseRequestJson)) /* not array or map */
+ oneOfRequestAndResponseRequest <- Parsed.fromTry(OneOfRequestAndResponseRequestData.validated(oneOfRequestAndResponseRequestData, failFast))
+ resultTry <- Parsed.eval(service.oneOfRequestAndResponse(oneOfRequestAndResponseRequest))
+ result <- Parsed.fromTry(resultTry)
+ } yield result
+
+ import OneOfRequestAndResponse200Response.{given, *} // this brings in upickle in the case of union (oneOf) types
+
+ (result : @unchecked) match {
+ case Left(error) => cask.Response(error, 500)
+ case Right(value : OneOfRequestAndResponse200Response) => cask.Response(data = write(value), 200, headers = Seq("Content-Type" -> "application/json"))
+ case Right(other) => cask.Response(s"$other", 200)
+ }
+ }
+
+ initialize()
+}
diff --git a/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/api/PetRoutes.scala b/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/api/PetRoutes.scala
index da02bbb338d..972b15d30e9 100644
--- a/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/api/PetRoutes.scala
+++ b/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/api/PetRoutes.scala
@@ -63,11 +63,13 @@ class PetRoutes(service : PetService[Try]) extends cask.Routes {
val result = for {
petJson <- Parsed.fromTry(request.bodyAsJson)
petData <- Parsed.eval(PetData.fromJson(petJson)) /* not array or map */
- pet <- Parsed.fromTry(petData.validated(failFast))
+ pet <- Parsed.fromTry(PetData.validated(petData, failFast))
resultTry <- Parsed.eval(service.addPet(pet))
result <- Parsed.fromTry(resultTry)
} yield result
+ import Pet.{given, *} // this brings in upickle in the case of union (oneOf) types
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(value : Pet) => cask.Response(data = write(value), 200, headers = Seq("Content-Type" -> "application/json"))
@@ -90,6 +92,7 @@ class PetRoutes(service : PetService[Try]) extends cask.Routes {
result <- Parsed.fromTry(resultTry)
} yield result
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(other) => cask.Response(s"$other", 200)
@@ -109,6 +112,7 @@ class PetRoutes(service : PetService[Try]) extends cask.Routes {
result <- Parsed.fromTry(resultTry)
} yield result
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(value : List[Pet]) => cask.Response(data = write(value), 200, headers = Seq("Content-Type" -> "application/json"))
@@ -129,6 +133,7 @@ class PetRoutes(service : PetService[Try]) extends cask.Routes {
result <- Parsed.fromTry(resultTry)
} yield result
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(value : List[Pet]) => cask.Response(data = write(value), 200, headers = Seq("Content-Type" -> "application/json"))
@@ -150,6 +155,8 @@ class PetRoutes(service : PetService[Try]) extends cask.Routes {
result <- Parsed.fromTry(resultTry)
} yield result
+ import Pet.{given, *} // this brings in upickle in the case of union (oneOf) types
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(value : Pet) => cask.Response(data = write(value), 200, headers = Seq("Content-Type" -> "application/json"))
@@ -168,11 +175,13 @@ class PetRoutes(service : PetService[Try]) extends cask.Routes {
val result = for {
petJson <- Parsed.fromTry(request.bodyAsJson)
petData <- Parsed.eval(PetData.fromJson(petJson)) /* not array or map */
- pet <- Parsed.fromTry(petData.validated(failFast))
+ pet <- Parsed.fromTry(PetData.validated(petData, failFast))
resultTry <- Parsed.eval(service.updatePet(pet))
result <- Parsed.fromTry(resultTry)
} yield result
+ import Pet.{given, *} // this brings in upickle in the case of union (oneOf) types
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(value : Pet) => cask.Response(data = write(value), 200, headers = Seq("Content-Type" -> "application/json"))
@@ -196,6 +205,7 @@ class PetRoutes(service : PetService[Try]) extends cask.Routes {
result <- Parsed.fromTry(resultTry)
} yield result
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(other) => cask.Response(s"$other", 200)
@@ -218,6 +228,8 @@ class PetRoutes(service : PetService[Try]) extends cask.Routes {
result <- Parsed.fromTry(resultTry)
} yield result
+ import ApiResponse.{given, *} // this brings in upickle in the case of union (oneOf) types
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(value : ApiResponse) => cask.Response(data = write(value), 200, headers = Seq("Content-Type" -> "application/json"))
diff --git a/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/api/StoreRoutes.scala b/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/api/StoreRoutes.scala
index 5c3414564e5..5cea1d14b35 100644
--- a/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/api/StoreRoutes.scala
+++ b/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/api/StoreRoutes.scala
@@ -43,6 +43,7 @@ class StoreRoutes(service : StoreService[Try]) extends cask.Routes {
result <- Parsed.fromTry(resultTry)
} yield result
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(other) => cask.Response(s"$other", 200)
@@ -62,6 +63,7 @@ class StoreRoutes(service : StoreService[Try]) extends cask.Routes {
result <- Parsed.fromTry(resultTry)
} yield result
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(value : Map[String, Int]) => cask.Response(data = write(value), 200, headers = Seq("Content-Type" -> "application/json"))
@@ -82,6 +84,8 @@ class StoreRoutes(service : StoreService[Try]) extends cask.Routes {
result <- Parsed.fromTry(resultTry)
} yield result
+ import Order.{given, *} // this brings in upickle in the case of union (oneOf) types
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(value : Order) => cask.Response(data = write(value), 200, headers = Seq("Content-Type" -> "application/json"))
@@ -99,11 +103,13 @@ class StoreRoutes(service : StoreService[Try]) extends cask.Routes {
val result = for {
orderJson <- Parsed.fromTry(request.bodyAsJson)
orderData <- Parsed.eval(OrderData.fromJson(orderJson)) /* not array or map */
- order <- Parsed.fromTry(orderData.validated(failFast))
+ order <- Parsed.fromTry(OrderData.validated(orderData, failFast))
resultTry <- Parsed.eval(service.placeOrder(order))
result <- Parsed.fromTry(resultTry)
} yield result
+ import Order.{given, *} // this brings in upickle in the case of union (oneOf) types
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(value : Order) => cask.Response(data = write(value), 200, headers = Seq("Content-Type" -> "application/json"))
diff --git a/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/api/UserRoutes.scala b/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/api/UserRoutes.scala
index 63c01ea5583..5cb1b56288c 100644
--- a/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/api/UserRoutes.scala
+++ b/samples/server/petstore/scala-cask/jvm/src/main/scala/sample/cask/api/UserRoutes.scala
@@ -52,11 +52,12 @@ class UserRoutes(service : UserService[Try]) extends cask.Routes {
val result = for {
userJson <- Parsed.fromTry(request.bodyAsJson)
userData <- Parsed.eval(UserData.fromJson(userJson)) /* not array or map */
- user <- Parsed.fromTry(userData.validated(failFast))
+ user <- Parsed.fromTry(UserData.validated(userData, failFast))
resultTry <- Parsed.eval(service.createUser(user))
result <- Parsed.fromTry(resultTry)
} yield result
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(other) => cask.Response(s"$other", 200)
@@ -77,6 +78,7 @@ class UserRoutes(service : UserService[Try]) extends cask.Routes {
result <- Parsed.fromTry(resultTry)
} yield result
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(other) => cask.Response(s"$other", 200)
@@ -97,6 +99,7 @@ class UserRoutes(service : UserService[Try]) extends cask.Routes {
result <- Parsed.fromTry(resultTry)
} yield result
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(other) => cask.Response(s"$other", 200)
@@ -117,6 +120,7 @@ class UserRoutes(service : UserService[Try]) extends cask.Routes {
result <- Parsed.fromTry(resultTry)
} yield result
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(other) => cask.Response(s"$other", 200)
@@ -136,6 +140,8 @@ class UserRoutes(service : UserService[Try]) extends cask.Routes {
result <- Parsed.fromTry(resultTry)
} yield result
+ import User.{given, *} // this brings in upickle in the case of union (oneOf) types
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(value : User) => cask.Response(data = write(value), 200, headers = Seq("Content-Type" -> "application/json"))
@@ -155,6 +161,7 @@ class UserRoutes(service : UserService[Try]) extends cask.Routes {
result <- Parsed.fromTry(resultTry)
} yield result
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(value : String) => cask.Response(data = write(value), 200, headers = Seq("Content-Type" -> "application/json"))
@@ -175,6 +182,7 @@ class UserRoutes(service : UserService[Try]) extends cask.Routes {
result <- Parsed.fromTry(resultTry)
} yield result
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(other) => cask.Response(s"$other", 200)
@@ -193,11 +201,12 @@ class UserRoutes(service : UserService[Try]) extends cask.Routes {
username <- Parsed(username)
userJson <- Parsed.fromTry(request.bodyAsJson)
userData <- Parsed.eval(UserData.fromJson(userJson)) /* not array or map */
- user <- Parsed.fromTry(userData.validated(failFast))
+ user <- Parsed.fromTry(UserData.validated(userData, failFast))
resultTry <- Parsed.eval(service.updateUser(username, user))
result <- Parsed.fromTry(resultTry)
} yield result
+
(result : @unchecked) match {
case Left(error) => cask.Response(error, 500)
case Right(other) => cask.Response(s"$other", 200)
diff --git a/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/AllOfRequestDetailsTest.scala b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/AllOfRequestDetailsTest.scala
new file mode 100644
index 00000000000..fd04c762efc
--- /dev/null
+++ b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/AllOfRequestDetailsTest.scala
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelTest.mustache
+package sample.cask.model
+
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
+import scala.util.*
+
+class AllOfRequestDetailsTest extends AnyWordSpec with Matchers {
+
+
+ "AllOfRequestDetails.fromJson" should {
+ """not parse invalid json""" in {
+ val Failure(err) = Try(AllOfRequestDetailsData.fromJsonString("invalid jason"))
+ err.getMessage should startWith ("Error parsing json 'invalid jason'")
+ }
+ """parse """ ignore {
+ val d8a = AllOfRequestDetailsData.fromJsonString("""""")
+ val Failure(err : ValidationErrors) = AllOfRequestDetailsData.validated(d8a, true)
+
+ sys.error("TODO")
+ }
+ }
+}
diff --git a/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/AllOfRequestTest.scala b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/AllOfRequestTest.scala
new file mode 100644
index 00000000000..13a8aba1a17
--- /dev/null
+++ b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/AllOfRequestTest.scala
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelTest.mustache
+package sample.cask.model
+
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
+import scala.util.*
+
+class AllOfRequestTest extends AnyWordSpec with Matchers {
+
+
+ "AllOfRequest.fromJson" should {
+ """not parse invalid json""" in {
+ val Failure(err) = Try(AllOfRequestData.fromJsonString("invalid jason"))
+ err.getMessage should startWith ("Error parsing json 'invalid jason'")
+ }
+ """parse """ ignore {
+ val d8a = AllOfRequestData.fromJsonString("""""")
+ val Failure(err : ValidationErrors) = AllOfRequestData.validated(d8a, true)
+
+ sys.error("TODO")
+ }
+ }
+}
diff --git a/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/ComplexRequestArrayOfObjectsFieldInnerTest.scala b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/ComplexRequestArrayOfObjectsFieldInnerTest.scala
new file mode 100644
index 00000000000..3ab544d8567
--- /dev/null
+++ b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/ComplexRequestArrayOfObjectsFieldInnerTest.scala
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelTest.mustache
+package sample.cask.model
+
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
+import scala.util.*
+
+class ComplexRequestArrayOfObjectsFieldInnerTest extends AnyWordSpec with Matchers {
+
+
+ "ComplexRequestArrayOfObjectsFieldInner.fromJson" should {
+ """not parse invalid json""" in {
+ val Failure(err) = Try(ComplexRequestArrayOfObjectsFieldInnerData.fromJsonString("invalid jason"))
+ err.getMessage should startWith ("Error parsing json 'invalid jason'")
+ }
+ """parse """ ignore {
+ val d8a = ComplexRequestArrayOfObjectsFieldInnerData.fromJsonString("""""")
+ val Failure(err : ValidationErrors) = ComplexRequestArrayOfObjectsFieldInnerData.validated(d8a, true)
+
+ sys.error("TODO")
+ }
+ }
+}
diff --git a/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/ComplexRequestNestedObjectTest.scala b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/ComplexRequestNestedObjectTest.scala
new file mode 100644
index 00000000000..ac1f00ffc51
--- /dev/null
+++ b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/ComplexRequestNestedObjectTest.scala
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelTest.mustache
+package sample.cask.model
+
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
+import scala.util.*
+
+class ComplexRequestNestedObjectTest extends AnyWordSpec with Matchers {
+
+
+ "ComplexRequestNestedObject.fromJson" should {
+ """not parse invalid json""" in {
+ val Failure(err) = Try(ComplexRequestNestedObjectData.fromJsonString("invalid jason"))
+ err.getMessage should startWith ("Error parsing json 'invalid jason'")
+ }
+ """parse """ ignore {
+ val d8a = ComplexRequestNestedObjectData.fromJsonString("""""")
+ val Failure(err : ValidationErrors) = ComplexRequestNestedObjectData.validated(d8a, true)
+
+ sys.error("TODO")
+ }
+ }
+}
diff --git a/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/ComplexRequestTest.scala b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/ComplexRequestTest.scala
new file mode 100644
index 00000000000..c353c9dac58
--- /dev/null
+++ b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/ComplexRequestTest.scala
@@ -0,0 +1,41 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelTest.mustache
+package sample.cask.model
+import java.time.LocalDate
+import java.time.OffsetDateTime
+import java.util.UUID
+import scala.math.BigDecimal
+import ujson.Value
+
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
+import scala.util.*
+
+class ComplexRequestTest extends AnyWordSpec with Matchers {
+
+
+ "ComplexRequest.fromJson" should {
+ """not parse invalid json""" in {
+ val Failure(err) = Try(ComplexRequestData.fromJsonString("invalid jason"))
+ err.getMessage should startWith ("Error parsing json 'invalid jason'")
+ }
+ """parse """ ignore {
+ val d8a = ComplexRequestData.fromJsonString("""""")
+ val Failure(err : ValidationErrors) = ComplexRequestData.validated(d8a, true)
+
+ sys.error("TODO")
+ }
+ }
+}
diff --git a/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/OneOfRequestAndResponse200ResponseTest.scala b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/OneOfRequestAndResponse200ResponseTest.scala
new file mode 100644
index 00000000000..4fd4e0eace2
--- /dev/null
+++ b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/OneOfRequestAndResponse200ResponseTest.scala
@@ -0,0 +1,37 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelTest.mustache
+package sample.cask.model
+import java.time.OffsetDateTime
+
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
+import scala.util.*
+
+class OneOfRequestAndResponse200ResponseTest extends AnyWordSpec with Matchers {
+
+
+ "OneOfRequestAndResponse200Response.fromJson" should {
+ """not parse invalid json""" in {
+ val Failure(err) = Try(OneOfRequestAndResponse200ResponseData.fromJsonString("invalid jason"))
+ err.getMessage should startWith ("Error parsing json 'invalid jason'")
+ }
+ """parse """ ignore {
+ val d8a = OneOfRequestAndResponse200ResponseData.fromJsonString("""""")
+ val Failure(err : ValidationErrors) = OneOfRequestAndResponse200ResponseData.validated(d8a, true)
+
+ sys.error("TODO")
+ }
+ }
+}
diff --git a/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/OneOfRequestAndResponseRequestTest.scala b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/OneOfRequestAndResponseRequestTest.scala
new file mode 100644
index 00000000000..33d5aa9b87c
--- /dev/null
+++ b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/OneOfRequestAndResponseRequestTest.scala
@@ -0,0 +1,40 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelTest.mustache
+package sample.cask.model
+import java.time.LocalDate
+import java.time.OffsetDateTime
+import java.util.UUID
+import scala.math.BigDecimal
+
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
+import scala.util.*
+
+class OneOfRequestAndResponseRequestTest extends AnyWordSpec with Matchers {
+
+
+ "OneOfRequestAndResponseRequest.fromJson" should {
+ """not parse invalid json""" in {
+ val Failure(err) = Try(OneOfRequestAndResponseRequestData.fromJsonString("invalid jason"))
+ err.getMessage should startWith ("Error parsing json 'invalid jason'")
+ }
+ """parse """ ignore {
+ val d8a = OneOfRequestAndResponseRequestData.fromJsonString("""""")
+ val Failure(err : ValidationErrors) = OneOfRequestAndResponseRequestData.validated(d8a, true)
+
+ sys.error("TODO")
+ }
+ }
+}
diff --git a/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/SomeResponse1Test.scala b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/SomeResponse1Test.scala
new file mode 100644
index 00000000000..63c26cff6b6
--- /dev/null
+++ b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/SomeResponse1Test.scala
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelTest.mustache
+package sample.cask.model
+
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
+import scala.util.*
+
+class SomeResponse1Test extends AnyWordSpec with Matchers {
+
+
+ "SomeResponse1.fromJson" should {
+ """not parse invalid json""" in {
+ val Failure(err) = Try(SomeResponse1Data.fromJsonString("invalid jason"))
+ err.getMessage should startWith ("Error parsing json 'invalid jason'")
+ }
+ """parse """ ignore {
+ val d8a = SomeResponse1Data.fromJsonString("""""")
+ val Failure(err : ValidationErrors) = SomeResponse1Data.validated(d8a, true)
+
+ sys.error("TODO")
+ }
+ }
+}
diff --git a/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/SomeResponse2DetailsTest.scala b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/SomeResponse2DetailsTest.scala
new file mode 100644
index 00000000000..8a71e91dbf5
--- /dev/null
+++ b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/SomeResponse2DetailsTest.scala
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelTest.mustache
+package sample.cask.model
+
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
+import scala.util.*
+
+class SomeResponse2DetailsTest extends AnyWordSpec with Matchers {
+
+
+ "SomeResponse2Details.fromJson" should {
+ """not parse invalid json""" in {
+ val Failure(err) = Try(SomeResponse2DetailsData.fromJsonString("invalid jason"))
+ err.getMessage should startWith ("Error parsing json 'invalid jason'")
+ }
+ """parse """ ignore {
+ val d8a = SomeResponse2DetailsData.fromJsonString("""""")
+ val Failure(err : ValidationErrors) = SomeResponse2DetailsData.validated(d8a, true)
+
+ sys.error("TODO")
+ }
+ }
+}
diff --git a/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/SomeResponse2Test.scala b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/SomeResponse2Test.scala
new file mode 100644
index 00000000000..c63dddd0c76
--- /dev/null
+++ b/samples/server/petstore/scala-cask/jvm/src/test/scala/sample/cask/model/SomeResponse2Test.scala
@@ -0,0 +1,37 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelTest.mustache
+package sample.cask.model
+import java.time.OffsetDateTime
+
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
+import scala.util.*
+
+class SomeResponse2Test extends AnyWordSpec with Matchers {
+
+
+ "SomeResponse2.fromJson" should {
+ """not parse invalid json""" in {
+ val Failure(err) = Try(SomeResponse2Data.fromJsonString("invalid jason"))
+ err.getMessage should startWith ("Error parsing json 'invalid jason'")
+ }
+ """parse """ ignore {
+ val d8a = SomeResponse2Data.fromJsonString("""""")
+ val Failure(err : ValidationErrors) = SomeResponse2Data.validated(d8a, true)
+
+ sys.error("TODO")
+ }
+ }
+}
diff --git a/samples/server/petstore/scala-cask/project/build.properties b/samples/server/petstore/scala-cask/project/build.properties
index 04267b14af6..bc7390601f4 100644
--- a/samples/server/petstore/scala-cask/project/build.properties
+++ b/samples/server/petstore/scala-cask/project/build.properties
@@ -1 +1 @@
-sbt.version=1.9.9
+sbt.version=1.10.3
diff --git a/samples/server/petstore/scala-cask/project/plugins.sbt b/samples/server/petstore/scala-cask/project/plugins.sbt
index ece317dfad9..9c4d009e290 100644
--- a/samples/server/petstore/scala-cask/project/plugins.sbt
+++ b/samples/server/petstore/scala-cask/project/plugins.sbt
@@ -1,4 +1,4 @@
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0")
-addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0")
+addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.17.0")
addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.2.0")
\ No newline at end of file
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/api/ComplexRouteService.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/api/ComplexRouteService.scala
new file mode 100644
index 00000000000..08b99029f59
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/api/ComplexRouteService.scala
@@ -0,0 +1,118 @@
+//> using scala "3.3.1"
+//> using lib "com.lihaoyi::cask:0.8.3"
+//> using lib "com.lihaoyi::scalatags:0.12.0"
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+
+// generated from apiService.mustache
+package sample.cask.api
+
+import _root_.sample.cask.model.OneOfRequestAndResponse200Response
+import _root_.sample.cask.model.OneOfRequestAndResponseRequest
+import scala.util.Failure
+import scala.util.Try
+import _root_.sample.cask.model.*
+
+/**
+ * The ComplexRouteService companion object.
+ *
+ * Use the ComplexRouteService() companion object to create an instance which returns a 'not implemented' error
+ * for each operation.
+ *
+ */
+object ComplexRouteService {
+
+ /**
+ * The 'Handler' is an implementation of ComplexRouteService convenient for delegating or overriding individual functions
+ */
+ case class Handler[F[_]](
+ oneOfRequestAndResponseHandler : (oneOfRequestAndResponseRequest : OneOfRequestAndResponseRequest) => F[OneOfRequestAndResponse200Response]
+ ) extends ComplexRouteService[F] {
+
+ override def oneOfRequestAndResponse(oneOfRequestAndResponseRequest : OneOfRequestAndResponseRequest) : F[OneOfRequestAndResponse200Response] = {
+ oneOfRequestAndResponseHandler(oneOfRequestAndResponseRequest)
+ }
+ }
+
+ def apply() : ComplexRouteService[Try] = ComplexRouteService.Handler[Try](
+ (_) => notImplemented("oneOfRequestAndResponse")
+ )
+
+ private def notImplemented(name : String) = Failure(new Exception(s"TODO: $name not implemented"))
+}
+
+/**
+ * The ComplexRoute business-logic
+ *
+ *
+ * The 'asHandler' will return an implementation which allows for easily overriding individual operations.
+ *
+ * equally there are "on<Function>" helper methods for easily overriding individual functions
+ *
+ * @tparam F the effect type (Future, Try, IO, ID, etc) of the operations
+ */
+trait ComplexRouteService[F[_]] {
+ /** Example route with 'oneOf' content and response
+ *
+ * @return OneOfRequestAndResponse200Response
+ */
+ def oneOfRequestAndResponse(oneOfRequestAndResponseRequest : OneOfRequestAndResponseRequest) : F[OneOfRequestAndResponse200Response]
+
+ /**
+ * override oneOfRequestAndResponse with the given handler
+ * @return a new implementation of ComplexRouteService[F] with oneOfRequestAndResponse overridden using the given handler
+ */
+ final def onOneOfRequestAndResponse(handler : (oneOfRequestAndResponseRequest : OneOfRequestAndResponseRequest) => F[OneOfRequestAndResponse200Response]) : ComplexRouteService[F] = {
+ asHandler.copy(oneOfRequestAndResponseHandler = handler)
+ }
+
+ /**
+ * @return a Handler implementation of this service
+ */
+ final def asHandler : ComplexRouteService.Handler[F] = this match {
+ case h : ComplexRouteService.Handler[F] => h
+ case _ =>
+ ComplexRouteService.Handler[F](
+ (oneOfRequestAndResponseRequest) => oneOfRequestAndResponse(oneOfRequestAndResponseRequest)
+ )
+ }
+
+ /**
+ * This function will change the effect type of this service.
+ *
+ * It's not unlike a typical map operation from A => B, except we're not mapping
+ * a type from A to B, but rather from F[A] => G[A] using the 'changeEffect' function.
+ *
+ * For, this could turn an asynchronous service (one which returns Future[_] types) into
+ * a synchronous one (one which returns Try[_] types) by awaiting on the Future.
+ *
+ * It could change an IO type (like cats effect or ZIO) into an ID[A] which is just:
+ * ```
+ * type ID[A] => A
+ * ```
+ *
+ * @tparam G the new "polymorphic" effect type
+ * @param changeEffect the "natural transformation" which can change one effect type into another
+ * @return a new ComplexRouteService service implementation with effect type [G]
+ */
+ final def mapEffect[G[_]](changeEffect : [A] => F[A] => G[A]) : ComplexRouteService[G] = {
+ val self = this
+
+ new ComplexRouteService[G] {
+ override def oneOfRequestAndResponse(oneOfRequestAndResponseRequest : OneOfRequestAndResponseRequest) : G[OneOfRequestAndResponse200Response] = changeEffect {
+ self.oneOfRequestAndResponse(oneOfRequestAndResponseRequest)
+ }
+ }
+ }
+}
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/AllOfRequest.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/AllOfRequest.scala
new file mode 100644
index 00000000000..df67709ee24
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/AllOfRequest.scala
@@ -0,0 +1,58 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using model.mustache
+package sample.cask.model
+
+import scala.util.control.NonFatal
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+
+case class AllOfRequest(
+ name: String,
+ age: Int,
+ details: Option[AllOfRequestDetails] = None
+
+
+) {
+
+def asJsonString: String = asData.asJsonString
+def asJson: ujson.Value = asData.asJson
+
+def asData : AllOfRequestData = {
+AllOfRequestData(
+ name = name /* 2 */,
+ age = age /* 2 */,
+ details = details.map(_.asData).getOrElse(null) /* 4 */
+
+)
+}
+}
+
+object AllOfRequest {
+given RW[AllOfRequest] = summon[RW[ujson.Value]].bimap[AllOfRequest](_.asJson, json => read[AllOfRequestData](json).asModel)
+
+enum Fields(val fieldName : String) extends Field(fieldName) {
+ case name extends Fields("name")
+ case age extends Fields("age")
+ case details extends Fields("details")
+}
+
+
+}
+
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/AllOfRequestData.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/AllOfRequestData.scala
new file mode 100644
index 00000000000..7f43eb9792c
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/AllOfRequestData.scala
@@ -0,0 +1,149 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelData.mustache
+package sample.cask.model
+import scala.util.control.NonFatal
+import scala.util.*
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+ /** AllOfRequestData a data transfer object, primarily for simple json serialisation.
+ * It has no validation - there may be nulls, values out of range, etc
+ */
+case class AllOfRequestData(
+ name: String,
+ age: Int,
+ details: AllOfRequestDetailsData = null
+
+
+) derives RW {
+
+ def asJsonString: String = asJson.toString()
+
+ def asJson : ujson.Value = {
+ val jason = writeJs(this)
+ jason
+ }
+
+ def validationErrors(path : Seq[Field], failFast : Boolean) : Seq[ValidationError] = {
+ val _allValidationErrors = scala.collection.mutable.ListBuffer[ValidationError]()
+ // ================== name validation ==================
+
+
+
+
+
+ // ================== age validation ==================
+
+
+
+
+
+ // ================== details validation ==================
+
+
+
+
+ // validating details
+ if (_allValidationErrors.isEmpty || !failFast) {
+ if details != null then _allValidationErrors ++= details.validationErrors(path :+ AllOfRequest.Fields.details, failFast)
+ }
+
+ _allValidationErrors.toSeq
+ }
+
+ /**
+ * @return the validated model within a Try (if successful)
+ */
+ def validated(failFast : Boolean = false) : scala.util.Try[AllOfRequest] = {
+ validationErrors(Vector(), failFast) match {
+ case Seq() => Success(asModel)
+ case first +: theRest => Failure(ValidationErrors(first, theRest))
+ }
+ }
+
+ /** use 'validated' to check validation */
+ def asModel : AllOfRequest = {
+ AllOfRequest(
+ name = name /* 2 */,
+ age = age /* 2 */,
+ details = Option(details).map(_.asModel) /* 4 */
+
+ )
+ }
+}
+
+object AllOfRequestData {
+
+ def validated(d8a : AllOfRequestData, failFast : Boolean) : scala.util.Try[AllOfRequest] = d8a.validated(failFast)
+
+ def fromJson(jason : ujson.Value) : AllOfRequestData = try {
+ val data = read[AllOfRequestData](jason)
+ data
+ } catch {
+ case NonFatal(e) => sys.error(s"Error creating AllOfRequestData from json '$jason': $e")
+ }
+
+ def fromJsonString(jason : String) : AllOfRequestData = {
+ val parsed = try {
+ read[ujson.Value](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason': $e")
+ }
+ fromJson(parsed)
+ }
+
+ def manyFromJsonString(jason : String) : Seq[AllOfRequestData] = try {
+ read[List[AllOfRequestData]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as list: $e")
+ }
+
+ def manyFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Seq[AllOfRequest]] = {
+ Try(manyFromJsonString(jason)).flatMap { list =>
+ list.zipWithIndex.foldLeft(Try(Vector[AllOfRequest]())) {
+ case (Success(list), (next, i)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(list :+ ok)
+ case Failure(err) => Failure(new Exception(s"Validation error on element $i: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+
+ def mapFromJsonString(jason : String) : Map[String, AllOfRequestData] = try {
+ read[Map[String, AllOfRequestData]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as map: $e")
+ }
+
+
+ def mapFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Map[String, AllOfRequest]] = {
+ Try(mapFromJsonString(jason)).flatMap { map =>
+ map.foldLeft(Try(Map[String, AllOfRequest]())) {
+ case (Success(map), (key, next)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(map.updated(key, ok))
+ case Failure(err) => Failure(new Exception(s"Validation error on element $key: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+}
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/AllOfRequestDetails.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/AllOfRequestDetails.scala
new file mode 100644
index 00000000000..28d1774320f
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/AllOfRequestDetails.scala
@@ -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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using model.mustache
+package sample.cask.model
+
+import scala.util.control.NonFatal
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+
+case class AllOfRequestDetails(
+ address: Option[String] = None ,
+ contactNumber: Option[String] = None
+
+
+) {
+
+def asJsonString: String = asData.asJsonString
+def asJson: ujson.Value = asData.asJson
+
+def asData : AllOfRequestDetailsData = {
+AllOfRequestDetailsData(
+ address = address.getOrElse("") /* 1 */,
+ contactNumber = contactNumber.getOrElse("") /* 1 */
+
+)
+}
+}
+
+object AllOfRequestDetails {
+given RW[AllOfRequestDetails] = summon[RW[ujson.Value]].bimap[AllOfRequestDetails](_.asJson, json => read[AllOfRequestDetailsData](json).asModel)
+
+enum Fields(val fieldName : String) extends Field(fieldName) {
+ case address extends Fields("address")
+ case contactNumber extends Fields("contactNumber")
+}
+
+
+}
+
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/AllOfRequestDetailsData.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/AllOfRequestDetailsData.scala
new file mode 100644
index 00000000000..c8a5775e673
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/AllOfRequestDetailsData.scala
@@ -0,0 +1,137 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelData.mustache
+package sample.cask.model
+import scala.util.control.NonFatal
+import scala.util.*
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+ /** AllOfRequestDetailsData a data transfer object, primarily for simple json serialisation.
+ * It has no validation - there may be nulls, values out of range, etc
+ */
+case class AllOfRequestDetailsData(
+ address: String = "" ,
+ contactNumber: String = ""
+
+
+) derives RW {
+
+ def asJsonString: String = asJson.toString()
+
+ def asJson : ujson.Value = {
+ val jason = writeJs(this)
+ jason
+ }
+
+ def validationErrors(path : Seq[Field], failFast : Boolean) : Seq[ValidationError] = {
+ val _allValidationErrors = scala.collection.mutable.ListBuffer[ValidationError]()
+ // ================== address validation ==================
+
+
+
+
+
+ // ================== contactNumber validation ==================
+
+
+
+
+
+ _allValidationErrors.toSeq
+ }
+
+ /**
+ * @return the validated model within a Try (if successful)
+ */
+ def validated(failFast : Boolean = false) : scala.util.Try[AllOfRequestDetails] = {
+ validationErrors(Vector(), failFast) match {
+ case Seq() => Success(asModel)
+ case first +: theRest => Failure(ValidationErrors(first, theRest))
+ }
+ }
+
+ /** use 'validated' to check validation */
+ def asModel : AllOfRequestDetails = {
+ AllOfRequestDetails(
+ address = Option(address) /* 1 */,
+ contactNumber = Option(contactNumber) /* 1 */
+
+ )
+ }
+}
+
+object AllOfRequestDetailsData {
+
+ def validated(d8a : AllOfRequestDetailsData, failFast : Boolean) : scala.util.Try[AllOfRequestDetails] = d8a.validated(failFast)
+
+ def fromJson(jason : ujson.Value) : AllOfRequestDetailsData = try {
+ val data = read[AllOfRequestDetailsData](jason)
+ data
+ } catch {
+ case NonFatal(e) => sys.error(s"Error creating AllOfRequestDetailsData from json '$jason': $e")
+ }
+
+ def fromJsonString(jason : String) : AllOfRequestDetailsData = {
+ val parsed = try {
+ read[ujson.Value](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason': $e")
+ }
+ fromJson(parsed)
+ }
+
+ def manyFromJsonString(jason : String) : Seq[AllOfRequestDetailsData] = try {
+ read[List[AllOfRequestDetailsData]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as list: $e")
+ }
+
+ def manyFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Seq[AllOfRequestDetails]] = {
+ Try(manyFromJsonString(jason)).flatMap { list =>
+ list.zipWithIndex.foldLeft(Try(Vector[AllOfRequestDetails]())) {
+ case (Success(list), (next, i)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(list :+ ok)
+ case Failure(err) => Failure(new Exception(s"Validation error on element $i: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+
+ def mapFromJsonString(jason : String) : Map[String, AllOfRequestDetailsData] = try {
+ read[Map[String, AllOfRequestDetailsData]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as map: $e")
+ }
+
+
+ def mapFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Map[String, AllOfRequestDetails]] = {
+ Try(mapFromJsonString(jason)).flatMap { map =>
+ map.foldLeft(Try(Map[String, AllOfRequestDetails]())) {
+ case (Success(map), (key, next)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(map.updated(key, ok))
+ case Failure(err) => Failure(new Exception(s"Validation error on element $key: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+}
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ApiResponse.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ApiResponse.scala
index cafa7711645..0307a91039d 100644
--- a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ApiResponse.scala
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ApiResponse.scala
@@ -21,7 +21,7 @@ import upickle.default.{ReadWriter => RW, macroRW}
import upickle.default.*
-
+
case class ApiResponse(
code: Option[Int] = None ,
`type`: Option[String] = None ,
@@ -55,3 +55,4 @@ enum Fields(val fieldName : String) extends Field(fieldName) {
}
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ApiResponseData.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ApiResponseData.scala
index 4c80e1c743f..df95d64e141 100644
--- a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ApiResponseData.scala
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ApiResponseData.scala
@@ -40,7 +40,7 @@ case class ApiResponseData(
}
def validationErrors(path : Seq[Field], failFast : Boolean) : Seq[ValidationError] = {
- val errors = scala.collection.mutable.ListBuffer[ValidationError]()
+ val _allValidationErrors = scala.collection.mutable.ListBuffer[ValidationError]()
// ================== code validation ==================
@@ -59,7 +59,7 @@ case class ApiResponseData(
- errors.toSeq
+ _allValidationErrors.toSeq
}
/**
@@ -85,6 +85,8 @@ case class ApiResponseData(
object ApiResponseData {
+ def validated(d8a : ApiResponseData, failFast : Boolean) : scala.util.Try[ApiResponse] = d8a.validated(failFast)
+
def fromJson(jason : ujson.Value) : ApiResponseData = try {
val data = read[ApiResponseData](jason)
data
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Category.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Category.scala
index e89cbd7e81e..34eb6b98be4 100644
--- a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Category.scala
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Category.scala
@@ -21,7 +21,7 @@ import upickle.default.{ReadWriter => RW, macroRW}
import upickle.default.*
-
+
case class Category(
id: Option[Long] = None ,
name: Option[String] = None
@@ -52,3 +52,4 @@ enum Fields(val fieldName : String) extends Field(fieldName) {
}
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/CategoryData.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/CategoryData.scala
index 7eb8a948970..ab187bf5f66 100644
--- a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/CategoryData.scala
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/CategoryData.scala
@@ -39,7 +39,7 @@ case class CategoryData(
}
def validationErrors(path : Seq[Field], failFast : Boolean) : Seq[ValidationError] = {
- val errors = scala.collection.mutable.ListBuffer[ValidationError]()
+ val _allValidationErrors = scala.collection.mutable.ListBuffer[ValidationError]()
// ================== id validation ==================
@@ -48,17 +48,17 @@ case class CategoryData(
// ================== name validation ==================
// validate against pattern '^[a-zA-Z0-9]+[a-zA-Z0-9\\.\\-_]*[a-zA-Z0-9]+$'
- if (errors.isEmpty || !failFast) {
+ if (_allValidationErrors.isEmpty || !failFast) {
val regex = """^[a-zA-Z0-9]+[a-zA-Z0-9\\.\\-_]*[a-zA-Z0-9]+$"""
if name == null || !regex.r.matches(name) then
- errors += ValidationError(path :+ Category.Fields.name, s"value '$name' doesn't match pattern $regex")
+ _allValidationErrors += ValidationError(path :+ Category.Fields.name, s"value '$name' doesn't match pattern $regex")
}
- errors.toSeq
+ _allValidationErrors.toSeq
}
/**
@@ -83,6 +83,8 @@ case class CategoryData(
object CategoryData {
+ def validated(d8a : CategoryData, failFast : Boolean) : scala.util.Try[Category] = d8a.validated(failFast)
+
def fromJson(jason : ujson.Value) : CategoryData = try {
val data = read[CategoryData](jason)
data
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequest.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequest.scala
new file mode 100644
index 00000000000..1aa43f6ac93
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequest.scala
@@ -0,0 +1,127 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using model.mustache
+package sample.cask.model
+import java.time.LocalDate
+import java.time.OffsetDateTime
+import java.util.UUID
+import scala.math.BigDecimal
+import ujson.Value
+
+import scala.util.control.NonFatal
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+
+case class ComplexRequest(
+ `type`: ComplexRequest.TypeEnum,
+ /* A required string field */
+ requiredField: String,
+ /* String with length constraints */
+ stringField: Option[String] = None ,
+ /* Integer with a range from 1 to 100 */
+ integerField: Option[Int] = None ,
+ /* Number with exclusive minimum and maximum constraints */
+ numberField: Option[BigDecimal] = None ,
+ /* A boolean field */
+ booleanField: Option[Boolean] = None ,
+ /* A valid email address */
+ emailField: Option[String] = None ,
+ /* A valid UUID */
+ uuidField: Option[UUID] = None ,
+ /* A date field (YYYY-MM-DD) */
+ dateField: Option[LocalDate] = None ,
+ /* A date-time field (RFC 3339 format) */
+ dateTimeField: Option[OffsetDateTime] = None ,
+ /* An array of strings with min and max items constraints */
+ arrayField: Seq[String] = Nil ,
+ /* A string field with enum validation */
+ enumField: Option[ComplexRequest.EnumFieldEnum] = None ,
+ nestedObject: Option[ComplexRequestNestedObject] = None ,
+ arrayOfObjectsField: Seq[ComplexRequestArrayOfObjectsFieldInner] = Nil ,
+ /* A string field with regex pattern validation */
+ patternField: Option[String] = None ,
+ /* A string field that allows null values */
+ nullableField: Option[String] = None
+
+, additionalProperties : ujson.Value = ujson.Null
+) {
+
+def asJsonString: String = asData.asJsonString
+def asJson: ujson.Value = asData.asJson
+
+def asData : ComplexRequestData = {
+ComplexRequestData(
+ `type` = `type` /* 2 */,
+ requiredField = requiredField /* 2 */,
+ stringField = stringField.getOrElse("") /* 1 */,
+ integerField = integerField.getOrElse(0) /* 1 */,
+ numberField = numberField.getOrElse(0) /* 1 */,
+ booleanField = booleanField.getOrElse(false) /* 1 */,
+ emailField = emailField.getOrElse("") /* 1 */,
+ uuidField = uuidField.getOrElse(java.util.UUID.randomUUID()) /* 1 */,
+ dateField = dateField.getOrElse(null) /* 1 */,
+ dateTimeField = dateTimeField.getOrElse(null) /* 1 */,
+ arrayField = arrayField /* 2 */,
+ enumField = enumField.getOrElse(null) /* 1 */,
+ nestedObject = nestedObject.map(_.asData).getOrElse(null) /* 4 */,
+ arrayOfObjectsField = arrayOfObjectsField.map(_.asData) /* 6 */,
+ patternField = patternField.getOrElse("") /* 1 */,
+ nullableField = nullableField.getOrElse("") /* 1 */
+, additionalProperties
+)
+}
+}
+
+object ComplexRequest {
+given RW[ComplexRequest] = summon[RW[ujson.Value]].bimap[ComplexRequest](_.asJson, json => read[ComplexRequestData](json).asModel)
+
+enum Fields(val fieldName : String) extends Field(fieldName) {
+ case `type` extends Fields("`type`")
+ case requiredField extends Fields("requiredField")
+ case stringField extends Fields("stringField")
+ case integerField extends Fields("integerField")
+ case numberField extends Fields("numberField")
+ case booleanField extends Fields("booleanField")
+ case emailField extends Fields("emailField")
+ case uuidField extends Fields("uuidField")
+ case dateField extends Fields("dateField")
+ case dateTimeField extends Fields("dateTimeField")
+ case arrayField extends Fields("arrayField")
+ case enumField extends Fields("enumField")
+ case nestedObject extends Fields("nestedObject")
+ case arrayOfObjectsField extends Fields("arrayOfObjectsField")
+ case patternField extends Fields("patternField")
+ case nullableField extends Fields("nullableField")
+}
+
+ // baseName=type
+ // nameInCamelCase = `type`
+ enum TypeEnum derives ReadWriter {
+ case someEnum
+ }
+ // baseName=enumField
+ // nameInCamelCase = enumField
+ enum EnumFieldEnum derives ReadWriter {
+ case value1
+ case value2
+ case value3
+ }
+
+}
+
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequestArrayOfObjectsFieldInner.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequestArrayOfObjectsFieldInner.scala
new file mode 100644
index 00000000000..c7e221cc2db
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequestArrayOfObjectsFieldInner.scala
@@ -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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using model.mustache
+package sample.cask.model
+
+import scala.util.control.NonFatal
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+
+case class ComplexRequestArrayOfObjectsFieldInner(
+ objectField1: Option[String] = None ,
+ objectField2: Option[Int] = None
+
+
+) {
+
+def asJsonString: String = asData.asJsonString
+def asJson: ujson.Value = asData.asJson
+
+def asData : ComplexRequestArrayOfObjectsFieldInnerData = {
+ComplexRequestArrayOfObjectsFieldInnerData(
+ objectField1 = objectField1.getOrElse("") /* 1 */,
+ objectField2 = objectField2.getOrElse(0) /* 1 */
+
+)
+}
+}
+
+object ComplexRequestArrayOfObjectsFieldInner {
+given RW[ComplexRequestArrayOfObjectsFieldInner] = summon[RW[ujson.Value]].bimap[ComplexRequestArrayOfObjectsFieldInner](_.asJson, json => read[ComplexRequestArrayOfObjectsFieldInnerData](json).asModel)
+
+enum Fields(val fieldName : String) extends Field(fieldName) {
+ case objectField1 extends Fields("objectField1")
+ case objectField2 extends Fields("objectField2")
+}
+
+
+}
+
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequestArrayOfObjectsFieldInnerData.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequestArrayOfObjectsFieldInnerData.scala
new file mode 100644
index 00000000000..07f08a9d5e9
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequestArrayOfObjectsFieldInnerData.scala
@@ -0,0 +1,137 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelData.mustache
+package sample.cask.model
+import scala.util.control.NonFatal
+import scala.util.*
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+ /** ComplexRequestArrayOfObjectsFieldInnerData a data transfer object, primarily for simple json serialisation.
+ * It has no validation - there may be nulls, values out of range, etc
+ */
+case class ComplexRequestArrayOfObjectsFieldInnerData(
+ objectField1: String = "" ,
+ objectField2: Int = 0
+
+
+) derives RW {
+
+ def asJsonString: String = asJson.toString()
+
+ def asJson : ujson.Value = {
+ val jason = writeJs(this)
+ jason
+ }
+
+ def validationErrors(path : Seq[Field], failFast : Boolean) : Seq[ValidationError] = {
+ val _allValidationErrors = scala.collection.mutable.ListBuffer[ValidationError]()
+ // ================== objectField1 validation ==================
+
+
+
+
+
+ // ================== objectField2 validation ==================
+
+
+
+
+
+ _allValidationErrors.toSeq
+ }
+
+ /**
+ * @return the validated model within a Try (if successful)
+ */
+ def validated(failFast : Boolean = false) : scala.util.Try[ComplexRequestArrayOfObjectsFieldInner] = {
+ validationErrors(Vector(), failFast) match {
+ case Seq() => Success(asModel)
+ case first +: theRest => Failure(ValidationErrors(first, theRest))
+ }
+ }
+
+ /** use 'validated' to check validation */
+ def asModel : ComplexRequestArrayOfObjectsFieldInner = {
+ ComplexRequestArrayOfObjectsFieldInner(
+ objectField1 = Option(objectField1) /* 1 */,
+ objectField2 = Option(objectField2) /* 1 */
+
+ )
+ }
+}
+
+object ComplexRequestArrayOfObjectsFieldInnerData {
+
+ def validated(d8a : ComplexRequestArrayOfObjectsFieldInnerData, failFast : Boolean) : scala.util.Try[ComplexRequestArrayOfObjectsFieldInner] = d8a.validated(failFast)
+
+ def fromJson(jason : ujson.Value) : ComplexRequestArrayOfObjectsFieldInnerData = try {
+ val data = read[ComplexRequestArrayOfObjectsFieldInnerData](jason)
+ data
+ } catch {
+ case NonFatal(e) => sys.error(s"Error creating ComplexRequestArrayOfObjectsFieldInnerData from json '$jason': $e")
+ }
+
+ def fromJsonString(jason : String) : ComplexRequestArrayOfObjectsFieldInnerData = {
+ val parsed = try {
+ read[ujson.Value](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason': $e")
+ }
+ fromJson(parsed)
+ }
+
+ def manyFromJsonString(jason : String) : Seq[ComplexRequestArrayOfObjectsFieldInnerData] = try {
+ read[List[ComplexRequestArrayOfObjectsFieldInnerData]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as list: $e")
+ }
+
+ def manyFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Seq[ComplexRequestArrayOfObjectsFieldInner]] = {
+ Try(manyFromJsonString(jason)).flatMap { list =>
+ list.zipWithIndex.foldLeft(Try(Vector[ComplexRequestArrayOfObjectsFieldInner]())) {
+ case (Success(list), (next, i)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(list :+ ok)
+ case Failure(err) => Failure(new Exception(s"Validation error on element $i: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+
+ def mapFromJsonString(jason : String) : Map[String, ComplexRequestArrayOfObjectsFieldInnerData] = try {
+ read[Map[String, ComplexRequestArrayOfObjectsFieldInnerData]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as map: $e")
+ }
+
+
+ def mapFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Map[String, ComplexRequestArrayOfObjectsFieldInner]] = {
+ Try(mapFromJsonString(jason)).flatMap { map =>
+ map.foldLeft(Try(Map[String, ComplexRequestArrayOfObjectsFieldInner]())) {
+ case (Success(map), (key, next)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(map.updated(key, ok))
+ case Failure(err) => Failure(new Exception(s"Validation error on element $key: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+}
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequestData.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequestData.scala
new file mode 100644
index 00000000000..eb5b7f407e2
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequestData.scala
@@ -0,0 +1,338 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelData.mustache
+package sample.cask.model
+import java.time.LocalDate
+import java.time.OffsetDateTime
+import java.util.UUID
+import scala.math.BigDecimal
+import ujson.Value
+import scala.util.control.NonFatal
+import scala.util.*
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+ /** ComplexRequestData a data transfer object, primarily for simple json serialisation.
+ * It has no validation - there may be nulls, values out of range, etc
+ */
+case class ComplexRequestData(
+ `type`: ComplexRequest.TypeEnum,
+/* A required string field */
+ requiredField: String,
+/* String with length constraints */
+ stringField: String = "" ,
+/* Integer with a range from 1 to 100 */
+ integerField: Int = 0 ,
+/* Number with exclusive minimum and maximum constraints */
+ numberField: BigDecimal = 0 ,
+/* A boolean field */
+ booleanField: Boolean = false ,
+/* A valid email address */
+ emailField: String = "" ,
+/* A valid UUID */
+ uuidField: UUID = java.util.UUID.randomUUID() ,
+/* A date field (YYYY-MM-DD) */
+ dateField: LocalDate = null ,
+/* A date-time field (RFC 3339 format) */
+ dateTimeField: OffsetDateTime = null ,
+/* An array of strings with min and max items constraints */
+ arrayField: Seq[String] = Nil ,
+/* A string field with enum validation */
+ enumField: ComplexRequest.EnumFieldEnum = null ,
+ nestedObject: ComplexRequestNestedObjectData = null ,
+ arrayOfObjectsField: Seq[ComplexRequestArrayOfObjectsFieldInnerData] = Nil ,
+/* A string field with regex pattern validation */
+ patternField: String = "" ,
+/* A string field that allows null values */
+ nullableField: String = ""
+ , additionalProperties : ujson.Value = ujson.Null
+
+) derives RW {
+
+ def asJsonString: String = asJson.toString()
+
+ def asJson : ujson.Value = {
+ val jason = writeJs(this)
+ jason.obj.remove("additionalProperties")
+ jason.mergeWith(additionalProperties)
+ }
+
+ def validationErrors(path : Seq[Field], failFast : Boolean) : Seq[ValidationError] = {
+ val _allValidationErrors = scala.collection.mutable.ListBuffer[ValidationError]()
+ // ================== `type` validation ==================
+
+
+
+
+
+ // ================== requiredField validation ==================
+
+
+
+
+
+ // ================== stringField validation ==================
+ // validate min length 5
+ if (_allValidationErrors.isEmpty || !failFast) {
+ val len = if stringField == null then 0 else stringField.length
+ if (len < 5) {
+ _allValidationErrors += ValidationError(path :+ ComplexRequest.Fields.stringField, s"length $len is shorter than the min length 5")
+ }
+ }
+ // validate max length 100
+ if (_allValidationErrors.isEmpty || !failFast) {
+ val len = if stringField == null then 0 else stringField.length
+ if (len < 100) {
+ _allValidationErrors += ValidationError(path :+ ComplexRequest.Fields.stringField, s"length $len is longer than the max length 100")
+ }
+ }
+
+
+
+
+
+ // ================== integerField validation ==================
+ // validate against minimum 1
+ if (_allValidationErrors.isEmpty || !failFast) {
+ if !(integerField >= 1) then
+ _allValidationErrors += ValidationError(path :+ ComplexRequest.Fields.integerField, s"value '$integerField' is not greater than the minimum value 1")
+ }
+ // validate against maximum 100
+ if (_allValidationErrors.isEmpty || !failFast) {
+ if !(integerField <= 100) then
+ _allValidationErrors += ValidationError(path :+ ComplexRequest.Fields.integerField, s"value '$integerField' is not greater than the maximum value 100")
+ }
+
+
+
+
+
+ // ================== numberField validation ==================
+
+
+
+
+
+ // ================== booleanField validation ==================
+
+
+
+
+
+ // ================== emailField validation ==================
+ // validate emailField is a valid email address
+ if (_allValidationErrors.isEmpty || !failFast) {
+ val emailRegex = """^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"""
+ // validate emailField is email
+ if (emailField == null || !emailRegex.r.matches(emailField)) {
+ _allValidationErrors += ValidationError(path :+ ComplexRequest.Fields.emailField, s"$emailField is not a valid email address according to the pattern $emailRegex")
+ }
+ }
+
+
+
+
+
+ // ================== uuidField validation ==================
+
+
+
+
+
+ // ================== dateField validation ==================
+
+
+
+
+
+ // ================== dateTimeField validation ==================
+
+
+
+
+
+ // ================== arrayField validation ==================
+
+ // validate min items 1
+ if (_allValidationErrors.isEmpty || !failFast) {
+ val len = if arrayField == null then 0 else arrayField.size
+ if (len < 1) {
+ _allValidationErrors += ValidationError(path :+ ComplexRequest.Fields.arrayField, s"arrayField has $len, which is less than the min items 1")
+ }
+ }
+ // validate min items 10
+ if (_allValidationErrors.isEmpty || !failFast) {
+ val len = if arrayField == null then 0 else arrayField.size
+ if (len > 10) {
+ _allValidationErrors += ValidationError(path :+ ComplexRequest.Fields.arrayField, s"arrayField has $len, which is greater than the max items 10")
+ }
+ }
+
+
+
+
+ // ================== enumField validation ==================
+
+
+
+
+
+ // ================== nestedObject validation ==================
+
+
+
+
+ // validating nestedObject
+ if (_allValidationErrors.isEmpty || !failFast) {
+ if nestedObject != null then _allValidationErrors ++= nestedObject.validationErrors(path :+ ComplexRequest.Fields.nestedObject, failFast)
+ }
+
+ // ================== arrayOfObjectsField validation ==================
+
+
+
+
+ if (_allValidationErrors.isEmpty || !failFast) {
+ if (arrayOfObjectsField != null) {
+ arrayOfObjectsField.zipWithIndex.foreach {
+ case (value, i) if _allValidationErrors.isEmpty || !failFast =>
+ _allValidationErrors ++= value.validationErrors(
+ path :+ ComplexRequest.Fields.arrayOfObjectsField :+ Field(i.toString),
+ failFast)
+ case (value, i) =>
+ }
+ }
+ }
+
+
+ // ================== patternField validation ==================
+ // validate against pattern '^[a-zA-Z0-9]{3,10}$'
+ if (_allValidationErrors.isEmpty || !failFast) {
+ val regex = """^[a-zA-Z0-9]{3,10}$"""
+ if patternField == null || !regex.r.matches(patternField) then
+ _allValidationErrors += ValidationError(path :+ ComplexRequest.Fields.patternField, s"value '$patternField' doesn't match pattern $regex")
+ }
+
+
+
+
+
+ // ================== nullableField validation ==================
+
+
+
+
+
+ _allValidationErrors.toSeq
+ }
+
+ /**
+ * @return the validated model within a Try (if successful)
+ */
+ def validated(failFast : Boolean = false) : scala.util.Try[ComplexRequest] = {
+ validationErrors(Vector(), failFast) match {
+ case Seq() => Success(asModel)
+ case first +: theRest => Failure(ValidationErrors(first, theRest))
+ }
+ }
+
+ /** use 'validated' to check validation */
+ def asModel : ComplexRequest = {
+ ComplexRequest(
+ `type` = `type` /* 2 */,
+ requiredField = requiredField /* 2 */,
+ stringField = Option(stringField) /* 1 */,
+ integerField = Option(integerField) /* 1 */,
+ numberField = Option(numberField) /* 1 */,
+ booleanField = Option(booleanField) /* 1 */,
+ emailField = Option(emailField) /* 1 */,
+ uuidField = Option(uuidField) /* 1 */,
+ dateField = Option(dateField) /* 1 */,
+ dateTimeField = Option(dateTimeField) /* 1 */,
+ arrayField = arrayField /* 2 */,
+ enumField = Option(enumField) /* 1 */,
+ nestedObject = Option(nestedObject).map(_.asModel) /* 4 */,
+ arrayOfObjectsField = arrayOfObjectsField.map(_.asModel) /* 5 */,
+ patternField = Option(patternField) /* 1 */,
+ nullableField = Option(nullableField) /* 1 */
+ , additionalProperties
+ )
+ }
+}
+
+object ComplexRequestData {
+
+ def validated(d8a : ComplexRequestData, failFast : Boolean) : scala.util.Try[ComplexRequest] = d8a.validated(failFast)
+
+ def fromJson(jason : ujson.Value) : ComplexRequestData = try {
+ val data = read[ComplexRequestData](jason)
+ val obj = jason.obj
+ ComplexRequest.Fields.values.foreach(v => obj.value.subtractOne(v.fieldName))
+ data.copy(additionalProperties = obj)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error creating ComplexRequestData from json '$jason': $e")
+ }
+
+ def fromJsonString(jason : String) : ComplexRequestData = {
+ val parsed = try {
+ read[ujson.Value](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason': $e")
+ }
+ fromJson(parsed)
+ }
+
+ def manyFromJsonString(jason : String) : Seq[ComplexRequestData] = try {
+ read[List[ComplexRequestData]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as list: $e")
+ }
+
+ def manyFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Seq[ComplexRequest]] = {
+ Try(manyFromJsonString(jason)).flatMap { list =>
+ list.zipWithIndex.foldLeft(Try(Vector[ComplexRequest]())) {
+ case (Success(list), (next, i)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(list :+ ok)
+ case Failure(err) => Failure(new Exception(s"Validation error on element $i: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+
+ def mapFromJsonString(jason : String) : Map[String, ComplexRequestData] = try {
+ read[Map[String, ComplexRequestData]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as map: $e")
+ }
+
+
+ def mapFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Map[String, ComplexRequest]] = {
+ Try(mapFromJsonString(jason)).flatMap { map =>
+ map.foldLeft(Try(Map[String, ComplexRequest]())) {
+ case (Success(map), (key, next)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(map.updated(key, ok))
+ case Failure(err) => Failure(new Exception(s"Validation error on element $key: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+}
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequestNestedObject.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequestNestedObject.scala
new file mode 100644
index 00000000000..c3ea749dff2
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequestNestedObject.scala
@@ -0,0 +1,57 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using model.mustache
+package sample.cask.model
+
+import scala.util.control.NonFatal
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+
+case class ComplexRequestNestedObject(
+ /* A field within a nested object */
+ nestedField1: Option[String] = None ,
+ /* Another field in a nested object */
+ nestedField2: Option[Int] = None
+
+
+) {
+
+def asJsonString: String = asData.asJsonString
+def asJson: ujson.Value = asData.asJson
+
+def asData : ComplexRequestNestedObjectData = {
+ComplexRequestNestedObjectData(
+ nestedField1 = nestedField1.getOrElse("") /* 1 */,
+ nestedField2 = nestedField2.getOrElse(0) /* 1 */
+
+)
+}
+}
+
+object ComplexRequestNestedObject {
+given RW[ComplexRequestNestedObject] = summon[RW[ujson.Value]].bimap[ComplexRequestNestedObject](_.asJson, json => read[ComplexRequestNestedObjectData](json).asModel)
+
+enum Fields(val fieldName : String) extends Field(fieldName) {
+ case nestedField1 extends Fields("nestedField1")
+ case nestedField2 extends Fields("nestedField2")
+}
+
+
+}
+
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequestNestedObjectData.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequestNestedObjectData.scala
new file mode 100644
index 00000000000..b7d204891f4
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/ComplexRequestNestedObjectData.scala
@@ -0,0 +1,139 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelData.mustache
+package sample.cask.model
+import scala.util.control.NonFatal
+import scala.util.*
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+ /** ComplexRequestNestedObjectData a data transfer object, primarily for simple json serialisation.
+ * It has no validation - there may be nulls, values out of range, etc
+ */
+case class ComplexRequestNestedObjectData(
+/* A field within a nested object */
+ nestedField1: String = "" ,
+/* Another field in a nested object */
+ nestedField2: Int = 0
+
+
+) derives RW {
+
+ def asJsonString: String = asJson.toString()
+
+ def asJson : ujson.Value = {
+ val jason = writeJs(this)
+ jason
+ }
+
+ def validationErrors(path : Seq[Field], failFast : Boolean) : Seq[ValidationError] = {
+ val _allValidationErrors = scala.collection.mutable.ListBuffer[ValidationError]()
+ // ================== nestedField1 validation ==================
+
+
+
+
+
+ // ================== nestedField2 validation ==================
+
+
+
+
+
+ _allValidationErrors.toSeq
+ }
+
+ /**
+ * @return the validated model within a Try (if successful)
+ */
+ def validated(failFast : Boolean = false) : scala.util.Try[ComplexRequestNestedObject] = {
+ validationErrors(Vector(), failFast) match {
+ case Seq() => Success(asModel)
+ case first +: theRest => Failure(ValidationErrors(first, theRest))
+ }
+ }
+
+ /** use 'validated' to check validation */
+ def asModel : ComplexRequestNestedObject = {
+ ComplexRequestNestedObject(
+ nestedField1 = Option(nestedField1) /* 1 */,
+ nestedField2 = Option(nestedField2) /* 1 */
+
+ )
+ }
+}
+
+object ComplexRequestNestedObjectData {
+
+ def validated(d8a : ComplexRequestNestedObjectData, failFast : Boolean) : scala.util.Try[ComplexRequestNestedObject] = d8a.validated(failFast)
+
+ def fromJson(jason : ujson.Value) : ComplexRequestNestedObjectData = try {
+ val data = read[ComplexRequestNestedObjectData](jason)
+ data
+ } catch {
+ case NonFatal(e) => sys.error(s"Error creating ComplexRequestNestedObjectData from json '$jason': $e")
+ }
+
+ def fromJsonString(jason : String) : ComplexRequestNestedObjectData = {
+ val parsed = try {
+ read[ujson.Value](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason': $e")
+ }
+ fromJson(parsed)
+ }
+
+ def manyFromJsonString(jason : String) : Seq[ComplexRequestNestedObjectData] = try {
+ read[List[ComplexRequestNestedObjectData]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as list: $e")
+ }
+
+ def manyFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Seq[ComplexRequestNestedObject]] = {
+ Try(manyFromJsonString(jason)).flatMap { list =>
+ list.zipWithIndex.foldLeft(Try(Vector[ComplexRequestNestedObject]())) {
+ case (Success(list), (next, i)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(list :+ ok)
+ case Failure(err) => Failure(new Exception(s"Validation error on element $i: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+
+ def mapFromJsonString(jason : String) : Map[String, ComplexRequestNestedObjectData] = try {
+ read[Map[String, ComplexRequestNestedObjectData]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as map: $e")
+ }
+
+
+ def mapFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Map[String, ComplexRequestNestedObject]] = {
+ Try(mapFromJsonString(jason)).flatMap { map =>
+ map.foldLeft(Try(Map[String, ComplexRequestNestedObject]())) {
+ case (Success(map), (key, next)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(map.updated(key, ok))
+ case Failure(err) => Failure(new Exception(s"Validation error on element $key: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+}
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OneOfRequestAndResponse200Response.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OneOfRequestAndResponse200Response.scala
new file mode 100644
index 00000000000..12dc5f4a1d8
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OneOfRequestAndResponse200Response.scala
@@ -0,0 +1,33 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using model.mustache
+package sample.cask.model
+import java.time.OffsetDateTime
+
+import scala.util.control.NonFatal
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+
+type OneOfRequestAndResponse200Response = SomeResponse1 | SomeResponse2
+object OneOfRequestAndResponse200Response {
+
+ given RW[OneOfRequestAndResponse200Response] = RW.merge(summon[RW[SomeResponse1]], summon[RW[SomeResponse2]])
+}
+
+
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OneOfRequestAndResponse200ResponseData.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OneOfRequestAndResponse200ResponseData.scala
new file mode 100644
index 00000000000..dd4e1051c40
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OneOfRequestAndResponse200ResponseData.scala
@@ -0,0 +1,48 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelData.mustache
+package sample.cask.model
+import java.time.OffsetDateTime
+import scala.util.control.NonFatal
+import scala.util.*
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+type OneOfRequestAndResponse200ResponseData = SomeResponse1Data | SomeResponse2Data
+
+object OneOfRequestAndResponse200ResponseData {
+
+ def validated(d8a : OneOfRequestAndResponse200ResponseData, failFast: Boolean) : Try[OneOfRequestAndResponse200Response] = {
+ d8a match {
+ case value : SomeResponse1Data => value.validated(failFast)
+ case value : SomeResponse2Data => value.validated(failFast)
+ }
+ }
+
+ def fromJsonString(jason : String) = fromJson {
+ try {
+ read[ujson.Value](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason': $e")
+ }
+ }
+
+ def fromJson(jason : ujson.Value) : OneOfRequestAndResponse200ResponseData = {
+ val attempt = Try(SomeResponse1Data.fromJson(jason)) .orElse( Try(SomeResponse2Data.fromJson(jason)) ) /* not first */
+ attempt.get
+ }
+}
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OneOfRequestAndResponseRequest.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OneOfRequestAndResponseRequest.scala
new file mode 100644
index 00000000000..af69e0107e7
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OneOfRequestAndResponseRequest.scala
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using model.mustache
+package sample.cask.model
+import java.time.LocalDate
+import java.time.OffsetDateTime
+import java.util.UUID
+import scala.math.BigDecimal
+
+import scala.util.control.NonFatal
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+
+type OneOfRequestAndResponseRequest = AllOfRequest | ComplexRequest
+object OneOfRequestAndResponseRequest {
+
+ given RW[OneOfRequestAndResponseRequest] = RW.merge(summon[RW[AllOfRequest]], summon[RW[ComplexRequest]])
+}
+
+
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OneOfRequestAndResponseRequestData.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OneOfRequestAndResponseRequestData.scala
new file mode 100644
index 00000000000..f9c7ef40b0d
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OneOfRequestAndResponseRequestData.scala
@@ -0,0 +1,51 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelData.mustache
+package sample.cask.model
+import java.time.LocalDate
+import java.time.OffsetDateTime
+import java.util.UUID
+import scala.math.BigDecimal
+import scala.util.control.NonFatal
+import scala.util.*
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+type OneOfRequestAndResponseRequestData = AllOfRequestData | ComplexRequestData
+
+object OneOfRequestAndResponseRequestData {
+
+ def validated(d8a : OneOfRequestAndResponseRequestData, failFast: Boolean) : Try[OneOfRequestAndResponseRequest] = {
+ d8a match {
+ case value : AllOfRequestData => value.validated(failFast)
+ case value : ComplexRequestData => value.validated(failFast)
+ }
+ }
+
+ def fromJsonString(jason : String) = fromJson {
+ try {
+ read[ujson.Value](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason': $e")
+ }
+ }
+
+ def fromJson(jason : ujson.Value) : OneOfRequestAndResponseRequestData = {
+ val attempt = Try(AllOfRequestData.fromJson(jason)) .orElse( Try(ComplexRequestData.fromJson(jason)) ) /* not first */
+ attempt.get
+ }
+}
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Order.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Order.scala
index 77dbcd6793b..03b50eae2a9 100644
--- a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Order.scala
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Order.scala
@@ -22,7 +22,7 @@ import upickle.default.{ReadWriter => RW, macroRW}
import upickle.default.*
-
+
case class Order(
id: Option[Long] = None ,
petId: Option[Long] = None ,
@@ -73,3 +73,4 @@ enum Fields(val fieldName : String) extends Field(fieldName) {
}
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OrderData.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OrderData.scala
index 1330c2111c5..2ef08f14aa6 100644
--- a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OrderData.scala
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/OrderData.scala
@@ -45,7 +45,7 @@ case class OrderData(
}
def validationErrors(path : Seq[Field], failFast : Boolean) : Seq[ValidationError] = {
- val errors = scala.collection.mutable.ListBuffer[ValidationError]()
+ val _allValidationErrors = scala.collection.mutable.ListBuffer[ValidationError]()
// ================== id validation ==================
@@ -82,7 +82,7 @@ case class OrderData(
- errors.toSeq
+ _allValidationErrors.toSeq
}
/**
@@ -111,6 +111,8 @@ case class OrderData(
object OrderData {
+ def validated(d8a : OrderData, failFast : Boolean) : scala.util.Try[Order] = d8a.validated(failFast)
+
def fromJson(jason : ujson.Value) : OrderData = try {
val data = read[OrderData](jason)
data
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Pet.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Pet.scala
index 58725e10dcc..041aab7f6ed 100644
--- a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Pet.scala
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Pet.scala
@@ -21,7 +21,7 @@ import upickle.default.{ReadWriter => RW, macroRW}
import upickle.default.*
-
+
case class Pet(
id: Option[Long] = None ,
category: Option[Category] = None ,
@@ -72,3 +72,4 @@ enum Fields(val fieldName : String) extends Field(fieldName) {
}
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/PetData.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/PetData.scala
index 755d33c288d..126c81abe88 100644
--- a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/PetData.scala
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/PetData.scala
@@ -44,7 +44,7 @@ case class PetData(
}
def validationErrors(path : Seq[Field], failFast : Boolean) : Seq[ValidationError] = {
- val errors = scala.collection.mutable.ListBuffer[ValidationError]()
+ val _allValidationErrors = scala.collection.mutable.ListBuffer[ValidationError]()
// ================== id validation ==================
@@ -57,8 +57,8 @@ case class PetData(
// validating category
- if (errors.isEmpty || !failFast) {
- if category != null then errors ++= category.validationErrors(path :+ Pet.Fields.category, failFast)
+ if (_allValidationErrors.isEmpty || !failFast) {
+ if category != null then _allValidationErrors ++= category.validationErrors(path :+ Pet.Fields.category, failFast)
}
// ================== name validation ==================
@@ -78,11 +78,11 @@ case class PetData(
- if (errors.isEmpty || !failFast) {
+ if (_allValidationErrors.isEmpty || !failFast) {
if (tags != null) {
tags.zipWithIndex.foreach {
- case (value, i) if errors.isEmpty || !failFast =>
- errors ++= value.validationErrors(
+ case (value, i) if _allValidationErrors.isEmpty || !failFast =>
+ _allValidationErrors ++= value.validationErrors(
path :+ Pet.Fields.tags :+ Field(i.toString),
failFast)
case (value, i) =>
@@ -97,7 +97,7 @@ case class PetData(
- errors.toSeq
+ _allValidationErrors.toSeq
}
/**
@@ -126,6 +126,8 @@ case class PetData(
object PetData {
+ def validated(d8a : PetData, failFast : Boolean) : scala.util.Try[Pet] = d8a.validated(failFast)
+
def fromJson(jason : ujson.Value) : PetData = try {
val data = read[PetData](jason)
data
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse1.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse1.scala
new file mode 100644
index 00000000000..4ba6da63550
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse1.scala
@@ -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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using model.mustache
+package sample.cask.model
+
+import scala.util.control.NonFatal
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+
+case class SomeResponse1(
+ status: String,
+ message: String
+
+
+) {
+
+def asJsonString: String = asData.asJsonString
+def asJson: ujson.Value = asData.asJson
+
+def asData : SomeResponse1Data = {
+SomeResponse1Data(
+ status = status /* 2 */,
+ message = message /* 2 */
+
+)
+}
+}
+
+object SomeResponse1 {
+given RW[SomeResponse1] = summon[RW[ujson.Value]].bimap[SomeResponse1](_.asJson, json => read[SomeResponse1Data](json).asModel)
+
+enum Fields(val fieldName : String) extends Field(fieldName) {
+ case status extends Fields("status")
+ case message extends Fields("message")
+}
+
+
+}
+
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse1Data.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse1Data.scala
new file mode 100644
index 00000000000..1437eafe712
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse1Data.scala
@@ -0,0 +1,137 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelData.mustache
+package sample.cask.model
+import scala.util.control.NonFatal
+import scala.util.*
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+ /** SomeResponse1Data a data transfer object, primarily for simple json serialisation.
+ * It has no validation - there may be nulls, values out of range, etc
+ */
+case class SomeResponse1Data(
+ status: String,
+ message: String
+
+
+) derives RW {
+
+ def asJsonString: String = asJson.toString()
+
+ def asJson : ujson.Value = {
+ val jason = writeJs(this)
+ jason
+ }
+
+ def validationErrors(path : Seq[Field], failFast : Boolean) : Seq[ValidationError] = {
+ val _allValidationErrors = scala.collection.mutable.ListBuffer[ValidationError]()
+ // ================== status validation ==================
+
+
+
+
+
+ // ================== message validation ==================
+
+
+
+
+
+ _allValidationErrors.toSeq
+ }
+
+ /**
+ * @return the validated model within a Try (if successful)
+ */
+ def validated(failFast : Boolean = false) : scala.util.Try[SomeResponse1] = {
+ validationErrors(Vector(), failFast) match {
+ case Seq() => Success(asModel)
+ case first +: theRest => Failure(ValidationErrors(first, theRest))
+ }
+ }
+
+ /** use 'validated' to check validation */
+ def asModel : SomeResponse1 = {
+ SomeResponse1(
+ status = status /* 2 */,
+ message = message /* 2 */
+
+ )
+ }
+}
+
+object SomeResponse1Data {
+
+ def validated(d8a : SomeResponse1Data, failFast : Boolean) : scala.util.Try[SomeResponse1] = d8a.validated(failFast)
+
+ def fromJson(jason : ujson.Value) : SomeResponse1Data = try {
+ val data = read[SomeResponse1Data](jason)
+ data
+ } catch {
+ case NonFatal(e) => sys.error(s"Error creating SomeResponse1Data from json '$jason': $e")
+ }
+
+ def fromJsonString(jason : String) : SomeResponse1Data = {
+ val parsed = try {
+ read[ujson.Value](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason': $e")
+ }
+ fromJson(parsed)
+ }
+
+ def manyFromJsonString(jason : String) : Seq[SomeResponse1Data] = try {
+ read[List[SomeResponse1Data]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as list: $e")
+ }
+
+ def manyFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Seq[SomeResponse1]] = {
+ Try(manyFromJsonString(jason)).flatMap { list =>
+ list.zipWithIndex.foldLeft(Try(Vector[SomeResponse1]())) {
+ case (Success(list), (next, i)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(list :+ ok)
+ case Failure(err) => Failure(new Exception(s"Validation error on element $i: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+
+ def mapFromJsonString(jason : String) : Map[String, SomeResponse1Data] = try {
+ read[Map[String, SomeResponse1Data]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as map: $e")
+ }
+
+
+ def mapFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Map[String, SomeResponse1]] = {
+ Try(mapFromJsonString(jason)).flatMap { map =>
+ map.foldLeft(Try(Map[String, SomeResponse1]())) {
+ case (Success(map), (key, next)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(map.updated(key, ok))
+ case Failure(err) => Failure(new Exception(s"Validation error on element $key: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+}
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse2.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse2.scala
new file mode 100644
index 00000000000..122706e7357
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse2.scala
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using model.mustache
+package sample.cask.model
+import java.time.OffsetDateTime
+
+import scala.util.control.NonFatal
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+
+case class SomeResponse2(
+ id: String,
+ createdAt: OffsetDateTime,
+ details: Option[SomeResponse2Details] = None
+
+
+) {
+
+def asJsonString: String = asData.asJsonString
+def asJson: ujson.Value = asData.asJson
+
+def asData : SomeResponse2Data = {
+SomeResponse2Data(
+ id = id /* 2 */,
+ createdAt = createdAt /* 2 */,
+ details = details.map(_.asData).getOrElse(null) /* 4 */
+
+)
+}
+}
+
+object SomeResponse2 {
+given RW[SomeResponse2] = summon[RW[ujson.Value]].bimap[SomeResponse2](_.asJson, json => read[SomeResponse2Data](json).asModel)
+
+enum Fields(val fieldName : String) extends Field(fieldName) {
+ case id extends Fields("id")
+ case createdAt extends Fields("createdAt")
+ case details extends Fields("details")
+}
+
+
+}
+
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse2Data.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse2Data.scala
new file mode 100644
index 00000000000..fad33a53186
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse2Data.scala
@@ -0,0 +1,156 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelData.mustache
+package sample.cask.model
+import java.time.OffsetDateTime
+import scala.util.control.NonFatal
+import scala.util.*
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+ /** SomeResponse2Data a data transfer object, primarily for simple json serialisation.
+ * It has no validation - there may be nulls, values out of range, etc
+ */
+case class SomeResponse2Data(
+ id: String,
+ createdAt: OffsetDateTime,
+ details: SomeResponse2DetailsData = null
+
+
+) derives RW {
+
+ def asJsonString: String = asJson.toString()
+
+ def asJson : ujson.Value = {
+ val jason = writeJs(this)
+ jason
+ }
+
+ def validationErrors(path : Seq[Field], failFast : Boolean) : Seq[ValidationError] = {
+ val _allValidationErrors = scala.collection.mutable.ListBuffer[ValidationError]()
+ // ================== id validation ==================
+
+
+
+
+
+ // ================== createdAt validation ==================
+
+ if (_allValidationErrors.isEmpty || !failFast) {
+ if (createdAt == null) {
+ _allValidationErrors += ValidationError(path :+ SomeResponse2.Fields.createdAt, "createdAt is a required field and cannot be null")
+ }
+ }
+
+
+
+
+
+ // ================== details validation ==================
+
+
+
+
+ // validating details
+ if (_allValidationErrors.isEmpty || !failFast) {
+ if details != null then _allValidationErrors ++= details.validationErrors(path :+ SomeResponse2.Fields.details, failFast)
+ }
+
+ _allValidationErrors.toSeq
+ }
+
+ /**
+ * @return the validated model within a Try (if successful)
+ */
+ def validated(failFast : Boolean = false) : scala.util.Try[SomeResponse2] = {
+ validationErrors(Vector(), failFast) match {
+ case Seq() => Success(asModel)
+ case first +: theRest => Failure(ValidationErrors(first, theRest))
+ }
+ }
+
+ /** use 'validated' to check validation */
+ def asModel : SomeResponse2 = {
+ SomeResponse2(
+ id = id /* 2 */,
+ createdAt = createdAt /* 2 */,
+ details = Option(details).map(_.asModel) /* 4 */
+
+ )
+ }
+}
+
+object SomeResponse2Data {
+
+ def validated(d8a : SomeResponse2Data, failFast : Boolean) : scala.util.Try[SomeResponse2] = d8a.validated(failFast)
+
+ def fromJson(jason : ujson.Value) : SomeResponse2Data = try {
+ val data = read[SomeResponse2Data](jason)
+ data
+ } catch {
+ case NonFatal(e) => sys.error(s"Error creating SomeResponse2Data from json '$jason': $e")
+ }
+
+ def fromJsonString(jason : String) : SomeResponse2Data = {
+ val parsed = try {
+ read[ujson.Value](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason': $e")
+ }
+ fromJson(parsed)
+ }
+
+ def manyFromJsonString(jason : String) : Seq[SomeResponse2Data] = try {
+ read[List[SomeResponse2Data]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as list: $e")
+ }
+
+ def manyFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Seq[SomeResponse2]] = {
+ Try(manyFromJsonString(jason)).flatMap { list =>
+ list.zipWithIndex.foldLeft(Try(Vector[SomeResponse2]())) {
+ case (Success(list), (next, i)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(list :+ ok)
+ case Failure(err) => Failure(new Exception(s"Validation error on element $i: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+
+ def mapFromJsonString(jason : String) : Map[String, SomeResponse2Data] = try {
+ read[Map[String, SomeResponse2Data]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as map: $e")
+ }
+
+
+ def mapFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Map[String, SomeResponse2]] = {
+ Try(mapFromJsonString(jason)).flatMap { map =>
+ map.foldLeft(Try(Map[String, SomeResponse2]())) {
+ case (Success(map), (key, next)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(map.updated(key, ok))
+ case Failure(err) => Failure(new Exception(s"Validation error on element $key: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+}
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse2Details.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse2Details.scala
new file mode 100644
index 00000000000..e3b2eaf26e7
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse2Details.scala
@@ -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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using model.mustache
+package sample.cask.model
+
+import scala.util.control.NonFatal
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+
+case class SomeResponse2Details(
+ description: Option[String] = None ,
+ status: Option[String] = None
+
+
+) {
+
+def asJsonString: String = asData.asJsonString
+def asJson: ujson.Value = asData.asJson
+
+def asData : SomeResponse2DetailsData = {
+SomeResponse2DetailsData(
+ description = description.getOrElse("") /* 1 */,
+ status = status.getOrElse("") /* 1 */
+
+)
+}
+}
+
+object SomeResponse2Details {
+given RW[SomeResponse2Details] = summon[RW[ujson.Value]].bimap[SomeResponse2Details](_.asJson, json => read[SomeResponse2DetailsData](json).asModel)
+
+enum Fields(val fieldName : String) extends Field(fieldName) {
+ case description extends Fields("description")
+ case status extends Fields("status")
+}
+
+
+}
+
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse2DetailsData.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse2DetailsData.scala
new file mode 100644
index 00000000000..371693b4c83
--- /dev/null
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/SomeResponse2DetailsData.scala
@@ -0,0 +1,137 @@
+/**
+ * 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.
+ *
+ * OpenAPI spec version: 1.0.0
+ *
+ * Contact: team@openapitools.org
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator.
+ *
+ * https://openapi-generator.tech
+ */
+
+// this model was generated using modelData.mustache
+package sample.cask.model
+import scala.util.control.NonFatal
+import scala.util.*
+
+// see https://com-lihaoyi.github.io/upickle/
+import upickle.default.{ReadWriter => RW, macroRW}
+import upickle.default.*
+
+
+ /** SomeResponse2DetailsData a data transfer object, primarily for simple json serialisation.
+ * It has no validation - there may be nulls, values out of range, etc
+ */
+case class SomeResponse2DetailsData(
+ description: String = "" ,
+ status: String = ""
+
+
+) derives RW {
+
+ def asJsonString: String = asJson.toString()
+
+ def asJson : ujson.Value = {
+ val jason = writeJs(this)
+ jason
+ }
+
+ def validationErrors(path : Seq[Field], failFast : Boolean) : Seq[ValidationError] = {
+ val _allValidationErrors = scala.collection.mutable.ListBuffer[ValidationError]()
+ // ================== description validation ==================
+
+
+
+
+
+ // ================== status validation ==================
+
+
+
+
+
+ _allValidationErrors.toSeq
+ }
+
+ /**
+ * @return the validated model within a Try (if successful)
+ */
+ def validated(failFast : Boolean = false) : scala.util.Try[SomeResponse2Details] = {
+ validationErrors(Vector(), failFast) match {
+ case Seq() => Success(asModel)
+ case first +: theRest => Failure(ValidationErrors(first, theRest))
+ }
+ }
+
+ /** use 'validated' to check validation */
+ def asModel : SomeResponse2Details = {
+ SomeResponse2Details(
+ description = Option(description) /* 1 */,
+ status = Option(status) /* 1 */
+
+ )
+ }
+}
+
+object SomeResponse2DetailsData {
+
+ def validated(d8a : SomeResponse2DetailsData, failFast : Boolean) : scala.util.Try[SomeResponse2Details] = d8a.validated(failFast)
+
+ def fromJson(jason : ujson.Value) : SomeResponse2DetailsData = try {
+ val data = read[SomeResponse2DetailsData](jason)
+ data
+ } catch {
+ case NonFatal(e) => sys.error(s"Error creating SomeResponse2DetailsData from json '$jason': $e")
+ }
+
+ def fromJsonString(jason : String) : SomeResponse2DetailsData = {
+ val parsed = try {
+ read[ujson.Value](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason': $e")
+ }
+ fromJson(parsed)
+ }
+
+ def manyFromJsonString(jason : String) : Seq[SomeResponse2DetailsData] = try {
+ read[List[SomeResponse2DetailsData]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as list: $e")
+ }
+
+ def manyFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Seq[SomeResponse2Details]] = {
+ Try(manyFromJsonString(jason)).flatMap { list =>
+ list.zipWithIndex.foldLeft(Try(Vector[SomeResponse2Details]())) {
+ case (Success(list), (next, i)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(list :+ ok)
+ case Failure(err) => Failure(new Exception(s"Validation error on element $i: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+
+ def mapFromJsonString(jason : String) : Map[String, SomeResponse2DetailsData] = try {
+ read[Map[String, SomeResponse2DetailsData]](jason)
+ } catch {
+ case NonFatal(e) => sys.error(s"Error parsing json '$jason' as map: $e")
+ }
+
+
+ def mapFromJsonStringValidated(jason : String, failFast : Boolean = false) : Try[Map[String, SomeResponse2Details]] = {
+ Try(mapFromJsonString(jason)).flatMap { map =>
+ map.foldLeft(Try(Map[String, SomeResponse2Details]())) {
+ case (Success(map), (key, next)) =>
+ next.validated(failFast) match {
+ case Success(ok) => Success(map.updated(key, ok))
+ case Failure(err) => Failure(new Exception(s"Validation error on element $key: ${err.getMessage}", err))
+ }
+ case (fail, _) => fail
+ }
+ }
+ }
+}
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Tag.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Tag.scala
index fa6805f6c33..05ff4fcc9d6 100644
--- a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Tag.scala
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/Tag.scala
@@ -21,7 +21,7 @@ import upickle.default.{ReadWriter => RW, macroRW}
import upickle.default.*
-
+
case class Tag(
id: Option[Long] = None ,
name: Option[String] = None
@@ -52,3 +52,4 @@ enum Fields(val fieldName : String) extends Field(fieldName) {
}
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/TagData.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/TagData.scala
index 972b21dd518..35db0cdb382 100644
--- a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/TagData.scala
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/TagData.scala
@@ -39,7 +39,7 @@ case class TagData(
}
def validationErrors(path : Seq[Field], failFast : Boolean) : Seq[ValidationError] = {
- val errors = scala.collection.mutable.ListBuffer[ValidationError]()
+ val _allValidationErrors = scala.collection.mutable.ListBuffer[ValidationError]()
// ================== id validation ==================
@@ -52,7 +52,7 @@ case class TagData(
- errors.toSeq
+ _allValidationErrors.toSeq
}
/**
@@ -77,6 +77,8 @@ case class TagData(
object TagData {
+ def validated(d8a : TagData, failFast : Boolean) : scala.util.Try[Tag] = d8a.validated(failFast)
+
def fromJson(jason : ujson.Value) : TagData = try {
val data = read[TagData](jason)
data
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/User.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/User.scala
index 55614de4f87..5e432c0b043 100644
--- a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/User.scala
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/User.scala
@@ -21,7 +21,7 @@ import upickle.default.{ReadWriter => RW, macroRW}
import upickle.default.*
-
+
case class User(
id: Option[Long] = None ,
username: Option[String] = None ,
@@ -71,3 +71,4 @@ enum Fields(val fieldName : String) extends Field(fieldName) {
}
+
diff --git a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/UserData.scala b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/UserData.scala
index 07b5cb1de41..dea3a5927b1 100644
--- a/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/UserData.scala
+++ b/samples/server/petstore/scala-cask/shared/src/main/scala/sample/cask/model/UserData.scala
@@ -46,7 +46,7 @@ case class UserData(
}
def validationErrors(path : Seq[Field], failFast : Boolean) : Seq[ValidationError] = {
- val errors = scala.collection.mutable.ListBuffer[ValidationError]()
+ val _allValidationErrors = scala.collection.mutable.ListBuffer[ValidationError]()
// ================== id validation ==================
@@ -95,7 +95,7 @@ case class UserData(
- errors.toSeq
+ _allValidationErrors.toSeq
}
/**
@@ -126,6 +126,8 @@ case class UserData(
object UserData {
+ def validated(d8a : UserData, failFast : Boolean) : scala.util.Try[User] = d8a.validated(failFast)
+
def fromJson(jason : ujson.Value) : UserData = try {
val data = read[UserData](jason)
data