Scala Cask oneOf support (#20051)

* added support for 'oneOf' types represented as unions

also updated libs and an 'errors' field rename to address
name clashes with likely/popular field names

* Created cask-specific petstore example which 
Includes a oneOf and allOf example
This commit is contained in:
Aaron Pritzlaff 2024-11-11 10:46:27 +00:00 committed by GitHub
parent bfcfc6ff25
commit 6792218775
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
66 changed files with 3994 additions and 95 deletions

View File

@ -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"

View File

@ -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:
* <p>
* {{{
* 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<String> 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<String> 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<String> 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));
}

View File

@ -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}}

View File

@ -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}}

View File

@ -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}}

View File

@ -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}}

View File

@ -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}}

View File

@ -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")
}

View File

@ -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}}

View File

@ -1 +1 @@
sbt.version=1.9.9
sbt.version=1.10.3

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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" : {

View File

@ -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

View File

@ -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(),

View File

@ -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 &#39;oneOf&#39; 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()
}

View File

@ -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"))

View File

@ -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"))

View File

@ -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)

View File

@ -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")
}
}
}

View File

@ -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")
}
}
}

View File

@ -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")
}
}
}

View File

@ -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")
}
}
}

View File

@ -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")
}
}
}

View File

@ -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")
}
}
}

View File

@ -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")
}
}
}

View File

@ -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")
}
}
}

View File

@ -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")
}
}
}

View File

@ -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")
}
}
}

View File

@ -1 +1 @@
sbt.version=1.9.9
sbt.version=1.10.3

View File

@ -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")

View File

@ -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&lt;Function&gt;" 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)
}
}
}
}

View File

@ -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")
}
}

View File

@ -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
}
}
}
}

View File

@ -0,0 +1,55 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* 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")
}
}

View File

@ -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
}
}
}
}

View File

@ -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) {
}

View File

@ -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

View File

@ -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) {
}

View File

@ -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

View File

@ -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
}
}

View File

@ -0,0 +1,55 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* 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")
}
}

View File

@ -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
}
}
}
}

View File

@ -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
}
}
}
}

View File

@ -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")
}
}

View File

@ -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
}
}
}
}

View File

@ -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]])
}

View File

@ -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
}
}

View File

@ -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]])
}

View File

@ -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
}
}

View File

@ -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) {
}

View File

@ -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

View File

@ -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) {
}

View File

@ -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

View File

@ -0,0 +1,55 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* 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")
}
}

View File

@ -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
}
}
}
}

View File

@ -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")
}
}

View File

@ -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
}
}
}
}

View File

@ -0,0 +1,55 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* 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")
}
}

View File

@ -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
}
}
}
}

View File

@ -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) {
}

View File

@ -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

View File

@ -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) {
}

View File

@ -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