forked from loafle/openapi-generator-original
[Scala][Client]Add Http4s scala3 client codegen (#19658)
* fix attemp * use java.time.Instant * fix client gen * Tweeks * header and form * use scala 3 enum * more tweeks * add additional properties; add auth * add form media type * add modelsOnly * add unit tests * add petstore samples * add doc * add new samle to .github/workflows/samples-scala.yaml * update build.sbt template * simply the baseclient * add None to optional field * tweek auth model and format --------- Co-authored-by: Jenny Leahy <jennyleahy@JENNYLEAHY.localdomain>
This commit is contained in:
parent
e5dee54797
commit
9791e6f537
1
.github/workflows/samples-scala.yaml
vendored
1
.github/workflows/samples-scala.yaml
vendored
@ -23,6 +23,7 @@ jobs:
|
||||
- 'samples/client/petstore/java/okhttp-gson'
|
||||
- samples/client/petstore/scalaz
|
||||
- samples/client/petstore/scala-pekko
|
||||
- samples/client/petstore/scala-http4s
|
||||
#- samples/client/petstore/scala-sttp # won't pass while the same tests in circleci pass
|
||||
# servers
|
||||
- samples/server/petstore/scala-lagom-server
|
||||
|
6
bin/configs/scala-http4s.yaml
Normal file
6
bin/configs/scala-http4s.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
generatorName: scala-http4s
|
||||
outputDir: samples/client/petstore/scala-http4s
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/scala-http4s/petstore.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/scala-http4s
|
||||
additionalProperties:
|
||||
artifactId: scala-http4s-client
|
272
docs/generators/scala-http4s.md
Normal file
272
docs/generators/scala-http4s.md
Normal file
@ -0,0 +1,272 @@
|
||||
---
|
||||
title: Documentation for the scala-http4s Generator
|
||||
---
|
||||
|
||||
## METADATA
|
||||
|
||||
| Property | Value | Notes |
|
||||
| -------- | ----- | ----- |
|
||||
| generator name | scala-http4s | pass this to the generate command after -g |
|
||||
| generator stability | STABLE | |
|
||||
| generator type | CLIENT | |
|
||||
| generator language | Scala | |
|
||||
| generator default templating engine | mustache | |
|
||||
| helpTxt | Generates a scala-http4s client. | |
|
||||
|
||||
## CONFIG OPTIONS
|
||||
These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details.
|
||||
|
||||
| Option | Description | Values | Default |
|
||||
|-------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------ | ------- |
|
||||
| allowUnicodeIdentifiers | boolean, toggles whether unicode identifiers are allowed in names or not, default is false | |false|
|
||||
| packageName | main package for the generated classes, parent package for api package and model package | |null|
|
||||
| artifactId | project name / artifactId for for the generated project | |null|
|
||||
| excludeSbt | exclude sbt from generation | |null|
|
||||
| excludeApi | exclude apis from generation | |null|
|
||||
| prependFormOrBodyParameters | Add form or body parameters to the beginning of the parameter list. | |false|
|
||||
| disallowAdditionalPropertiesIfNotPresent | If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default. |<dl><dt>**false**</dt><dd>The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.</dd><dt>**true**</dt><dd>Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.</dd></dl>|true|
|
||||
| ensureUniqueParams | Whether to ensure parameter names are unique in an operation (rename parameters that are not). | |true|
|
||||
| legacyDiscriminatorBehavior | Set to false for generators with better support for discriminators. (Python, Java, Go, PowerShell, C# have this enabled by default). |<dl><dt>**true**</dt><dd>The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.</dd><dt>**false**</dt><dd>The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.</dd></dl>|true|
|
||||
| sortModelPropertiesByRequiredFlag | Sort model properties to place required parameters before optional parameters. | |true|
|
||||
| sortParamsByRequiredFlag | Sort method arguments to place required parameters before optional parameters. | |true|
|
||||
| sourceFolder | source folder for generated code | |null|
|
||||
|
||||
## IMPORT MAPPING
|
||||
|
||||
| Type/Alias | Imports |
|
||||
| ---------- | ------- |
|
||||
|ArrayBuffer|scala.collection.mutable.ArrayBuffer|
|
||||
|Date|java.util.Date|
|
||||
|File|java.io.File|
|
||||
|HashMap|scala.collection.immutable.HashMap|
|
||||
|Instant|java.time.Instant|
|
||||
|Json|io.circe.Json|
|
||||
|LocalDate|java.time.LocalDate|
|
||||
|LocalDateTime|java.time.LocalDateTime|
|
||||
|LocalTime|java.time.LocalTime|
|
||||
|Map|scala.collection.immutable.Map|
|
||||
|OffsetDateTime|java.time.OffsetDateTime|
|
||||
|Seq|scala.collection.immutable.Seq|
|
||||
|Timestamp|java.sql.Timestamp|
|
||||
|URI|java.net.URI|
|
||||
|UUID|java.util.UUID|
|
||||
|ZonedDateTime|java.time.ZonedDateTime|
|
||||
|
||||
|
||||
## INSTANTIATION TYPES
|
||||
|
||||
| Type/Alias | Instantiated By |
|
||||
| ---------- | --------------- |
|
||||
|array|Seq|
|
||||
|list|List|
|
||||
|map|Map|
|
||||
|seq|Seq|
|
||||
|set|Set|
|
||||
|
||||
|
||||
## LANGUAGE PRIMITIVES
|
||||
|
||||
<ul class="column-ul">
|
||||
<li>Any</li>
|
||||
<li>AnyRef</li>
|
||||
<li>AnyVal</li>
|
||||
<li>BigDecimal</li>
|
||||
<li>Boolean</li>
|
||||
<li>Double</li>
|
||||
<li>Float</li>
|
||||
<li>Int</li>
|
||||
<li>Integer</li>
|
||||
<li>Long</li>
|
||||
<li>Object</li>
|
||||
<li>String</li>
|
||||
</ul>
|
||||
|
||||
## RESERVED WORDS
|
||||
|
||||
<ul class="column-ul">
|
||||
<li>abstract</li>
|
||||
<li>assert</li>
|
||||
<li>break</li>
|
||||
<li>byte</li>
|
||||
<li>case</li>
|
||||
<li>catch</li>
|
||||
<li>char</li>
|
||||
<li>class</li>
|
||||
<li>const</li>
|
||||
<li>continue</li>
|
||||
<li>def</li>
|
||||
<li>default</li>
|
||||
<li>do</li>
|
||||
<li>double</li>
|
||||
<li>else</li>
|
||||
<li>enum</li>
|
||||
<li>extends</li>
|
||||
<li>false</li>
|
||||
<li>final</li>
|
||||
<li>finally</li>
|
||||
<li>float</li>
|
||||
<li>for</li>
|
||||
<li>forsome</li>
|
||||
<li>goto</li>
|
||||
<li>if</li>
|
||||
<li>implements</li>
|
||||
<li>implicit</li>
|
||||
<li>import</li>
|
||||
<li>instanceof</li>
|
||||
<li>int</li>
|
||||
<li>interface</li>
|
||||
<li>lazy</li>
|
||||
<li>long</li>
|
||||
<li>match</li>
|
||||
<li>native</li>
|
||||
<li>new</li>
|
||||
<li>null</li>
|
||||
<li>object</li>
|
||||
<li>override</li>
|
||||
<li>package</li>
|
||||
<li>private</li>
|
||||
<li>protected</li>
|
||||
<li>public</li>
|
||||
<li>return</li>
|
||||
<li>sealed</li>
|
||||
<li>short</li>
|
||||
<li>static</li>
|
||||
<li>strictfp</li>
|
||||
<li>super</li>
|
||||
<li>switch</li>
|
||||
<li>synchronized</li>
|
||||
<li>this</li>
|
||||
<li>throw</li>
|
||||
<li>throws</li>
|
||||
<li>trait</li>
|
||||
<li>transient</li>
|
||||
<li>true</li>
|
||||
<li>try</li>
|
||||
<li>type</li>
|
||||
<li>val</li>
|
||||
<li>var</li>
|
||||
<li>void</li>
|
||||
<li>volatile</li>
|
||||
<li>while</li>
|
||||
<li>with</li>
|
||||
<li>yield</li>
|
||||
</ul>
|
||||
|
||||
## FEATURE SET
|
||||
|
||||
|
||||
### Client Modification Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|BasePath|✗|ToolingExtension
|
||||
|Authorizations|✗|ToolingExtension
|
||||
|UserAgent|✗|ToolingExtension
|
||||
|MockServer|✗|ToolingExtension
|
||||
|
||||
### Data Type Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|Custom|✗|OAS2,OAS3
|
||||
|Int32|✓|OAS2,OAS3
|
||||
|Int64|✓|OAS2,OAS3
|
||||
|Float|✓|OAS2,OAS3
|
||||
|Double|✓|OAS2,OAS3
|
||||
|Decimal|✓|ToolingExtension
|
||||
|String|✓|OAS2,OAS3
|
||||
|Byte|✓|OAS2,OAS3
|
||||
|Binary|✓|OAS2,OAS3
|
||||
|Boolean|✓|OAS2,OAS3
|
||||
|Date|✓|OAS2,OAS3
|
||||
|DateTime|✓|OAS2,OAS3
|
||||
|Password|✓|OAS2,OAS3
|
||||
|File|✓|OAS2
|
||||
|Uuid|✗|
|
||||
|Array|✓|OAS2,OAS3
|
||||
|Null|✗|OAS3
|
||||
|AnyType|✗|OAS2,OAS3
|
||||
|Object|✓|OAS2,OAS3
|
||||
|Maps|✓|ToolingExtension
|
||||
|CollectionFormat|✓|OAS2
|
||||
|CollectionFormatMulti|✓|OAS2
|
||||
|Enum|✓|OAS2,OAS3
|
||||
|ArrayOfEnum|✓|ToolingExtension
|
||||
|ArrayOfModel|✓|ToolingExtension
|
||||
|ArrayOfCollectionOfPrimitives|✓|ToolingExtension
|
||||
|ArrayOfCollectionOfModel|✓|ToolingExtension
|
||||
|ArrayOfCollectionOfEnum|✓|ToolingExtension
|
||||
|MapOfEnum|✓|ToolingExtension
|
||||
|MapOfModel|✓|ToolingExtension
|
||||
|MapOfCollectionOfPrimitives|✓|ToolingExtension
|
||||
|MapOfCollectionOfModel|✓|ToolingExtension
|
||||
|MapOfCollectionOfEnum|✓|ToolingExtension
|
||||
|
||||
### Documentation Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|Readme|✗|ToolingExtension
|
||||
|Model|✓|ToolingExtension
|
||||
|Api|✓|ToolingExtension
|
||||
|
||||
### Global Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|Host|✓|OAS2,OAS3
|
||||
|BasePath|✓|OAS2,OAS3
|
||||
|Info|✓|OAS2,OAS3
|
||||
|Schemes|✗|OAS2,OAS3
|
||||
|PartialSchemes|✓|OAS2,OAS3
|
||||
|Consumes|✓|OAS2
|
||||
|Produces|✓|OAS2
|
||||
|ExternalDocumentation|✓|OAS2,OAS3
|
||||
|Examples|✓|OAS2,OAS3
|
||||
|XMLStructureDefinitions|✗|OAS2,OAS3
|
||||
|MultiServer|✗|OAS3
|
||||
|ParameterizedServer|✗|OAS3
|
||||
|ParameterStyling|✗|OAS3
|
||||
|Callbacks|✗|OAS3
|
||||
|LinkObjects|✗|OAS3
|
||||
|
||||
### Parameter Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|Path|✓|OAS2,OAS3
|
||||
|Query|✓|OAS2,OAS3
|
||||
|Header|✓|OAS2,OAS3
|
||||
|Body|✓|OAS2
|
||||
|FormUnencoded|✓|OAS2
|
||||
|FormMultipart|✗|OAS2
|
||||
|Cookie|✗|OAS3
|
||||
|
||||
### Schema Support Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|Simple|✓|OAS2,OAS3
|
||||
|Composite|✓|OAS2,OAS3
|
||||
|Polymorphism|✗|OAS2,OAS3
|
||||
|Union|✗|OAS3
|
||||
|allOf|✗|OAS2,OAS3
|
||||
|anyOf|✗|OAS3
|
||||
|oneOf|✗|OAS3
|
||||
|not|✗|OAS3
|
||||
|
||||
### Security Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|BasicAuth|✓|OAS2,OAS3
|
||||
|ApiKey|✓|OAS2,OAS3
|
||||
|OpenIDConnect|✗|OAS3
|
||||
|BearerToken|✓|OAS3
|
||||
|OAuth2_Implicit|✗|OAS2,OAS3
|
||||
|OAuth2_Password|✗|OAS2,OAS3
|
||||
|OAuth2_ClientCredentials|✗|OAS2,OAS3
|
||||
|OAuth2_AuthorizationCode|✗|OAS2,OAS3
|
||||
|SignatureAuth|✗|OAS3
|
||||
|AWSV4Signature|✗|ToolingExtension
|
||||
|
||||
### Wire Format Feature
|
||||
| Name | Supported | Defined By |
|
||||
| ---- | --------- | ---------- |
|
||||
|JSON|✓|OAS2,OAS3
|
||||
|XML|✓|OAS2,OAS3
|
||||
|PROTOBUF|✗|ToolingExtension
|
||||
|Custom|✓|OAS2,OAS3
|
@ -30,7 +30,7 @@ public class CodegenOperation {
|
||||
hasVersionHeaders = false, hasVersionQueryParams = false,
|
||||
isResponseBinary = false, isResponseFile = false, isResponseOptional = false, hasReference = false, defaultReturnType = false,
|
||||
isRestfulIndex, isRestfulShow, isRestfulCreate, isRestfulUpdate, isRestfulDestroy,
|
||||
isRestful, isDeprecated, isCallbackRequest, uniqueItems, hasDefaultResponse = false, hasConstantParams = false,
|
||||
isRestful, isDeprecated, isCallbackRequest, uniqueItems, hasDefaultResponse = false, hasOnlyDefaultResponse = false, hasConstantParams = false,
|
||||
hasErrorResponseObject, // if 4xx, 5xx responses have at least one error object defined
|
||||
hasSingleParam = false; // if the operation has only one parameter;
|
||||
public CodegenProperty returnProperty;
|
||||
@ -215,6 +215,13 @@ public class CodegenOperation {
|
||||
return responses.stream().anyMatch(response -> response.isDefault);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the responses contain only 1 entry and it's default
|
||||
*
|
||||
* @return true if responses contain only 1 entry and it's a default response, false otherwise
|
||||
*/
|
||||
public boolean getHasOnlyDefaultResponse() { return responses.size() == 1 && getHasDefaultResponse(); }
|
||||
|
||||
public boolean getAllResponsesAreErrors() {
|
||||
return responses.stream().allMatch(response -> response.is4xx || response.is5xx);
|
||||
}
|
||||
@ -351,6 +358,7 @@ public class CodegenOperation {
|
||||
sb.append(", isResponseOptional=").append(isResponseOptional);
|
||||
sb.append(", hasReference=").append(hasReference);
|
||||
sb.append(", hasDefaultResponse=").append(hasDefaultResponse);
|
||||
sb.append(", hasOnlyDefaultResponse=").append(hasOnlyDefaultResponse);
|
||||
sb.append(", hasErrorResponseObject=").append(hasErrorResponseObject);
|
||||
sb.append(", hasSingleParam=").append(hasSingleParam);
|
||||
sb.append(", isRestfulIndex=").append(isRestfulIndex);
|
||||
@ -432,6 +440,7 @@ public class CodegenOperation {
|
||||
isResponseOptional == that.isResponseOptional &&
|
||||
hasReference == that.hasReference &&
|
||||
hasDefaultResponse == that.hasDefaultResponse &&
|
||||
hasOnlyDefaultResponse == that.hasOnlyDefaultResponse &&
|
||||
hasErrorResponseObject == that.hasErrorResponseObject &&
|
||||
hasSingleParam == that.hasSingleParam &&
|
||||
isRestfulIndex == that.isRestfulIndex &&
|
||||
@ -496,7 +505,7 @@ public class CodegenOperation {
|
||||
return Objects.hash(responseHeaders, hasAuthMethods, hasConsumes, hasProduces, hasParams, hasOptionalParams,
|
||||
hasRequiredParams, returnTypeIsPrimitive, returnSimpleType, subresourceOperation, isMap,
|
||||
isArray, isMultipart, isVoid, isResponseBinary, isResponseFile, isResponseOptional, hasReference,
|
||||
hasDefaultResponse, isRestfulIndex, isRestfulShow, isRestfulCreate, isRestfulUpdate, isRestfulDestroy,
|
||||
hasDefaultResponse, hasOnlyDefaultResponse, isRestfulIndex, isRestfulShow, isRestfulCreate, isRestfulUpdate, isRestfulDestroy,
|
||||
isRestful, isDeprecated, isCallbackRequest, uniqueItems, path, operationId, returnType, httpMethod,
|
||||
returnBaseType, returnContainer, summary, unescapedNotes, notes, baseName, defaultResponse,
|
||||
discriminator, consumes, produces, prioritizedContentTypes, servers, bodyParam, allParams, bodyParams,
|
||||
|
@ -0,0 +1,459 @@
|
||||
/*
|
||||
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
* Copyright 2018 SmartBear Software
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.openapitools.codegen.languages;
|
||||
|
||||
import io.swagger.v3.oas.models.Operation;
|
||||
import io.swagger.v3.oas.models.media.Schema;
|
||||
import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||
import io.swagger.v3.oas.models.servers.Server;
|
||||
import lombok.Getter;
|
||||
import org.openapitools.codegen.*;
|
||||
import org.openapitools.codegen.meta.features.*;
|
||||
import org.openapitools.codegen.model.ModelMap;
|
||||
import org.openapitools.codegen.model.OperationMap;
|
||||
import org.openapitools.codegen.model.OperationsMap;
|
||||
import org.openapitools.codegen.utils.ModelUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ScalaHttp4sClientCodegen extends AbstractScalaCodegen implements CodegenConfig {
|
||||
private final Logger LOGGER = LoggerFactory.getLogger(ScalaHttp4sClientCodegen.class);
|
||||
|
||||
protected String packageName = "org.openapitools.client";
|
||||
protected String groupId = "org.openapitools";
|
||||
protected String artifactId = "scala-http4s-client";
|
||||
protected String artifactVersion = "1.0.0";
|
||||
protected boolean registerNonStandardStatusCodes = true;
|
||||
protected boolean removeOAuthSecurities = true;
|
||||
@Getter
|
||||
protected boolean excludeSbt = false;
|
||||
@Getter
|
||||
protected boolean excludeApi = false;
|
||||
protected static final String EXCLUDE_SBT = "excludeSbt";
|
||||
protected static final String EXCLUDE_API = "excludeApi";
|
||||
protected String sourceFolder = "src" + File.separator + "main" + File.separator + "scala";
|
||||
|
||||
@Override
|
||||
public CodegenType getTag() {
|
||||
return CodegenType.CLIENT;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "scala-http4s";
|
||||
}
|
||||
|
||||
public String getHelp() {
|
||||
return "Generates a scala-http4s client.";
|
||||
}
|
||||
|
||||
public ScalaHttp4sClientCodegen() {
|
||||
super();
|
||||
|
||||
modifyFeatureSet(features -> features
|
||||
.wireFormatFeatures(EnumSet.of(WireFormatFeature.JSON, WireFormatFeature.XML, WireFormatFeature.Custom))
|
||||
.securityFeatures(EnumSet.of(
|
||||
SecurityFeature.BasicAuth,
|
||||
SecurityFeature.ApiKey,
|
||||
SecurityFeature.BearerToken
|
||||
))
|
||||
.excludeGlobalFeatures(
|
||||
GlobalFeature.XMLStructureDefinitions,
|
||||
GlobalFeature.Callbacks,
|
||||
GlobalFeature.LinkObjects,
|
||||
GlobalFeature.ParameterStyling
|
||||
)
|
||||
.excludeSchemaSupportFeatures(
|
||||
SchemaSupportFeature.Polymorphism,
|
||||
SchemaSupportFeature.not
|
||||
)
|
||||
.excludeParameterFeatures(
|
||||
ParameterFeature.Cookie,
|
||||
ParameterFeature.FormMultipart
|
||||
)
|
||||
);
|
||||
|
||||
useOneOfInterfaces = true;
|
||||
supportsMultipleInheritance = true;
|
||||
supportsInheritance = true;
|
||||
supportsMixins = true;
|
||||
addOneOfInterfaceImports = true;
|
||||
|
||||
embeddedTemplateDir = templateDir = "scala-http4s";
|
||||
|
||||
modelTemplateFiles.put("model.mustache", ".scala");
|
||||
apiTemplateFiles.put("api.mustache", ".scala");
|
||||
|
||||
setApiPackage(packageName + ".apis");
|
||||
setModelPackage(packageName + ".models");
|
||||
|
||||
setReservedWordsLowerCase(
|
||||
Arrays.asList(
|
||||
// Scala
|
||||
"abstract", "case", "catch", "class", "def",
|
||||
"do", "else", "extends", "false", "final",
|
||||
"finally", "for", "forSome", "if", "implicit",
|
||||
"import", "lazy", "match", "new", "null",
|
||||
"object", "override", "package", "private", "protected",
|
||||
"return", "sealed", "super", "this", "throw",
|
||||
"trait", "try", "true", "type", "val",
|
||||
"var", "while", "with", "yield",
|
||||
// Scala-interop languages keywords
|
||||
"abstract", "continue", "switch", "assert",
|
||||
"default", "synchronized", "goto",
|
||||
"break", "double", "implements", "byte",
|
||||
"public", "throws", "enum", "instanceof", "transient",
|
||||
"int", "short", "char", "interface", "static",
|
||||
"void", "finally", "long", "strictfp", "volatile", "const", "float",
|
||||
"native")
|
||||
);
|
||||
|
||||
defaultIncludes = new HashSet<>(
|
||||
Arrays.asList("double",
|
||||
"Int",
|
||||
"Long",
|
||||
"Float",
|
||||
"Double",
|
||||
"char",
|
||||
"float",
|
||||
"String",
|
||||
"boolean",
|
||||
"Boolean",
|
||||
"Double",
|
||||
"Integer",
|
||||
"Long",
|
||||
"Float",
|
||||
"List",
|
||||
"Set",
|
||||
"Map")
|
||||
);
|
||||
|
||||
languageSpecificPrimitives = new HashSet<>(
|
||||
Arrays.asList(
|
||||
"String",
|
||||
"Boolean",
|
||||
"Double",
|
||||
"Int",
|
||||
"Integer",
|
||||
"Long",
|
||||
"Float",
|
||||
"Any",
|
||||
"AnyVal",
|
||||
"AnyRef",
|
||||
"Object",
|
||||
"BigDecimal"
|
||||
)
|
||||
);
|
||||
|
||||
typeMapping = new HashMap<>();
|
||||
typeMapping.put("string", "String");
|
||||
typeMapping.put("boolean", "Boolean");
|
||||
typeMapping.put("integer", "Int");
|
||||
typeMapping.put("long", "Long");
|
||||
typeMapping.put("float", "Float");
|
||||
typeMapping.put("double", "Double");
|
||||
typeMapping.put("number", "BigDecimal");
|
||||
typeMapping.put("decimal", "BigDecimal");
|
||||
typeMapping.put("date", "LocalDate");
|
||||
typeMapping.put("date-time", "Instant");
|
||||
typeMapping.put("offset-date-time", "OffsetDateTime");
|
||||
typeMapping.put("file", "File");
|
||||
typeMapping.put("array", "Seq");
|
||||
typeMapping.put("list", "List");
|
||||
typeMapping.put("map", "Map");
|
||||
typeMapping.put("object", "Json");
|
||||
typeMapping.put("binary", "File");
|
||||
typeMapping.put("Date", "LocalDate");
|
||||
typeMapping.put("DateTime", "Instant");
|
||||
typeMapping.put("OffsetDateTime", "OffsetDateTime");
|
||||
typeMapping.put("uuid", "UUID");
|
||||
|
||||
additionalProperties.put(CodegenConstants.GROUP_ID, groupId);
|
||||
additionalProperties.put(CodegenConstants.ARTIFACT_ID, artifactId);
|
||||
additionalProperties.put(CodegenConstants.ARTIFACT_VERSION, artifactVersion);
|
||||
additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage());
|
||||
additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage());
|
||||
additionalProperties.put("infoUrl", "http://org.openapitools");
|
||||
additionalProperties.put("infoEmail", "team@openapitools.org");
|
||||
additionalProperties.put("licenseInfo", "Apache 2.0");
|
||||
additionalProperties.put("licenseUrl", "http://apache.org/licenses/LICENSE-2.0.html");
|
||||
|
||||
importMapping = new HashMap<>();
|
||||
importMapping.put("UUID", "java.util.UUID");
|
||||
importMapping.put("URI", "java.net.URI");
|
||||
importMapping.put("File", "java.io.File");
|
||||
importMapping.put("Json", "io.circe.Json");
|
||||
importMapping.put("Date", "java.util.Date");
|
||||
importMapping.put("Timestamp", "java.sql.Timestamp");
|
||||
importMapping.put("Map", "scala.collection.immutable.Map");
|
||||
importMapping.put("HashMap", "scala.collection.immutable.HashMap");
|
||||
importMapping.put("Seq", "scala.collection.immutable.Seq");
|
||||
importMapping.put("ArrayBuffer", "scala.collection.mutable.ArrayBuffer");
|
||||
importMapping.put("Instant", "java.time.Instant");
|
||||
importMapping.put("LocalDateTime", "java.time.LocalDateTime");
|
||||
importMapping.put("LocalDate", "java.time.LocalDate");
|
||||
importMapping.put("LocalTime", "java.time.LocalTime");
|
||||
importMapping.put("ZonedDateTime", "java.time.ZonedDateTime");
|
||||
importMapping.put("OffsetDateTime", "java.time.OffsetDateTime");
|
||||
|
||||
instantiationTypes.put("array", "Seq");
|
||||
instantiationTypes.put("seq", "Seq");
|
||||
instantiationTypes.put("list", "List");
|
||||
instantiationTypes.put("map", "Map");
|
||||
|
||||
//this option allows inline enums to be separate own models
|
||||
inlineSchemaOption.put("RESOLVE_INLINE_ENUMS", "true");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processOpts() {
|
||||
super.processOpts();
|
||||
|
||||
if (DateLibraries.java8.name().equals(dateLibrary)) {
|
||||
typeMapping.put("date", "LocalDate");
|
||||
typeMapping.put("date-time", "Instant");
|
||||
typeMapping.put("offset-date-time", "OffsetDateTime");
|
||||
typeMapping.put("Date", "LocalDate");
|
||||
typeMapping.put("DateTime", "Instant");
|
||||
typeMapping.put("OffsetDateTime", "OffsetDateTime");
|
||||
this.importMapping.put("LocalDate", "java.time.LocalDate");
|
||||
this.importMapping.put("Instant", "java.time.Instant");
|
||||
this.importMapping.put("OffsetDateTime", "java.time.OffsetDateTime");
|
||||
additionalProperties.put("java8", "true");
|
||||
} else {
|
||||
String error = "DateLibrary " + dateLibrary + " is not supported. Please use java8";
|
||||
LOGGER.error(error);
|
||||
throw new RuntimeException(error);
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) {
|
||||
packageName = (String) additionalProperties.get(CodegenConstants.PACKAGE_NAME);
|
||||
setApiPackage(packageName + ".apis");
|
||||
setModelPackage(packageName + ".models");
|
||||
additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage());
|
||||
additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage());
|
||||
} else {
|
||||
additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
|
||||
}
|
||||
if (additionalProperties.containsKey(CodegenConstants.SOURCE_FOLDER)) {
|
||||
//you can set your own source folder, i.e. target/scala-3.3.3/src_managed/main
|
||||
this.sourceFolder = (String) additionalProperties.get(CodegenConstants.SOURCE_FOLDER);
|
||||
}
|
||||
if (additionalProperties.containsKey(CodegenConstants.ARTIFACT_ID)) {
|
||||
this.artifactId = (String) additionalProperties.get(CodegenConstants.ARTIFACT_ID);
|
||||
}
|
||||
|
||||
additionalProperties.put("fnEnumEntry", new EnumEntryLambda());
|
||||
|
||||
supportingFiles.add(new SupportingFile("failedRequest.mustache", modelFileFolderRelative(), "_FailedRequest.scala"));
|
||||
supportingFiles.add(new SupportingFile("authModel.mustache", modelFileFolderRelative(), "_Authorization.scala"));
|
||||
supportingFiles.add(new SupportingFile("modelsPackage.mustache", modelFileFolderRelative(), "package.scala"));
|
||||
|
||||
if (additionalProperties.containsKey(EXCLUDE_SBT)) {
|
||||
this.excludeSbt = convertPropertyToBoolean(EXCLUDE_SBT);
|
||||
}
|
||||
if (!excludeSbt) {
|
||||
supportingFiles.add(new SupportingFile("build.sbt.mustache", "", "build.sbt"));
|
||||
supportingFiles.add(new SupportingFile("project/build.properties.mustache", "project", "build.properties"));
|
||||
} else {
|
||||
supportingFiles.remove(new SupportingFile("build.sbt.mustache", "", "build.sbt"));
|
||||
supportingFiles.remove(new SupportingFile("project/build.properties.mustache", "project", "build.properties"));
|
||||
}
|
||||
if (additionalProperties.containsKey(EXCLUDE_API)) {
|
||||
this.excludeApi = convertPropertyToBoolean(EXCLUDE_API);
|
||||
}
|
||||
if (!excludeApi) {
|
||||
supportingFiles.add(new SupportingFile("baseClient.mustache", apisFileFolderRelative(), "BaseClient.scala"));
|
||||
supportingFiles.add(new SupportingFile("jsonSupports.mustache", apisFileFolderRelative(), "JsonSupports.scala"));
|
||||
apiTemplateFiles.put("api.mustache", ".scala");
|
||||
} else {
|
||||
supportingFiles.remove(new SupportingFile("baseClient.mustache", apisFileFolderRelative(), "BaseClient.scala"));
|
||||
supportingFiles.remove(new SupportingFile("jsonSupports.mustache", apisFileFolderRelative(), "JsonSupports.scala"));
|
||||
apiTemplateFiles.remove("api.mustache");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String apiFileFolder() {
|
||||
return outputFolder + File.separator + apiFileFolderRelative();
|
||||
}
|
||||
|
||||
private String apiFileFolderRelative() {
|
||||
return sourceFolder + File.separator + apiPackage().replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String modelFileFolder() {
|
||||
return outputFolder + File.separator + modelFileFolderRelative();
|
||||
}
|
||||
|
||||
private String modelFileFolderRelative() {
|
||||
return sourceFolder + File.separator + modelPackage().replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
private String apisFileFolderRelative() {
|
||||
return sourceFolder + File.separator + apiPackage().replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapeReservedWord(String name) {
|
||||
if (this.reservedWordsMappings().containsKey(name)) {
|
||||
return this.reservedWordsMappings().get(name);
|
||||
}
|
||||
return "`" + name + "`";
|
||||
}
|
||||
|
||||
@Override
|
||||
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
|
||||
if (registerNonStandardStatusCodes) {
|
||||
try {
|
||||
OperationMap opsMap = objs.getOperations();
|
||||
HashSet<Integer> unknownCodes = new HashSet<>();
|
||||
for (CodegenOperation operation : opsMap.getOperation()) {
|
||||
for (CodegenResponse response : operation.responses) {
|
||||
if ("default".equals(response.code)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
int code = Integer.parseInt(response.code);
|
||||
if (code >= 600) {
|
||||
unknownCodes.add(code);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.error("Status code is not an integer : response.code", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!unknownCodes.isEmpty()) {
|
||||
additionalProperties.put("unknownStatusCodes", unknownCodes);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Unable to find operations List", e);
|
||||
}
|
||||
}
|
||||
return super.postProcessOperationsWithModels(objs, allModels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CodegenSecurity> fromSecurity(Map<String, SecurityScheme> schemes) {
|
||||
final List<CodegenSecurity> codegenSecurities = super.fromSecurity(schemes);
|
||||
if (!removeOAuthSecurities) {
|
||||
return codegenSecurities;
|
||||
}
|
||||
|
||||
// Remove OAuth securities
|
||||
codegenSecurities.removeIf(security -> security.isOAuth);
|
||||
if (codegenSecurities.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return codegenSecurities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toParamName(String name) {
|
||||
// obtain the name from parameterNameMapping directly if provided
|
||||
if (parameterNameMapping.containsKey(name)) {
|
||||
return parameterNameMapping.get(name);
|
||||
}
|
||||
|
||||
return formatIdentifier(name, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodePath(String input) {
|
||||
String path = super.encodePath(input);
|
||||
|
||||
// The parameter names in the URI must be converted to the same case as
|
||||
// the method parameter.
|
||||
StringBuilder buf = new StringBuilder(path.length());
|
||||
Matcher matcher = Pattern.compile("[{](.*?)[}]").matcher(path);
|
||||
while (matcher.find()) {
|
||||
matcher.appendReplacement(buf, "\\${" + toParamName(matcher.group(0)) + "}");
|
||||
}
|
||||
matcher.appendTail(buf);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodegenOperation fromOperation(String path,
|
||||
String httpMethod,
|
||||
Operation operation,
|
||||
List<Server> servers) {
|
||||
CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers);
|
||||
op.path = encodePath(path);
|
||||
return op;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toEnumName(CodegenProperty property) {
|
||||
return formatIdentifier(property.baseName, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toDefaultValue(Schema p) {
|
||||
if (p.getRequired() != null && p.getRequired().contains(p.getName())) {
|
||||
return "None";
|
||||
}
|
||||
|
||||
if (ModelUtils.isBooleanSchema(p)) {
|
||||
return null;
|
||||
} else if (ModelUtils.isDateSchema(p)) {
|
||||
return null;
|
||||
} else if (ModelUtils.isDateTimeSchema(p)) {
|
||||
return null;
|
||||
} else if (ModelUtils.isNumberSchema(p)) {
|
||||
return null;
|
||||
} else if (ModelUtils.isIntegerSchema(p)) {
|
||||
return null;
|
||||
} else if (ModelUtils.isMapSchema(p)) {
|
||||
String inner = getSchemaType(ModelUtils.getAdditionalProperties(p));
|
||||
return "Map[String, " + inner + "].empty ";
|
||||
} else if (ModelUtils.isArraySchema(p)) {
|
||||
String inner = getSchemaType(ModelUtils.getSchemaItems(p));
|
||||
if (ModelUtils.isSet(p)) {
|
||||
return "Set[" + inner + "].empty ";
|
||||
}
|
||||
return "Seq[" + inner + "].empty ";
|
||||
} else if (ModelUtils.isStringSchema(p)) {
|
||||
return null;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class EnumEntryLambda extends CustomLambda {
|
||||
@Override
|
||||
public String formatFragment(String fragment) {
|
||||
return formatIdentifier(fragment, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapeQuotationMark(String input) {
|
||||
// remove " to avoid code injection
|
||||
return input.replace("\"", "");
|
||||
}
|
||||
|
||||
}
|
@ -125,6 +125,7 @@ org.openapitools.codegen.languages.ScalaPekkoClientCodegen
|
||||
org.openapitools.codegen.languages.ScalaAkkaHttpServerCodegen
|
||||
org.openapitools.codegen.languages.ScalaFinchServerCodegen
|
||||
org.openapitools.codegen.languages.ScalaGatlingCodegen
|
||||
org.openapitools.codegen.languages.ScalaHttp4sClientCodegen
|
||||
org.openapitools.codegen.languages.ScalaHttp4sServerCodegen
|
||||
org.openapitools.codegen.languages.ScalaLagomServerCodegen
|
||||
org.openapitools.codegen.languages.ScalaPlayFrameworkServerCodegen
|
||||
|
60
modules/openapi-generator/src/main/resources/scala-http4s/api.mustache
vendored
Normal file
60
modules/openapi-generator/src/main/resources/scala-http4s/api.mustache
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
{{>licenseInfo}}
|
||||
package {{apiPackage}}
|
||||
|
||||
import cats.effect.Concurrent
|
||||
import io.circe.Encoder
|
||||
import org.http4s.Uri
|
||||
import org.http4s.client.Client as Http4sClient
|
||||
{{#imports}}
|
||||
import {{import}}
|
||||
{{/imports}}
|
||||
import {{modelPackage}}.*
|
||||
|
||||
{{#operations}}
|
||||
trait {{classname}}Endpoints[F[*]] {
|
||||
|
||||
{{#operation}}
|
||||
def {{operationId}}({{>methodParameters}}): F[{{>operationReturnType}}]
|
||||
{{/operation}}
|
||||
|
||||
}
|
||||
{{/operations}}
|
||||
|
||||
{{#operations}}
|
||||
class {{classname}}EndpointsImpl[F[*]: Concurrent](
|
||||
override val baseUrl: Uri,
|
||||
defaultHeaders: Seq[(String, String)] = Nil,
|
||||
httpClient: Http4sClient[F]
|
||||
) extends BaseClient[F](baseUrl, defaultHeaders, httpClient) with {{classname}}Endpoints[F] {
|
||||
|
||||
import JsonSupports.*
|
||||
import io.circe.syntax.EncoderOps
|
||||
import cats.implicits.toFlatMapOps
|
||||
|
||||
{{#operation}}
|
||||
override def {{operationId}}({{>methodParameters}}): F[{{>operationReturnType}}] = {
|
||||
val requestHeaders = {{>headerParamCreation}}{{#hasFormParams}}
|
||||
val formParameters = Some(({{#formParams}}
|
||||
{{>paramsCreation}}{{/formParams}}
|
||||
).toSeq.flatten){{/hasFormParams}}{{#hasQueryParams}}
|
||||
val queryParameters = ({{#queryParams}}
|
||||
{{>paramsCreation}}{{/queryParams}}
|
||||
).toSeq.flatten{{/hasQueryParams}}
|
||||
|
||||
_executeRequest[{{>bodyParamType}}, {{>operationReturnType}}](
|
||||
method = "{{httpMethod.toUpperCase}}",
|
||||
path = s"{{{path}}}",
|
||||
body = {{#bodyParam}}{{#required}}Some({{paramName}}){{/required}}{{^required}}{{paramName}}{{/required}}{{/bodyParam}}{{^bodyParam}}None{{/bodyParam}},
|
||||
formParameters = {{^hasFormParams}}None,{{/hasFormParams}}{{#hasFormParams}}formParameters,{{/hasFormParams}}
|
||||
queryParameters = {{^hasQueryParams}}Nil,{{/hasQueryParams}}{{#hasQueryParams}}queryParameters,{{/hasQueryParams}}
|
||||
requestHeaders = requestHeaders,
|
||||
auth = {{#authMethods}}Some(auth){{/authMethods}}{{^authMethods}}None{{/authMethods}}) {
|
||||
{{>responseState}}
|
||||
}
|
||||
}
|
||||
|
||||
{{/operation}}
|
||||
}
|
||||
{{/operations}}
|
||||
|
||||
|
10
modules/openapi-generator/src/main/resources/scala-http4s/authModel.mustache
vendored
Normal file
10
modules/openapi-generator/src/main/resources/scala-http4s/authModel.mustache
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
{{>licenseInfo}}
|
||||
package {{modelPackage}}
|
||||
|
||||
sealed trait _Authorization
|
||||
|
||||
object _Authorization {
|
||||
final case class Basic(username: String, password: Option[String] = None) extends _Authorization
|
||||
final case class ApiKey(name: String, value: String) extends _Authorization
|
||||
final case class Bearer(token: String) extends _Authorization
|
||||
}
|
80
modules/openapi-generator/src/main/resources/scala-http4s/baseClient.mustache
vendored
Normal file
80
modules/openapi-generator/src/main/resources/scala-http4s/baseClient.mustache
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
{{>licenseInfo}}
|
||||
package {{apiPackage}}
|
||||
|
||||
import cats.effect.Concurrent
|
||||
import io.circe.Encoder
|
||||
import org.http4s.{Header, Headers, Method, Request, Response, Uri, UrlForm}
|
||||
import org.http4s.client.Client as Http4sClient
|
||||
import org.http4s.QueryParamEncoder.*
|
||||
import org.typelevel.ci.CIString
|
||||
import java.util.Base64
|
||||
import java.nio.charset.StandardCharsets
|
||||
import {{modelPackage}}.*
|
||||
|
||||
abstract class BaseClient[F[*]: Concurrent](
|
||||
val baseUrl: Uri,
|
||||
defaultHeaders: Seq[(String, String)] = Nil,
|
||||
httpClient: Http4sClient[F]
|
||||
) {
|
||||
|
||||
val ApiVersion: String = "{{artifactVersion}}"
|
||||
|
||||
private lazy val defaultApiHeaders = Seq(
|
||||
("X-Apidoc-Version", ApiVersion)
|
||||
)
|
||||
|
||||
protected def modifyRequest(request: Request[F]): Request[F] = request
|
||||
|
||||
def _executeRequest[T, U](
|
||||
method: String,
|
||||
path: String,
|
||||
body: Option[T] = None,
|
||||
formParameters: Option[Seq[(String, Any)]] = None,
|
||||
queryParameters: Seq[(String, Any)] = Nil,
|
||||
requestHeaders: Seq[(String, String)] = Nil,
|
||||
auth: Option[_Authorization] = None
|
||||
)(handler: Response[F] => F[U])(implicit encoder: Encoder[T]): F[U] = {
|
||||
|
||||
val m = Method.fromString(method) match {
|
||||
case Right(m) => m
|
||||
case Left(e) => sys.error(e.toString)
|
||||
}
|
||||
|
||||
val headers = Headers(
|
||||
(
|
||||
defaultApiHeaders ++
|
||||
defaultHeaders ++
|
||||
requestHeaders
|
||||
).groupBy(_._1).map { case (k, l) => Header.Raw(CIString(k), l.last._2) }.toList
|
||||
)
|
||||
|
||||
val queryMap = queryParameters.groupBy(_._1).map { case (k, v) => k -> v.map(_._2.toString) }
|
||||
val uri = Uri.unsafeFromString(s"$baseUrl$path").setQueryParams(queryMap)
|
||||
|
||||
val request = Request[F](method = m, uri = uri, headers = headers)
|
||||
|
||||
val reqAndMaybeAuth = auth.fold(request) {
|
||||
case _Authorization.Basic(username, passwordOpt) =>
|
||||
val userpass = s"$username:${passwordOpt.getOrElse("")}"
|
||||
val token = Base64.getEncoder.encodeToString(
|
||||
userpass.getBytes(StandardCharsets.ISO_8859_1)
|
||||
)
|
||||
request.putHeaders(Header.Raw(CIString("Authorization"), s"Basic $token"))
|
||||
case _Authorization.Bearer(token) =>
|
||||
request.putHeaders(Header.Raw(CIString("Authorization"), s"Bearer $token"))
|
||||
case _Authorization.ApiKey(name, value) =>
|
||||
request.putHeaders(Header.Raw(CIString(name), value))
|
||||
}
|
||||
val formBody = formParameters.map { x =>
|
||||
UrlForm(x.groupBy(_._1).map{case (k, v) => (k, v.mkString(","))}.toSeq*)
|
||||
}
|
||||
|
||||
import JsonSupports.*
|
||||
val reqAndMaybeAuthAndBody =
|
||||
if (formBody.nonEmpty) formBody.fold(reqAndMaybeAuth)(reqAndMaybeAuth.withEntity)
|
||||
else body.fold(reqAndMaybeAuth)(reqAndMaybeAuth.withEntity)
|
||||
|
||||
httpClient.run(modifyRequest(reqAndMaybeAuthAndBody)).use(handler)
|
||||
}
|
||||
|
||||
}
|
1
modules/openapi-generator/src/main/resources/scala-http4s/bodyParamType.mustache
vendored
Normal file
1
modules/openapi-generator/src/main/resources/scala-http4s/bodyParamType.mustache
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{#hasBodyParam}}{{#allParams}}{{#isBodyParam}}{{dataType}}{{/isBodyParam}}{{/allParams}}{{/hasBodyParam}}{{^hasBodyParam}}Unit{{/hasBodyParam}}
|
34
modules/openapi-generator/src/main/resources/scala-http4s/build.sbt.mustache
vendored
Normal file
34
modules/openapi-generator/src/main/resources/scala-http4s/build.sbt.mustache
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
scalaVersion := "3.3.3"
|
||||
|
||||
version := "{{artifactVersion}}"
|
||||
name := "{{artifactId}}"
|
||||
organization := "{{groupId}}"
|
||||
|
||||
val CirceVersion = "0.14.9"
|
||||
val Http4sVersion = "0.23.26"
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
"org.http4s" %% "http4s-ember-client" % Http4sVersion,
|
||||
"org.http4s" %% "http4s-circe" % Http4sVersion,
|
||||
"org.http4s" %% "http4s-dsl" % Http4sVersion,
|
||||
"org.http4s" %% "http4s-client" % Http4sVersion,
|
||||
"io.circe" %% "circe-core" % CirceVersion,
|
||||
"io.circe" %% "circe-generic" % CirceVersion,
|
||||
"io.circe" %% "circe-parser" % CirceVersion,
|
||||
"org.scalatest" %% "scalatest" % "3.2.19" % "test"
|
||||
)
|
||||
|
||||
scalacOptions := Seq(
|
||||
"-encoding",
|
||||
"UTF-8",
|
||||
"-deprecation",
|
||||
"-unchecked",
|
||||
"-feature",
|
||||
"-language:existentials,experimental.macros,higherKinds,implicitConversions,postfixOps,adhocExtensions",
|
||||
"-Yretain-trees",
|
||||
"-Xmax-inlines:100",
|
||||
"-Ykind-projector:underscores",
|
||||
"-source:future"
|
||||
)
|
||||
|
||||
Compile / publishArtifact := false
|
1
modules/openapi-generator/src/main/resources/scala-http4s/errorResponsePart.mustache
vendored
Normal file
1
modules/openapi-generator/src/main/resources/scala-http4s/errorResponsePart.mustache
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{#dataType}}case r if r.status.code == {{code}} => parseJson[F, {{dataType}}]("{{dataType}}", r).flatMap(res => Concurrent[F].raiseError(_FailedRequest(r.status.code, res.asJson.noSpaces))){{/dataType}}{{^dataType}}case r if r.status.code == {{code}} => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason)){{/dataType}}
|
33
modules/openapi-generator/src/main/resources/scala-http4s/failedRequest.mustache
vendored
Normal file
33
modules/openapi-generator/src/main/resources/scala-http4s/failedRequest.mustache
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
{{>licenseInfo}}
|
||||
package {{modelPackage}}
|
||||
|
||||
import io.circe.*
|
||||
import io.circe.Decoder.*
|
||||
import io.circe.Encoder.*
|
||||
import io.circe.syntax.*
|
||||
|
||||
case class _FailedRequest(code: Int, message: String) extends Exception(s"Server return status code: $code; message: $message")
|
||||
|
||||
object _FailedRequest {
|
||||
|
||||
given encoderFailedRequest: Encoder[_FailedRequest] = Encoder.instance { t =>
|
||||
Json.fromFields{
|
||||
Seq(
|
||||
"code" -> t.code.asJson,
|
||||
"message" -> t.message.asJson
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
given decodeFailedRequest: Decoder[_FailedRequest] = Decoder.instance { c =>
|
||||
for {
|
||||
code <- c.downField("code").as[Int]
|
||||
message <- c.downField("message").as[String]
|
||||
} yield _FailedRequest(
|
||||
code = code,
|
||||
message = message
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
4
modules/openapi-generator/src/main/resources/scala-http4s/headerParamCreation.mustache
vendored
Normal file
4
modules/openapi-generator/src/main/resources/scala-http4s/headerParamCreation.mustache
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
Seq(
|
||||
Some("Content-Type" -> {{#consumes.0}}"{{{mediaType}}}"{{/consumes.0}}{{^consumes}}"application/json"{{/consumes}}){{#hasHeaderParams}},
|
||||
{{#headerParams}}{{#required}}Some("{{baseName}}" -> {{{paramName}}}){{/required}}{{^required}}{{{paramName}}}.map(x => "{{baseName}}" -> x){{/required}}{{^-last}}, {{/-last}}{{/headerParams}}{{/hasHeaderParams}}
|
||||
).flatten
|
29
modules/openapi-generator/src/main/resources/scala-http4s/jsonSupports.mustache
vendored
Normal file
29
modules/openapi-generator/src/main/resources/scala-http4s/jsonSupports.mustache
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
{{>licenseInfo}}
|
||||
package {{apiPackage}}
|
||||
|
||||
import cats.effect.*
|
||||
import cats.implicits.*
|
||||
import io.circe.{Decoder, Encoder}
|
||||
import org.http4s.{EntityDecoder, EntityEncoder, Response}
|
||||
import org.http4s.circe as http4sCirce
|
||||
import {{modelPackage}}.*
|
||||
|
||||
object JsonSupports {
|
||||
|
||||
implicit def circeJsonEncoder[F[*]: Concurrent, A](implicit encoder: Encoder[A]): EntityEncoder[F, A] =
|
||||
http4sCirce.jsonEncoderOf[F, A]
|
||||
implicit def circeJsonDecoder[F[*]: Concurrent, A](implicit decoder: Decoder[A]): EntityDecoder[F, A] =
|
||||
http4sCirce.jsonOf[F, A]
|
||||
|
||||
def parseJson[F[*]: Concurrent, T](
|
||||
className: String,
|
||||
r: Response[F]
|
||||
)(implicit decoder: Decoder[T]): F[T] = r.attemptAs[T].value.flatMap {
|
||||
case Right(value) => Concurrent[F].pure(value)
|
||||
case Left(error) => Concurrent[F].raiseError(
|
||||
_FailedRequest(r.status.code, s"Invalid json for class[$className]: error $error")
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
10
modules/openapi-generator/src/main/resources/scala-http4s/licenseInfo.mustache
vendored
Normal file
10
modules/openapi-generator/src/main/resources/scala-http4s/licenseInfo.mustache
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
/** {{{appName}}}
|
||||
* {{{appDescription}}}
|
||||
*
|
||||
* {{#version}}The version of the OpenAPI document: {{{.}}}{{/version}}
|
||||
* {{#infoEmail}}Contact: {{{.}}}{{/infoEmail}}
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
1
modules/openapi-generator/src/main/resources/scala-http4s/methodParameters.mustache
vendored
Normal file
1
modules/openapi-generator/src/main/resources/scala-http4s/methodParameters.mustache
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{#allParams}}{{paramName}}: {{#required}}{{dataType}}{{/required}}{{^required}}Option[{{dataType}}]{{/required}}{{^defaultValue}}{{^required}} = None{{/required}}{{/defaultValue}}{{^-last}}, {{/-last}}{{/allParams}}{{#authMethods.0}}{{#isApiKey}})(implicit auth: _Authorization.ApiKey{{/isApiKey}}{{#isBasic}}{{#isBasicBasic}})(implicit auth: _Authorization.Basic{{/isBasicBasic}}{{#isBasicBearer}})(implicit auth: _Authorization.Bearer{{/isBasicBearer}}{{/isBasic}}{{/authMethods.0}}
|
70
modules/openapi-generator/src/main/resources/scala-http4s/model.mustache
vendored
Normal file
70
modules/openapi-generator/src/main/resources/scala-http4s/model.mustache
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
{{>licenseInfo}}
|
||||
package {{modelPackage}}
|
||||
|
||||
import io.circe.*
|
||||
import io.circe.syntax.*
|
||||
import io.circe.{Decoder, Encoder}
|
||||
|
||||
{{#imports}}
|
||||
import {{import}}
|
||||
{{/imports}}
|
||||
|
||||
{{#models}}
|
||||
{{#model}}
|
||||
/** {{{description}}}
|
||||
{{#vars}}
|
||||
* @param {{name}} {{{description}}}
|
||||
{{/vars}}
|
||||
*/
|
||||
{{#isEnum}}
|
||||
enum {{classname}}(val value: String) {
|
||||
{{#allowableValues}}
|
||||
{{#values}}
|
||||
case {{#fnEnumEntry}}{{.}}{{/fnEnumEntry}} extends {{classname}}("{{.}}")
|
||||
{{/values}}
|
||||
{{/allowableValues}}
|
||||
}
|
||||
|
||||
object {{classname}} {
|
||||
given decoder{{classname}}: Decoder[{{classname}}] =
|
||||
Decoder.decodeString.map(str => {{classname}}.values.find(_.value == str)
|
||||
.getOrElse(throw java.lang.IllegalArgumentException(s"{{classname}} enum case not found: $str"))
|
||||
)
|
||||
|
||||
given encoder{{classname}}: Encoder[{{classname}}] =
|
||||
Encoder.encodeString.contramap[{{classname}}](_.value)
|
||||
}
|
||||
{{/isEnum}}
|
||||
{{^isEnum}}
|
||||
case class {{classname}}(
|
||||
{{#vars}}
|
||||
{{name}}: {{^required}}Option[{{{dataType}}}] = None{{/required}}{{#required}}{{{dataType}}}{{/required}}{{^-last}},{{/-last}}
|
||||
{{/vars}}
|
||||
)
|
||||
|
||||
object {{classname}} {
|
||||
given encoder{{classname}}: Encoder[{{classname}}] = Encoder.instance { t =>
|
||||
Json.fromFields{
|
||||
Seq(
|
||||
{{#vars}}
|
||||
{{#required}}Some("{{baseName}}" -> t.{{name}}.asJson){{/required}}{{^required}}t.{{name}}.map(v => "{{baseName}}" -> v.asJson){{/required}}{{^-last}},{{/-last}}
|
||||
{{/vars}}
|
||||
).flatten
|
||||
}
|
||||
}
|
||||
given decoder{{classname}}: Decoder[{{classname}}] = Decoder.instance { c =>
|
||||
for {
|
||||
{{#vars}}
|
||||
{{name}} <- c.downField("{{baseName}}").as[{{^required}}Option[{{{dataType}}}]{{/required}}{{#required}}{{{dataType}}}{{/required}}]
|
||||
{{/vars}}
|
||||
} yield {{classname}}(
|
||||
{{#vars}}
|
||||
{{name}} = {{name}}{{^-last}},{{/-last}}
|
||||
{{/vars}}
|
||||
)
|
||||
}
|
||||
}
|
||||
{{/isEnum}}
|
||||
{{/model}}
|
||||
{{/models}}
|
||||
|
32
modules/openapi-generator/src/main/resources/scala-http4s/modelsPackage.mustache
vendored
Normal file
32
modules/openapi-generator/src/main/resources/scala-http4s/modelsPackage.mustache
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
{{>licenseInfo}}
|
||||
package {{packageName}}
|
||||
|
||||
import io.circe.{Decoder, Encoder}
|
||||
|
||||
package object models {
|
||||
|
||||
given decodeUUID: Decoder[_root_.java.util.UUID] =
|
||||
Decoder.decodeString.map(str => _root_.java.util.UUID.fromString(str))
|
||||
|
||||
given encodeUUID: Encoder[_root_.java.util.UUID] =
|
||||
Encoder.encodeString.contramap[_root_.java.util.UUID](uuid => uuid.toString)
|
||||
|
||||
given decodeInstant: Decoder[_root_.java.time.Instant] =
|
||||
Decoder.decodeString.map(str => _root_.java.time.OffsetDateTime.parse(str).toInstant)
|
||||
|
||||
given encodeInstant: Encoder[_root_.java.time.Instant] =
|
||||
Encoder.encodeString.contramap[_root_.java.time.Instant](_.toString)
|
||||
|
||||
given decodeLocalDate: Decoder[_root_.java.time.LocalDate] =
|
||||
Decoder.decodeString.map(str => _root_.java.time.LocalDate.parse(str))
|
||||
|
||||
given encodeLocalDate: Encoder[_root_.java.time.LocalDate] =
|
||||
Encoder.encodeString.contramap[_root_.java.time.LocalDate](_.toString)
|
||||
|
||||
given decodeJson: Decoder[io.circe.Json] =
|
||||
Decoder.decodeString.map(str => io.circe.Json.fromString(str))
|
||||
|
||||
given encodeJson: Encoder[io.circe.Json] =
|
||||
Encoder.encodeString.contramap[io.circe.Json](_.toString)
|
||||
|
||||
}
|
1
modules/openapi-generator/src/main/resources/scala-http4s/operationReturnType.mustache
vendored
Normal file
1
modules/openapi-generator/src/main/resources/scala-http4s/operationReturnType.mustache
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{{returnType}}}{{^returnType}}Unit{{/returnType}}
|
1
modules/openapi-generator/src/main/resources/scala-http4s/paramsCreation.mustache
vendored
Normal file
1
modules/openapi-generator/src/main/resources/scala-http4s/paramsCreation.mustache
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{#isContainer}}{{#required}}Some({{paramName}}.map("{{baseName}}" -> _)){{/required}}{{^required}}{{paramName}}.map(x => x.map("{{baseName}}" -> _)){{/required}}{{/isContainer}}{{^isContainer}}{{#required}}Some(Seq("{{baseName}}" -> {{{paramName}}})){{/required}}{{^required}}{{paramName}}.map("{{baseName}}" -> _).map(Seq(_)){{/required}}{{/isContainer}}{{^-last}} ++ {{/-last}}
|
1
modules/openapi-generator/src/main/resources/scala-http4s/project/build.properties.mustache
vendored
Normal file
1
modules/openapi-generator/src/main/resources/scala-http4s/project/build.properties.mustache
vendored
Normal file
@ -0,0 +1 @@
|
||||
sbt.version=1.9.9
|
5
modules/openapi-generator/src/main/resources/scala-http4s/responseState.mustache
vendored
Normal file
5
modules/openapi-generator/src/main/resources/scala-http4s/responseState.mustache
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{{#hasOnlyDefaultResponse}}{{#responses.0}}{{#dataType}}r => parseJson[F, {{>operationReturnType}}]("{{>operationReturnType}}", r){{/dataType}}{{^dataType}}r => Concurrent[F].pure(()){{/dataType}}{{/responses.0}}{{/hasOnlyDefaultResponse}}{{^hasOnlyDefaultResponse}}{{#responses}}{{#is2xx}}
|
||||
{{>successResponsePart}}{{/is2xx}}{{^is2xx}}{{#is3xx}}
|
||||
{{>successResponsePart}}{{/is3xx}}{{^is3xx}}{{^isDefault}}
|
||||
{{>errorResponsePart}}{{/isDefault}}{{#isDefault}}
|
||||
{{#dataType}}case r => parseJson[F, {{dataType}}]("{{dataType}}", r).flatMap(res => Concurrent[F].raiseError(_FailedRequest(r.status.code, res.asJson.noSpaces))){{/dataType}}{{^dataType}}case r => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason)){{/dataType}}{{/isDefault}}{{/is3xx}}{{/is2xx}}{{/responses}}{{/hasOnlyDefaultResponse}}
|
1
modules/openapi-generator/src/main/resources/scala-http4s/successResponsePart.mustache
vendored
Normal file
1
modules/openapi-generator/src/main/resources/scala-http4s/successResponsePart.mustache
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{#dataType}}case r if r.status.code == {{code}} => parseJson[F, {{>operationReturnType}}]("{{>operationReturnType}}", r){{/dataType}}{{^dataType}}case r if r.status.code == {{code}} => Concurrent[F].pure(()){{/dataType}}
|
@ -0,0 +1,54 @@
|
||||
package org.openapitools.codegen.options;
|
||||
|
||||
import org.openapitools.codegen.CodegenConstants;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
public class ScalaHttp4sClientCodegenOptionsProvider implements OptionsProvider {
|
||||
public static final String ARTIFACT_ID_VALUE = "scala-http4s-client";
|
||||
public static final String PACKAGE_NAME_VALUE = "org.openapitools.client";
|
||||
public static final String MODEL_PACKAGE_VALUE = PACKAGE_NAME_VALUE + ".models";
|
||||
public static final String API_PACKAGE_VALUE = PACKAGE_NAME_VALUE + ".apis";
|
||||
public static final String MODEL_PROPERTY_NAMING = "camelCase";
|
||||
public static final String SOURCE_FOLDER_VALUE = "src" + File.separator + "main" + File.separator + "scala";
|
||||
public static final String SORT_PARAMS_VALUE = "false";
|
||||
public static final String SORT_MODEL_PROPERTIES_VALUE = "false";
|
||||
public static final String ENSURE_UNIQUE_PARAMS_VALUE = "true";
|
||||
public static final String ALLOW_UNICODE_IDENTIFIERS_VALUE = "false";
|
||||
public static final String PREPEND_FORM_OR_BODY_PARAMETERS_VALUE = "true";
|
||||
public static final String DATE_LIBRARY = "java8";
|
||||
|
||||
@Override
|
||||
public String getLanguage() {
|
||||
return "scala-http4s";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> createOptions() {
|
||||
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<String, String>();
|
||||
return builder
|
||||
.put(CodegenConstants.ARTIFACT_ID, ARTIFACT_ID_VALUE)
|
||||
.put(CodegenConstants.PACKAGE_NAME, PACKAGE_NAME_VALUE)
|
||||
.put(CodegenConstants.MODEL_PACKAGE, MODEL_PACKAGE_VALUE)
|
||||
.put(CodegenConstants.API_PACKAGE, API_PACKAGE_VALUE)
|
||||
.put(CodegenConstants.MODEL_PROPERTY_NAMING, MODEL_PROPERTY_NAMING)
|
||||
.put(CodegenConstants.SOURCE_FOLDER, SOURCE_FOLDER_VALUE)
|
||||
.put(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, SORT_PARAMS_VALUE)
|
||||
.put(CodegenConstants.SORT_MODEL_PROPERTIES_BY_REQUIRED_FLAG, SORT_MODEL_PROPERTIES_VALUE)
|
||||
.put(CodegenConstants.ENSURE_UNIQUE_PARAMS, ENSURE_UNIQUE_PARAMS_VALUE)
|
||||
.put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE)
|
||||
.put(CodegenConstants.PREPEND_FORM_OR_BODY_PARAMETERS, PREPEND_FORM_OR_BODY_PARAMETERS_VALUE)
|
||||
.put("dateLibrary", DATE_LIBRARY)
|
||||
.put(CodegenConstants.LEGACY_DISCRIMINATOR_BEHAVIOR, "true")
|
||||
.put("excludeSbt", "false")
|
||||
.put("excludeApi", "false")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isServer() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
package org.openapitools.codegen.scala;
|
||||
|
||||
import io.swagger.v3.oas.models.media.DateTimeSchema;
|
||||
import io.swagger.v3.oas.models.media.IntegerSchema;
|
||||
import io.swagger.v3.oas.models.media.Schema;
|
||||
import io.swagger.v3.oas.models.media.StringSchema;
|
||||
import io.swagger.v3.parser.util.SchemaTypeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.openapitools.codegen.*;
|
||||
import org.openapitools.codegen.config.CodegenConfigurator;
|
||||
import org.openapitools.codegen.languages.ScalaHttp4sClientCodegen;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class ScalaHttp4sClientCodegenTest {
|
||||
|
||||
@Test(description = "convert a simple java model")
|
||||
public void simpleModelTest() {
|
||||
ScalaHttp4sClientCodegen codegen = new ScalaHttp4sClientCodegen();
|
||||
final Schema model = new Schema()
|
||||
.description("a sample model")
|
||||
.addProperty("id", new IntegerSchema().format(SchemaTypeUtil.INTEGER64_FORMAT))
|
||||
.addProperty("name", new StringSchema())
|
||||
.addProperty("created_at", new DateTimeSchema())
|
||||
.addRequiredItem("id")
|
||||
.addRequiredItem("name");
|
||||
CodegenModel cm = codegen.fromModel("sample", model);
|
||||
|
||||
assertEquals(cm.name, "sample");
|
||||
assertEquals(cm.classname, "Sample");
|
||||
assertEquals(cm.description, "a sample model");
|
||||
assertEquals(cm.vars.size(), 3);
|
||||
assertEquals(cm.vars.stream().filter(CodegenProperty::getRequired).count(), 2);
|
||||
}
|
||||
|
||||
@Test(description = "happy path test")
|
||||
public void happyPathTest() throws IOException {
|
||||
ScalaHttp4sClientCodegen codegen = new ScalaHttp4sClientCodegen();
|
||||
assertEquals(codegen.getName(), "scala-http4s");
|
||||
assertEquals(codegen.getTag(), CodegenType.CLIENT);
|
||||
|
||||
File output = Files.createTempDirectory("test").toFile();
|
||||
output.deleteOnExit();
|
||||
|
||||
final CodegenConfigurator configurator = new CodegenConfigurator()
|
||||
.setGeneratorName(codegen.getName())
|
||||
.setInputSpec("src/test/resources/3_0/scala-http4s/petstore.yaml")
|
||||
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));
|
||||
|
||||
final ClientOptInput clientOptInput = configurator.toClientOptInput();
|
||||
DefaultGenerator generator = getDefaultGenerator();
|
||||
|
||||
List<File> files = generator.opts(clientOptInput).generate();
|
||||
|
||||
TestUtils.ensureContainsFile(files, output, "build.sbt");
|
||||
TestUtils.ensureContainsFile(files, output, "project/build.properties");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/models/package.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/models/_Authorization.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/models/_FailedRequest.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/models/ApiResponse.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/models/Category.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/models/FindPetsByStatusStatusParameterInner.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/models/Order.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/models/OrderStatus.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/models/Pet.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/models/PetStatus.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/models/Tag.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/models/User.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/apis/BaseClient.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/apis/JsonSupports.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/apis/PetApi.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/apis/StoreApi.scala");
|
||||
TestUtils.ensureContainsFile(files, output, "src/main/scala/org/openapitools/client/apis/UserApi.scala");
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static DefaultGenerator getDefaultGenerator() {
|
||||
DefaultGenerator generator = new DefaultGenerator();
|
||||
|
||||
generator.setGenerateMetadata(false);
|
||||
|
||||
generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true");
|
||||
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false");
|
||||
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false");
|
||||
generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true");
|
||||
generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "true");
|
||||
return generator;
|
||||
}
|
||||
|
||||
@Test(description = "use Instant for date-time")
|
||||
public void dateTimeToInstant() {
|
||||
ScalaHttp4sClientCodegen codegen = new ScalaHttp4sClientCodegen();
|
||||
|
||||
final Schema<?> schema = new Schema<Object>()
|
||||
.description("Schema with date-time");
|
||||
schema.setType("string");
|
||||
schema.setFormat("date-time");
|
||||
String type = codegen.getTypeDeclaration(schema);
|
||||
assertEquals(type, "Instant");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allowExcludeSbtFiles() {
|
||||
ScalaHttp4sClientCodegen codegen = new ScalaHttp4sClientCodegen();
|
||||
assertFalse(codegen.isExcludeSbt());
|
||||
codegen.additionalProperties().put("excludeSbt", "true");
|
||||
assertEquals(codegen.additionalProperties().get("excludeSbt"), "true");
|
||||
codegen.processOpts();
|
||||
assertTrue(codegen.isExcludeSbt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allowExcludeApiFiles() {
|
||||
ScalaHttp4sClientCodegen codegen = new ScalaHttp4sClientCodegen();
|
||||
assertFalse(codegen.isExcludeApi());
|
||||
codegen.additionalProperties().put("excludeApi", "true");
|
||||
assertEquals(codegen.additionalProperties().get("excludeApi"), "true");
|
||||
codegen.processOpts();
|
||||
assertTrue(codegen.isExcludeApi());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertVarNameCamelCase() {
|
||||
ScalaHttp4sClientCodegen codegen = new ScalaHttp4sClientCodegen();
|
||||
assertEquals(CodegenConstants.ENUM_PROPERTY_NAMING_TYPE.camelCase.name(), codegen.getModelPropertyNaming());
|
||||
assertEquals(codegen.toVarName("name"), "name");
|
||||
assertEquals(codegen.toVarName("user-name"), "userName");
|
||||
assertEquals(codegen.toVarName("user_name"), "userName");
|
||||
assertEquals(codegen.toVarName("user|name"), "userName");
|
||||
assertEquals(codegen.toVarName("uSername"), "uSername");
|
||||
assertEquals(codegen.toVarName("USERNAME"), "USERNAME");
|
||||
assertEquals(codegen.toVarName("USER123NAME"), "USER123NAME");
|
||||
assertEquals(codegen.toVarName("1"), "`1`");
|
||||
assertEquals(codegen.toVarName("1a"), "`1a`");
|
||||
assertEquals(codegen.toVarName("1A"), "`1A`");
|
||||
assertEquals(codegen.toVarName("1AAAA"), "`1AAAA`");
|
||||
assertEquals(codegen.toVarName("1AAaa"), "`1aAaa`");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodePath() {
|
||||
ScalaHttp4sClientCodegen codegen = new ScalaHttp4sClientCodegen();
|
||||
assertEquals(codegen.encodePath("{user_name}"), "${userName}");
|
||||
assertEquals(codegen.encodePath("{userName}"), "${userName}");
|
||||
assertEquals(codegen.encodePath("{UserName}"), "${userName}");
|
||||
assertEquals(codegen.encodePath("user_name"), "user_name");
|
||||
assertEquals(codegen.encodePath("before/{UserName}/after"), "before/${userName}/after");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,742 @@
|
||||
openapi: 3.0.0
|
||||
servers:
|
||||
- url: 'https://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:
|
||||
/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
|
||||
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
|
||||
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:
|
||||
'200':
|
||||
description: successful operation
|
||||
'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:
|
||||
- auth_cookie: []
|
||||
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:
|
||||
- auth_cookie: []
|
||||
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:
|
||||
- auth_cookie: []
|
||||
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 `auth_cookie`
|
||||
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:
|
||||
- auth_cookie: []
|
||||
'/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:
|
||||
- auth_cookie: []
|
||||
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:
|
||||
- auth_cookie: []
|
||||
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
|
||||
auth_cookie:
|
||||
type: apiKey
|
||||
name: AUTH_KEY
|
||||
in: cookie
|
||||
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
|
||||
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
|
@ -0,0 +1,23 @@
|
||||
# OpenAPI Generator Ignore
|
||||
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||
|
||||
# Use this file to prevent files from being overwritten by the generator.
|
||||
# The patterns follow closely to .gitignore or .dockerignore.
|
||||
|
||||
# As an example, the C# client generator defines ApiClient.cs.
|
||||
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||
#ApiClient.cs
|
||||
|
||||
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||
#foo/*/qux
|
||||
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||
|
||||
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||
#foo/**/qux
|
||||
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||
|
||||
# You can also negate patterns with an exclamation (!).
|
||||
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||
#docs/*.md
|
||||
# Then explicitly reverse the ignore rule for a single file:
|
||||
#!docs/README.md
|
@ -0,0 +1,19 @@
|
||||
build.sbt
|
||||
project/build.properties
|
||||
src/main/scala/org/openapitools/client/apis/BaseClient.scala
|
||||
src/main/scala/org/openapitools/client/apis/JsonSupports.scala
|
||||
src/main/scala/org/openapitools/client/apis/PetApi.scala
|
||||
src/main/scala/org/openapitools/client/apis/StoreApi.scala
|
||||
src/main/scala/org/openapitools/client/apis/UserApi.scala
|
||||
src/main/scala/org/openapitools/client/models/ApiResponse.scala
|
||||
src/main/scala/org/openapitools/client/models/Category.scala
|
||||
src/main/scala/org/openapitools/client/models/FindPetsByStatusStatusParameterInner.scala
|
||||
src/main/scala/org/openapitools/client/models/Order.scala
|
||||
src/main/scala/org/openapitools/client/models/OrderStatus.scala
|
||||
src/main/scala/org/openapitools/client/models/Pet.scala
|
||||
src/main/scala/org/openapitools/client/models/PetStatus.scala
|
||||
src/main/scala/org/openapitools/client/models/Tag.scala
|
||||
src/main/scala/org/openapitools/client/models/User.scala
|
||||
src/main/scala/org/openapitools/client/models/_Authorization.scala
|
||||
src/main/scala/org/openapitools/client/models/_FailedRequest.scala
|
||||
src/main/scala/org/openapitools/client/models/package.scala
|
@ -0,0 +1 @@
|
||||
7.9.0-SNAPSHOT
|
34
samples/client/petstore/scala-http4s/build.sbt
Normal file
34
samples/client/petstore/scala-http4s/build.sbt
Normal file
@ -0,0 +1,34 @@
|
||||
scalaVersion := "3.3.3"
|
||||
|
||||
version := "1.0.0"
|
||||
name := "scala-http4s-client"
|
||||
organization := "org.openapitools"
|
||||
|
||||
val CirceVersion = "0.14.9"
|
||||
val Http4sVersion = "0.23.26"
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
"org.http4s" %% "http4s-ember-client" % Http4sVersion,
|
||||
"org.http4s" %% "http4s-circe" % Http4sVersion,
|
||||
"org.http4s" %% "http4s-dsl" % Http4sVersion,
|
||||
"org.http4s" %% "http4s-client" % Http4sVersion,
|
||||
"io.circe" %% "circe-core" % CirceVersion,
|
||||
"io.circe" %% "circe-generic" % CirceVersion,
|
||||
"io.circe" %% "circe-parser" % CirceVersion,
|
||||
"org.scalatest" %% "scalatest" % "3.2.19" % "test"
|
||||
)
|
||||
|
||||
scalacOptions := Seq(
|
||||
"-encoding",
|
||||
"UTF-8",
|
||||
"-deprecation",
|
||||
"-unchecked",
|
||||
"-feature",
|
||||
"-language:existentials,experimental.macros,higherKinds,implicitConversions,postfixOps,adhocExtensions",
|
||||
"-Yretain-trees",
|
||||
"-Xmax-inlines:100",
|
||||
"-Ykind-projector:underscores",
|
||||
"-source:future"
|
||||
)
|
||||
|
||||
Compile / publishArtifact := false
|
@ -0,0 +1 @@
|
||||
sbt.version=1.9.9
|
@ -0,0 +1,89 @@
|
||||
/** 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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.apis
|
||||
|
||||
import cats.effect.Concurrent
|
||||
import io.circe.Encoder
|
||||
import org.http4s.{Header, Headers, Method, Request, Response, Uri, UrlForm}
|
||||
import org.http4s.client.Client as Http4sClient
|
||||
import org.http4s.QueryParamEncoder.*
|
||||
import org.typelevel.ci.CIString
|
||||
import java.util.Base64
|
||||
import java.nio.charset.StandardCharsets
|
||||
import org.openapitools.client.models.*
|
||||
|
||||
abstract class BaseClient[F[*]: Concurrent](
|
||||
val baseUrl: Uri,
|
||||
defaultHeaders: Seq[(String, String)] = Nil,
|
||||
httpClient: Http4sClient[F]
|
||||
) {
|
||||
|
||||
val ApiVersion: String = "1.0.0"
|
||||
|
||||
private lazy val defaultApiHeaders = Seq(
|
||||
("X-Apidoc-Version", ApiVersion)
|
||||
)
|
||||
|
||||
protected def modifyRequest(request: Request[F]): Request[F] = request
|
||||
|
||||
def _executeRequest[T, U](
|
||||
method: String,
|
||||
path: String,
|
||||
body: Option[T] = None,
|
||||
formParameters: Option[Seq[(String, Any)]] = None,
|
||||
queryParameters: Seq[(String, Any)] = Nil,
|
||||
requestHeaders: Seq[(String, String)] = Nil,
|
||||
auth: Option[_Authorization] = None
|
||||
)(handler: Response[F] => F[U])(implicit encoder: Encoder[T]): F[U] = {
|
||||
|
||||
val m = Method.fromString(method) match {
|
||||
case Right(m) => m
|
||||
case Left(e) => sys.error(e.toString)
|
||||
}
|
||||
|
||||
val headers = Headers(
|
||||
(
|
||||
defaultApiHeaders ++
|
||||
defaultHeaders ++
|
||||
requestHeaders
|
||||
).groupBy(_._1).map { case (k, l) => Header.Raw(CIString(k), l.last._2) }.toList
|
||||
)
|
||||
|
||||
val queryMap = queryParameters.groupBy(_._1).map { case (k, v) => k -> v.map(_._2.toString) }
|
||||
val uri = Uri.unsafeFromString(s"$baseUrl$path").setQueryParams(queryMap)
|
||||
|
||||
val request = Request[F](method = m, uri = uri, headers = headers)
|
||||
|
||||
val reqAndMaybeAuth = auth.fold(request) {
|
||||
case _Authorization.Basic(username, passwordOpt) =>
|
||||
val userpass = s"$username:${passwordOpt.getOrElse("")}"
|
||||
val token = Base64.getEncoder.encodeToString(
|
||||
userpass.getBytes(StandardCharsets.ISO_8859_1)
|
||||
)
|
||||
request.putHeaders(Header.Raw(CIString("Authorization"), s"Basic $token"))
|
||||
case _Authorization.Bearer(token) =>
|
||||
request.putHeaders(Header.Raw(CIString("Authorization"), s"Bearer $token"))
|
||||
case _Authorization.ApiKey(name, value) =>
|
||||
request.putHeaders(Header.Raw(CIString(name), value))
|
||||
}
|
||||
val formBody = formParameters.map { x =>
|
||||
UrlForm(x.groupBy(_._1).map{case (k, v) => (k, v.mkString(","))}.toSeq*)
|
||||
}
|
||||
|
||||
import JsonSupports.*
|
||||
val reqAndMaybeAuthAndBody =
|
||||
if (formBody.nonEmpty) formBody.fold(reqAndMaybeAuth)(reqAndMaybeAuth.withEntity)
|
||||
else body.fold(reqAndMaybeAuth)(reqAndMaybeAuth.withEntity)
|
||||
|
||||
httpClient.run(modifyRequest(reqAndMaybeAuthAndBody)).use(handler)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/** 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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.apis
|
||||
|
||||
import cats.effect.*
|
||||
import cats.implicits.*
|
||||
import io.circe.{Decoder, Encoder}
|
||||
import org.http4s.{EntityDecoder, EntityEncoder, Response}
|
||||
import org.http4s.circe as http4sCirce
|
||||
import org.openapitools.client.models.*
|
||||
|
||||
object JsonSupports {
|
||||
|
||||
implicit def circeJsonEncoder[F[*]: Concurrent, A](implicit encoder: Encoder[A]): EntityEncoder[F, A] =
|
||||
http4sCirce.jsonEncoderOf[F, A]
|
||||
implicit def circeJsonDecoder[F[*]: Concurrent, A](implicit decoder: Decoder[A]): EntityDecoder[F, A] =
|
||||
http4sCirce.jsonOf[F, A]
|
||||
|
||||
def parseJson[F[*]: Concurrent, T](
|
||||
className: String,
|
||||
r: Response[F]
|
||||
)(implicit decoder: Decoder[T]): F[T] = r.attemptAs[T].value.flatMap {
|
||||
case Right(value) => Concurrent[F].pure(value)
|
||||
case Left(error) => Concurrent[F].raiseError(
|
||||
_FailedRequest(r.status.code, s"Invalid json for class[$className]: error $error")
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,217 @@
|
||||
/** 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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.apis
|
||||
|
||||
import cats.effect.Concurrent
|
||||
import io.circe.Encoder
|
||||
import org.http4s.Uri
|
||||
import org.http4s.client.Client as Http4sClient
|
||||
import org.openapitools.client.models.ApiResponse
|
||||
import java.io.File
|
||||
import org.openapitools.client.models.FindPetsByStatusStatusParameterInner
|
||||
import org.openapitools.client.models.Pet
|
||||
import scala.collection.immutable.Seq
|
||||
import org.openapitools.client.models.*
|
||||
|
||||
trait PetApiEndpoints[F[*]] {
|
||||
|
||||
def addPet(pet: Pet): F[Pet]
|
||||
def deletePet(petId: Long, apiKey: Option[String] = None): F[Unit]
|
||||
def findPetsByStatus(status: Seq[FindPetsByStatusStatusParameterInner]): F[Seq[Pet]]
|
||||
def findPetsByTags(tags: Seq[String]): F[Seq[Pet]]
|
||||
def getPetById(petId: Long)(implicit auth: _Authorization.ApiKey): F[Pet]
|
||||
def updatePet(pet: Pet): F[Pet]
|
||||
def updatePetWithForm(petId: Long, name: Option[String] = None, status: Option[String] = None): F[Unit]
|
||||
def uploadFile(petId: Long, additionalMetadata: Option[String] = None, file: Option[File] = None): F[ApiResponse]
|
||||
|
||||
}
|
||||
|
||||
class PetApiEndpointsImpl[F[*]: Concurrent](
|
||||
override val baseUrl: Uri,
|
||||
defaultHeaders: Seq[(String, String)] = Nil,
|
||||
httpClient: Http4sClient[F]
|
||||
) extends BaseClient[F](baseUrl, defaultHeaders, httpClient) with PetApiEndpoints[F] {
|
||||
|
||||
import JsonSupports.*
|
||||
import io.circe.syntax.EncoderOps
|
||||
import cats.implicits.toFlatMapOps
|
||||
|
||||
override def addPet(pet: Pet): F[Pet] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
|
||||
_executeRequest[Pet, Pet](
|
||||
method = "POST",
|
||||
path = s"/pet",
|
||||
body = Some(pet),
|
||||
formParameters = None,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = None) {
|
||||
|
||||
case r if r.status.code == 200 => parseJson[F, Pet]("Pet", r)
|
||||
case r if r.status.code == 405 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
}
|
||||
}
|
||||
|
||||
override def deletePet(petId: Long, apiKey: Option[String] = None): F[Unit] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json"),
|
||||
apiKey.map(x => "api_key" -> x)
|
||||
).flatten
|
||||
|
||||
_executeRequest[Unit, Unit](
|
||||
method = "DELETE",
|
||||
path = s"/pet/${petId}",
|
||||
body = None,
|
||||
formParameters = None,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = None) {
|
||||
|
||||
case r if r.status.code == 400 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
}
|
||||
}
|
||||
|
||||
override def findPetsByStatus(status: Seq[FindPetsByStatusStatusParameterInner]): F[Seq[Pet]] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
val queryParameters = (
|
||||
Some(status.map("status" -> _))
|
||||
).toSeq.flatten
|
||||
|
||||
_executeRequest[Unit, Seq[Pet]](
|
||||
method = "GET",
|
||||
path = s"/pet/findByStatus",
|
||||
body = None,
|
||||
formParameters = None,
|
||||
queryParameters = queryParameters,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = None) {
|
||||
|
||||
case r if r.status.code == 200 => parseJson[F, Seq[Pet]]("Seq[Pet]", r)
|
||||
case r if r.status.code == 400 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
}
|
||||
}
|
||||
|
||||
override def findPetsByTags(tags: Seq[String]): F[Seq[Pet]] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
val queryParameters = (
|
||||
Some(tags.map("tags" -> _))
|
||||
).toSeq.flatten
|
||||
|
||||
_executeRequest[Unit, Seq[Pet]](
|
||||
method = "GET",
|
||||
path = s"/pet/findByTags",
|
||||
body = None,
|
||||
formParameters = None,
|
||||
queryParameters = queryParameters,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = None) {
|
||||
|
||||
case r if r.status.code == 200 => parseJson[F, Seq[Pet]]("Seq[Pet]", r)
|
||||
case r if r.status.code == 400 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
}
|
||||
}
|
||||
|
||||
override def getPetById(petId: Long)(implicit auth: _Authorization.ApiKey): F[Pet] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
|
||||
_executeRequest[Unit, Pet](
|
||||
method = "GET",
|
||||
path = s"/pet/${petId}",
|
||||
body = None,
|
||||
formParameters = None,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = Some(auth)) {
|
||||
|
||||
case r if r.status.code == 200 => parseJson[F, Pet]("Pet", r)
|
||||
case r if r.status.code == 400 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
case r if r.status.code == 404 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
}
|
||||
}
|
||||
|
||||
override def updatePet(pet: Pet): F[Pet] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
|
||||
_executeRequest[Pet, Pet](
|
||||
method = "PUT",
|
||||
path = s"/pet",
|
||||
body = Some(pet),
|
||||
formParameters = None,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = None) {
|
||||
|
||||
case r if r.status.code == 200 => parseJson[F, Pet]("Pet", r)
|
||||
case r if r.status.code == 400 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
case r if r.status.code == 404 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
case r if r.status.code == 405 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
}
|
||||
}
|
||||
|
||||
override def updatePetWithForm(petId: Long, name: Option[String] = None, status: Option[String] = None): F[Unit] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/x-www-form-urlencoded")
|
||||
).flatten
|
||||
val formParameters = Some((
|
||||
name.map("name" -> _).map(Seq(_)) ++
|
||||
status.map("status" -> _).map(Seq(_))
|
||||
).toSeq.flatten)
|
||||
|
||||
_executeRequest[Unit, Unit](
|
||||
method = "POST",
|
||||
path = s"/pet/${petId}",
|
||||
body = None,
|
||||
formParameters = formParameters,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = None) {
|
||||
|
||||
case r if r.status.code == 200 => Concurrent[F].pure(())
|
||||
case r if r.status.code == 405 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
}
|
||||
}
|
||||
|
||||
override def uploadFile(petId: Long, additionalMetadata: Option[String] = None, file: Option[File] = None): F[ApiResponse] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "multipart/form-data")
|
||||
).flatten
|
||||
val formParameters = Some((
|
||||
additionalMetadata.map("additionalMetadata" -> _).map(Seq(_)) ++
|
||||
file.map("file" -> _).map(Seq(_))
|
||||
).toSeq.flatten)
|
||||
|
||||
_executeRequest[Unit, ApiResponse](
|
||||
method = "POST",
|
||||
path = s"/pet/${petId}/uploadImage",
|
||||
body = None,
|
||||
formParameters = formParameters,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = None) {
|
||||
|
||||
case r if r.status.code == 200 => parseJson[F, ApiResponse]("ApiResponse", r)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,117 @@
|
||||
/** 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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.apis
|
||||
|
||||
import cats.effect.Concurrent
|
||||
import io.circe.Encoder
|
||||
import org.http4s.Uri
|
||||
import org.http4s.client.Client as Http4sClient
|
||||
import org.openapitools.client.models.Order
|
||||
import org.openapitools.client.models.*
|
||||
|
||||
trait StoreApiEndpoints[F[*]] {
|
||||
|
||||
def deleteOrder(orderId: String): F[Unit]
|
||||
def getInventory()(implicit auth: _Authorization.ApiKey): F[Map[String, Int]]
|
||||
def getOrderById(orderId: Long): F[Order]
|
||||
def placeOrder(order: Order): F[Order]
|
||||
|
||||
}
|
||||
|
||||
class StoreApiEndpointsImpl[F[*]: Concurrent](
|
||||
override val baseUrl: Uri,
|
||||
defaultHeaders: Seq[(String, String)] = Nil,
|
||||
httpClient: Http4sClient[F]
|
||||
) extends BaseClient[F](baseUrl, defaultHeaders, httpClient) with StoreApiEndpoints[F] {
|
||||
|
||||
import JsonSupports.*
|
||||
import io.circe.syntax.EncoderOps
|
||||
import cats.implicits.toFlatMapOps
|
||||
|
||||
override def deleteOrder(orderId: String): F[Unit] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
|
||||
_executeRequest[Unit, Unit](
|
||||
method = "DELETE",
|
||||
path = s"/store/order/${orderId}",
|
||||
body = None,
|
||||
formParameters = None,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = None) {
|
||||
|
||||
case r if r.status.code == 400 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
case r if r.status.code == 404 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
}
|
||||
}
|
||||
|
||||
override def getInventory()(implicit auth: _Authorization.ApiKey): F[Map[String, Int]] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
|
||||
_executeRequest[Unit, Map[String, Int]](
|
||||
method = "GET",
|
||||
path = s"/store/inventory",
|
||||
body = None,
|
||||
formParameters = None,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = Some(auth)) {
|
||||
|
||||
case r if r.status.code == 200 => parseJson[F, Map[String, Int]]("Map[String, Int]", r)
|
||||
}
|
||||
}
|
||||
|
||||
override def getOrderById(orderId: Long): F[Order] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
|
||||
_executeRequest[Unit, Order](
|
||||
method = "GET",
|
||||
path = s"/store/order/${orderId}",
|
||||
body = None,
|
||||
formParameters = None,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = None) {
|
||||
|
||||
case r if r.status.code == 200 => parseJson[F, Order]("Order", r)
|
||||
case r if r.status.code == 400 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
case r if r.status.code == 404 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
}
|
||||
}
|
||||
|
||||
override def placeOrder(order: Order): F[Order] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
|
||||
_executeRequest[Order, Order](
|
||||
method = "POST",
|
||||
path = s"/store/order",
|
||||
body = Some(order),
|
||||
formParameters = None,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = None) {
|
||||
|
||||
case r if r.status.code == 200 => parseJson[F, Order]("Order", r)
|
||||
case r if r.status.code == 400 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,196 @@
|
||||
/** 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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.apis
|
||||
|
||||
import cats.effect.Concurrent
|
||||
import io.circe.Encoder
|
||||
import org.http4s.Uri
|
||||
import org.http4s.client.Client as Http4sClient
|
||||
import java.time.Instant
|
||||
import scala.collection.immutable.Seq
|
||||
import org.openapitools.client.models.User
|
||||
import org.openapitools.client.models.*
|
||||
|
||||
trait UserApiEndpoints[F[*]] {
|
||||
|
||||
def createUser(user: User)(implicit auth: _Authorization.ApiKey): F[Unit]
|
||||
def createUsersWithArrayInput(user: Seq[User])(implicit auth: _Authorization.ApiKey): F[Unit]
|
||||
def createUsersWithListInput(user: Seq[User])(implicit auth: _Authorization.ApiKey): F[Unit]
|
||||
def deleteUser(username: String)(implicit auth: _Authorization.ApiKey): F[Unit]
|
||||
def getUserByName(username: String): F[User]
|
||||
def loginUser(username: String, password: String): F[String]
|
||||
def logoutUser()(implicit auth: _Authorization.ApiKey): F[Unit]
|
||||
def updateUser(username: String, user: User)(implicit auth: _Authorization.ApiKey): F[Unit]
|
||||
|
||||
}
|
||||
|
||||
class UserApiEndpointsImpl[F[*]: Concurrent](
|
||||
override val baseUrl: Uri,
|
||||
defaultHeaders: Seq[(String, String)] = Nil,
|
||||
httpClient: Http4sClient[F]
|
||||
) extends BaseClient[F](baseUrl, defaultHeaders, httpClient) with UserApiEndpoints[F] {
|
||||
|
||||
import JsonSupports.*
|
||||
import io.circe.syntax.EncoderOps
|
||||
import cats.implicits.toFlatMapOps
|
||||
|
||||
override def createUser(user: User)(implicit auth: _Authorization.ApiKey): F[Unit] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
|
||||
_executeRequest[User, Unit](
|
||||
method = "POST",
|
||||
path = s"/user",
|
||||
body = Some(user),
|
||||
formParameters = None,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = Some(auth)) {
|
||||
r => Concurrent[F].pure(())
|
||||
}
|
||||
}
|
||||
|
||||
override def createUsersWithArrayInput(user: Seq[User])(implicit auth: _Authorization.ApiKey): F[Unit] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
|
||||
_executeRequest[Seq[User], Unit](
|
||||
method = "POST",
|
||||
path = s"/user/createWithArray",
|
||||
body = Some(user),
|
||||
formParameters = None,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = Some(auth)) {
|
||||
r => Concurrent[F].pure(())
|
||||
}
|
||||
}
|
||||
|
||||
override def createUsersWithListInput(user: Seq[User])(implicit auth: _Authorization.ApiKey): F[Unit] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
|
||||
_executeRequest[Seq[User], Unit](
|
||||
method = "POST",
|
||||
path = s"/user/createWithList",
|
||||
body = Some(user),
|
||||
formParameters = None,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = Some(auth)) {
|
||||
r => Concurrent[F].pure(())
|
||||
}
|
||||
}
|
||||
|
||||
override def deleteUser(username: String)(implicit auth: _Authorization.ApiKey): F[Unit] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
|
||||
_executeRequest[Unit, Unit](
|
||||
method = "DELETE",
|
||||
path = s"/user/${username}",
|
||||
body = None,
|
||||
formParameters = None,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = Some(auth)) {
|
||||
|
||||
case r if r.status.code == 400 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
case r if r.status.code == 404 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
}
|
||||
}
|
||||
|
||||
override def getUserByName(username: String): F[User] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
|
||||
_executeRequest[Unit, User](
|
||||
method = "GET",
|
||||
path = s"/user/${username}",
|
||||
body = None,
|
||||
formParameters = None,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = None) {
|
||||
|
||||
case r if r.status.code == 200 => parseJson[F, User]("User", r)
|
||||
case r if r.status.code == 400 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
case r if r.status.code == 404 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
}
|
||||
}
|
||||
|
||||
override def loginUser(username: String, password: String): F[String] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
val queryParameters = (
|
||||
Some(Seq("username" -> username)) ++
|
||||
Some(Seq("password" -> password))
|
||||
).toSeq.flatten
|
||||
|
||||
_executeRequest[Unit, String](
|
||||
method = "GET",
|
||||
path = s"/user/login",
|
||||
body = None,
|
||||
formParameters = None,
|
||||
queryParameters = queryParameters,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = None) {
|
||||
|
||||
case r if r.status.code == 200 => parseJson[F, String]("String", r)
|
||||
case r if r.status.code == 400 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
}
|
||||
}
|
||||
|
||||
override def logoutUser()(implicit auth: _Authorization.ApiKey): F[Unit] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
|
||||
_executeRequest[Unit, Unit](
|
||||
method = "GET",
|
||||
path = s"/user/logout",
|
||||
body = None,
|
||||
formParameters = None,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = Some(auth)) {
|
||||
r => Concurrent[F].pure(())
|
||||
}
|
||||
}
|
||||
|
||||
override def updateUser(username: String, user: User)(implicit auth: _Authorization.ApiKey): F[Unit] = {
|
||||
val requestHeaders = Seq(
|
||||
Some("Content-Type" -> "application/json")
|
||||
).flatten
|
||||
|
||||
_executeRequest[User, Unit](
|
||||
method = "PUT",
|
||||
path = s"/user/${username}",
|
||||
body = Some(user),
|
||||
formParameters = None,
|
||||
queryParameters = Nil,
|
||||
requestHeaders = requestHeaders,
|
||||
auth = Some(auth)) {
|
||||
|
||||
case r if r.status.code == 400 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
case r if r.status.code == 404 => Concurrent[F].raiseError(_FailedRequest(r.status.code, r.status.reason))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.models
|
||||
|
||||
import io.circe.*
|
||||
import io.circe.syntax.*
|
||||
import io.circe.{Decoder, Encoder}
|
||||
|
||||
|
||||
/** Describes the result of uploading an image resource
|
||||
* @param code
|
||||
* @param `type`
|
||||
* @param message
|
||||
*/
|
||||
case class ApiResponse(
|
||||
code: Option[Int] = None,
|
||||
`type`: Option[String] = None,
|
||||
message: Option[String] = None
|
||||
)
|
||||
|
||||
object ApiResponse {
|
||||
given encoderApiResponse: Encoder[ApiResponse] = Encoder.instance { t =>
|
||||
Json.fromFields{
|
||||
Seq(
|
||||
t.code.map(v => "code" -> v.asJson),
|
||||
t.`type`.map(v => "type" -> v.asJson),
|
||||
t.message.map(v => "message" -> v.asJson)
|
||||
).flatten
|
||||
}
|
||||
}
|
||||
given decoderApiResponse: Decoder[ApiResponse] = Decoder.instance { c =>
|
||||
for {
|
||||
code <- c.downField("code").as[Option[Int]]
|
||||
`type` <- c.downField("type").as[Option[String]]
|
||||
message <- c.downField("message").as[Option[String]]
|
||||
} yield ApiResponse(
|
||||
code = code,
|
||||
`type` = `type`,
|
||||
message = message
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
/** 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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.models
|
||||
|
||||
import io.circe.*
|
||||
import io.circe.syntax.*
|
||||
import io.circe.{Decoder, Encoder}
|
||||
|
||||
|
||||
/** A category for a pet
|
||||
* @param id
|
||||
* @param name
|
||||
*/
|
||||
case class Category(
|
||||
id: Option[Long] = None,
|
||||
name: Option[String] = None
|
||||
)
|
||||
|
||||
object Category {
|
||||
given encoderCategory: Encoder[Category] = Encoder.instance { t =>
|
||||
Json.fromFields{
|
||||
Seq(
|
||||
t.id.map(v => "id" -> v.asJson),
|
||||
t.name.map(v => "name" -> v.asJson)
|
||||
).flatten
|
||||
}
|
||||
}
|
||||
given decoderCategory: Decoder[Category] = Decoder.instance { c =>
|
||||
for {
|
||||
id <- c.downField("id").as[Option[Long]]
|
||||
name <- c.downField("name").as[Option[String]]
|
||||
} yield Category(
|
||||
id = id,
|
||||
name = name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
/** 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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.models
|
||||
|
||||
import io.circe.*
|
||||
import io.circe.syntax.*
|
||||
import io.circe.{Decoder, Encoder}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
enum FindPetsByStatusStatusParameterInner(val value: String) {
|
||||
case Available extends FindPetsByStatusStatusParameterInner("available")
|
||||
case Pending extends FindPetsByStatusStatusParameterInner("pending")
|
||||
case Sold extends FindPetsByStatusStatusParameterInner("sold")
|
||||
}
|
||||
|
||||
object FindPetsByStatusStatusParameterInner {
|
||||
given decoderFindPetsByStatusStatusParameterInner: Decoder[FindPetsByStatusStatusParameterInner] =
|
||||
Decoder.decodeString.map(str => FindPetsByStatusStatusParameterInner.values.find(_.value == str)
|
||||
.getOrElse(throw java.lang.IllegalArgumentException(s"FindPetsByStatusStatusParameterInner enum case not found: $str"))
|
||||
)
|
||||
|
||||
given encoderFindPetsByStatusStatusParameterInner: Encoder[FindPetsByStatusStatusParameterInner] =
|
||||
Encoder.encodeString.contramap[FindPetsByStatusStatusParameterInner](_.value)
|
||||
}
|
||||
|
@ -0,0 +1,67 @@
|
||||
/** 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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.models
|
||||
|
||||
import io.circe.*
|
||||
import io.circe.syntax.*
|
||||
import io.circe.{Decoder, Encoder}
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
/** An order for a pets from the pet store
|
||||
* @param id
|
||||
* @param petId
|
||||
* @param quantity
|
||||
* @param shipDate
|
||||
* @param status
|
||||
* @param complete
|
||||
*/
|
||||
case class Order(
|
||||
id: Option[Long] = None,
|
||||
petId: Option[Long] = None,
|
||||
quantity: Option[Int] = None,
|
||||
shipDate: Option[Instant] = None,
|
||||
status: Option[OrderStatus] = None,
|
||||
complete: Option[Boolean] = None
|
||||
)
|
||||
|
||||
object Order {
|
||||
given encoderOrder: Encoder[Order] = Encoder.instance { t =>
|
||||
Json.fromFields{
|
||||
Seq(
|
||||
t.id.map(v => "id" -> v.asJson),
|
||||
t.petId.map(v => "petId" -> v.asJson),
|
||||
t.quantity.map(v => "quantity" -> v.asJson),
|
||||
t.shipDate.map(v => "shipDate" -> v.asJson),
|
||||
t.status.map(v => "status" -> v.asJson),
|
||||
t.complete.map(v => "complete" -> v.asJson)
|
||||
).flatten
|
||||
}
|
||||
}
|
||||
given decoderOrder: Decoder[Order] = Decoder.instance { c =>
|
||||
for {
|
||||
id <- c.downField("id").as[Option[Long]]
|
||||
petId <- c.downField("petId").as[Option[Long]]
|
||||
quantity <- c.downField("quantity").as[Option[Int]]
|
||||
shipDate <- c.downField("shipDate").as[Option[Instant]]
|
||||
status <- c.downField("status").as[Option[OrderStatus]]
|
||||
complete <- c.downField("complete").as[Option[Boolean]]
|
||||
} yield Order(
|
||||
id = id,
|
||||
petId = petId,
|
||||
quantity = quantity,
|
||||
shipDate = shipDate,
|
||||
status = status,
|
||||
complete = complete
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
/** 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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.models
|
||||
|
||||
import io.circe.*
|
||||
import io.circe.syntax.*
|
||||
import io.circe.{Decoder, Encoder}
|
||||
|
||||
|
||||
/** Order Status
|
||||
*/
|
||||
enum OrderStatus(val value: String) {
|
||||
case Placed extends OrderStatus("placed")
|
||||
case Approved extends OrderStatus("approved")
|
||||
case Delivered extends OrderStatus("delivered")
|
||||
}
|
||||
|
||||
object OrderStatus {
|
||||
given decoderOrderStatus: Decoder[OrderStatus] =
|
||||
Decoder.decodeString.map(str => OrderStatus.values.find(_.value == str)
|
||||
.getOrElse(throw java.lang.IllegalArgumentException(s"OrderStatus enum case not found: $str"))
|
||||
)
|
||||
|
||||
given encoderOrderStatus: Encoder[OrderStatus] =
|
||||
Encoder.encodeString.contramap[OrderStatus](_.value)
|
||||
}
|
||||
|
@ -0,0 +1,67 @@
|
||||
/** 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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.models
|
||||
|
||||
import io.circe.*
|
||||
import io.circe.syntax.*
|
||||
import io.circe.{Decoder, Encoder}
|
||||
|
||||
import scala.collection.immutable.Seq
|
||||
|
||||
/** A pet for sale in the pet store
|
||||
* @param id
|
||||
* @param category
|
||||
* @param name
|
||||
* @param photoUrls
|
||||
* @param tags
|
||||
* @param status
|
||||
*/
|
||||
case class Pet(
|
||||
id: Option[Long] = None,
|
||||
category: Option[Category] = None,
|
||||
name: String,
|
||||
photoUrls: Seq[String],
|
||||
tags: Option[Seq[Tag]] = None,
|
||||
status: Option[PetStatus] = None
|
||||
)
|
||||
|
||||
object Pet {
|
||||
given encoderPet: Encoder[Pet] = Encoder.instance { t =>
|
||||
Json.fromFields{
|
||||
Seq(
|
||||
t.id.map(v => "id" -> v.asJson),
|
||||
t.category.map(v => "category" -> v.asJson),
|
||||
Some("name" -> t.name.asJson),
|
||||
Some("photoUrls" -> t.photoUrls.asJson),
|
||||
t.tags.map(v => "tags" -> v.asJson),
|
||||
t.status.map(v => "status" -> v.asJson)
|
||||
).flatten
|
||||
}
|
||||
}
|
||||
given decoderPet: Decoder[Pet] = Decoder.instance { c =>
|
||||
for {
|
||||
id <- c.downField("id").as[Option[Long]]
|
||||
category <- c.downField("category").as[Option[Category]]
|
||||
name <- c.downField("name").as[String]
|
||||
photoUrls <- c.downField("photoUrls").as[Seq[String]]
|
||||
tags <- c.downField("tags").as[Option[Seq[Tag]]]
|
||||
status <- c.downField("status").as[Option[PetStatus]]
|
||||
} yield Pet(
|
||||
id = id,
|
||||
category = category,
|
||||
name = name,
|
||||
photoUrls = photoUrls,
|
||||
tags = tags,
|
||||
status = status
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
/** 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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.models
|
||||
|
||||
import io.circe.*
|
||||
import io.circe.syntax.*
|
||||
import io.circe.{Decoder, Encoder}
|
||||
|
||||
|
||||
/** pet status in the store
|
||||
*/
|
||||
enum PetStatus(val value: String) {
|
||||
case Available extends PetStatus("available")
|
||||
case Pending extends PetStatus("pending")
|
||||
case Sold extends PetStatus("sold")
|
||||
}
|
||||
|
||||
object PetStatus {
|
||||
given decoderPetStatus: Decoder[PetStatus] =
|
||||
Decoder.decodeString.map(str => PetStatus.values.find(_.value == str)
|
||||
.getOrElse(throw java.lang.IllegalArgumentException(s"PetStatus enum case not found: $str"))
|
||||
)
|
||||
|
||||
given encoderPetStatus: Encoder[PetStatus] =
|
||||
Encoder.encodeString.contramap[PetStatus](_.value)
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
/** 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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.models
|
||||
|
||||
import io.circe.*
|
||||
import io.circe.syntax.*
|
||||
import io.circe.{Decoder, Encoder}
|
||||
|
||||
|
||||
/** A tag for a pet
|
||||
* @param id
|
||||
* @param name
|
||||
*/
|
||||
case class Tag(
|
||||
id: Option[Long] = None,
|
||||
name: Option[String] = None
|
||||
)
|
||||
|
||||
object Tag {
|
||||
given encoderTag: Encoder[Tag] = Encoder.instance { t =>
|
||||
Json.fromFields{
|
||||
Seq(
|
||||
t.id.map(v => "id" -> v.asJson),
|
||||
t.name.map(v => "name" -> v.asJson)
|
||||
).flatten
|
||||
}
|
||||
}
|
||||
given decoderTag: Decoder[Tag] = Decoder.instance { c =>
|
||||
for {
|
||||
id <- c.downField("id").as[Option[Long]]
|
||||
name <- c.downField("name").as[Option[String]]
|
||||
} yield Tag(
|
||||
id = id,
|
||||
name = name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,76 @@
|
||||
/** 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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.models
|
||||
|
||||
import io.circe.*
|
||||
import io.circe.syntax.*
|
||||
import io.circe.{Decoder, Encoder}
|
||||
|
||||
|
||||
/** A User who is purchasing from the pet store
|
||||
* @param id
|
||||
* @param username
|
||||
* @param firstName
|
||||
* @param lastName
|
||||
* @param email
|
||||
* @param password
|
||||
* @param phone
|
||||
* @param userStatus User Status
|
||||
*/
|
||||
case class User(
|
||||
id: Option[Long] = None,
|
||||
username: Option[String] = None,
|
||||
firstName: Option[String] = None,
|
||||
lastName: Option[String] = None,
|
||||
email: Option[String] = None,
|
||||
password: Option[String] = None,
|
||||
phone: Option[String] = None,
|
||||
userStatus: Option[Int] = None
|
||||
)
|
||||
|
||||
object User {
|
||||
given encoderUser: Encoder[User] = Encoder.instance { t =>
|
||||
Json.fromFields{
|
||||
Seq(
|
||||
t.id.map(v => "id" -> v.asJson),
|
||||
t.username.map(v => "username" -> v.asJson),
|
||||
t.firstName.map(v => "firstName" -> v.asJson),
|
||||
t.lastName.map(v => "lastName" -> v.asJson),
|
||||
t.email.map(v => "email" -> v.asJson),
|
||||
t.password.map(v => "password" -> v.asJson),
|
||||
t.phone.map(v => "phone" -> v.asJson),
|
||||
t.userStatus.map(v => "userStatus" -> v.asJson)
|
||||
).flatten
|
||||
}
|
||||
}
|
||||
given decoderUser: Decoder[User] = Decoder.instance { c =>
|
||||
for {
|
||||
id <- c.downField("id").as[Option[Long]]
|
||||
username <- c.downField("username").as[Option[String]]
|
||||
firstName <- c.downField("firstName").as[Option[String]]
|
||||
lastName <- c.downField("lastName").as[Option[String]]
|
||||
email <- c.downField("email").as[Option[String]]
|
||||
password <- c.downField("password").as[Option[String]]
|
||||
phone <- c.downField("phone").as[Option[String]]
|
||||
userStatus <- c.downField("userStatus").as[Option[Int]]
|
||||
} yield User(
|
||||
id = id,
|
||||
username = username,
|
||||
firstName = firstName,
|
||||
lastName = lastName,
|
||||
email = email,
|
||||
password = password,
|
||||
phone = phone,
|
||||
userStatus = userStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
/** 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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.models
|
||||
|
||||
sealed trait _Authorization
|
||||
|
||||
object _Authorization {
|
||||
final case class Basic(username: String, password: Option[String] = None) extends _Authorization
|
||||
final case class ApiKey(name: String, value: String) extends _Authorization
|
||||
final case class Bearer(token: String) extends _Authorization
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/** 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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client.models
|
||||
|
||||
import io.circe.*
|
||||
import io.circe.Decoder.*
|
||||
import io.circe.Encoder.*
|
||||
import io.circe.syntax.*
|
||||
|
||||
case class _FailedRequest(code: Int, message: String) extends Exception(s"Server return status code: $code; message: $message")
|
||||
|
||||
object _FailedRequest {
|
||||
|
||||
given encoderFailedRequest: Encoder[_FailedRequest] = Encoder.instance { t =>
|
||||
Json.fromFields{
|
||||
Seq(
|
||||
"code" -> t.code.asJson,
|
||||
"message" -> t.message.asJson
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
given decodeFailedRequest: Decoder[_FailedRequest] = Decoder.instance { c =>
|
||||
for {
|
||||
code <- c.downField("code").as[Int]
|
||||
message <- c.downField("message").as[String]
|
||||
} yield _FailedRequest(
|
||||
code = code,
|
||||
message = message
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
* Contact: team@openapitools.org
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
package org.openapitools.client
|
||||
|
||||
import io.circe.{Decoder, Encoder}
|
||||
|
||||
package object models {
|
||||
|
||||
given decodeUUID: Decoder[_root_.java.util.UUID] =
|
||||
Decoder.decodeString.map(str => _root_.java.util.UUID.fromString(str))
|
||||
|
||||
given encodeUUID: Encoder[_root_.java.util.UUID] =
|
||||
Encoder.encodeString.contramap[_root_.java.util.UUID](uuid => uuid.toString)
|
||||
|
||||
given decodeInstant: Decoder[_root_.java.time.Instant] =
|
||||
Decoder.decodeString.map(str => _root_.java.time.OffsetDateTime.parse(str).toInstant)
|
||||
|
||||
given encodeInstant: Encoder[_root_.java.time.Instant] =
|
||||
Encoder.encodeString.contramap[_root_.java.time.Instant](_.toString)
|
||||
|
||||
given decodeLocalDate: Decoder[_root_.java.time.LocalDate] =
|
||||
Decoder.decodeString.map(str => _root_.java.time.LocalDate.parse(str))
|
||||
|
||||
given encodeLocalDate: Encoder[_root_.java.time.LocalDate] =
|
||||
Encoder.encodeString.contramap[_root_.java.time.LocalDate](_.toString)
|
||||
|
||||
given decodeJson: Decoder[io.circe.Json] =
|
||||
Decoder.decodeString.map(str => io.circe.Json.fromString(str))
|
||||
|
||||
given encodeJson: Encoder[io.circe.Json] =
|
||||
Encoder.encodeString.contramap[io.circe.Json](_.toString)
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user