diff --git a/CI/pom.xml.circleci.java7 b/CI/pom.xml.circleci.java7
index b4630eda541..e66fe6f5111 100644
--- a/CI/pom.xml.circleci.java7
+++ b/CI/pom.xml.circleci.java7
@@ -837,7 +837,6 @@
samples/client/petstore/scala-akka
samples/client/petstore/scala-httpclient
samples/client/petstore/scalaz
- samples/client/petstore/clojure
samples/client/petstore/java/feign
samples/client/petstore/java/jersey1
samples/client/petstore/java/jersey2
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ClojureClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ClojureClientCodegen.java
index 604211bd703..e1814e522b3 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ClojureClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ClojureClientCodegen.java
@@ -17,23 +17,16 @@
package org.openapitools.codegen.languages;
-import org.openapitools.codegen.CliOption;
-import org.openapitools.codegen.CodegenConfig;
-import org.openapitools.codegen.CodegenConstants;
-import org.openapitools.codegen.CodegenOperation;
-import org.openapitools.codegen.CodegenType;
-import org.openapitools.codegen.DefaultCodegen;
-import org.openapitools.codegen.SupportingFile;
+import org.openapitools.codegen.*;
import io.swagger.v3.oas.models.OpenAPI;
-import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.oas.models.info.*;
import org.apache.commons.lang3.StringUtils;
+import org.openapitools.codegen.utils.ModelUtils;
import java.io.File;
-import java.util.Map;
-import java.util.List;
+import java.util.*;
public class ClojureClientCodegen extends DefaultCodegen implements CodegenConfig {
private static final String PROJECT_NAME = "projectName";
@@ -44,23 +37,29 @@ public class ClojureClientCodegen extends DefaultCodegen implements CodegenConfi
private static final String PROJECT_LICENSE_URL = "projectLicenseUrl";
private static final String BASE_NAMESPACE = "baseNamespace";
+ static final String X_BASE_SPEC = "x-baseSpec";
+ static final String X_MODELS = "x-models";
+
protected String projectName;
protected String projectDescription;
protected String projectVersion;
protected String baseNamespace;
+ protected Set baseSpecs;
+ protected Set models = new HashSet<>();
protected String sourceFolder = "src";
public ClojureClientCodegen() {
super();
outputFolder = "generated-code" + File.separator + "clojure";
+ modelTemplateFiles.put("spec.mustache", ".clj");
apiTemplateFiles.put("api.mustache", ".clj");
embeddedTemplateDir = templateDir = "clojure";
cliOptions.add(new CliOption(PROJECT_NAME,
"name of the project (Default: generated from info.title or \"openapi-clj-client\")"));
cliOptions.add(new CliOption(PROJECT_DESCRIPTION,
- "description of the project (Default: using info.description or \"Client library of \")"));
+ "description of the project (Default: using info.description or \"Client library of \")"));
cliOptions.add(new CliOption(PROJECT_VERSION,
"version of the project (Default: using info.version or \"1.0.0\")"));
cliOptions.add(new CliOption(PROJECT_URL,
@@ -71,6 +70,49 @@ public class ClojureClientCodegen extends DefaultCodegen implements CodegenConfi
"URL of the license the project uses (Default: using info.license.url or not included in project.clj)"));
cliOptions.add(new CliOption(BASE_NAMESPACE,
"the base/top namespace (Default: generated from projectName)"));
+
+ typeMapping.clear();
+
+ // We have specs for most of the types:
+ typeMapping.put("integer", "int?");
+ typeMapping.put("long", "int?");
+ typeMapping.put("short", "int?");
+ typeMapping.put("number", "float?");
+ typeMapping.put("float", "float?");
+ typeMapping.put("double", "float?");
+ typeMapping.put("array", "list?");
+ typeMapping.put("map", "map?");
+ typeMapping.put("boolean", "boolean?");
+ typeMapping.put("string", "string?");
+ typeMapping.put("char", "char?");
+ typeMapping.put("date", "inst?");
+ typeMapping.put("DateTime", "inst?");
+ typeMapping.put("UUID", "uuid?");
+
+ // But some type mappings are not really worth/meaningful to check for:
+ typeMapping.put("object", "any?"); // Like, everything is an object.
+ typeMapping.put("file", "any?"); // We don't really have specs for files,
+ typeMapping.put("binary", "any?"); // nor binary.
+ // And while there is a way to easily check if something is a bytearray,
+ // (https://stackoverflow.com/questions/14796964/), it's not possible
+ // to conform it yet, so we leave it as is.
+ typeMapping.put("ByteArray", "any?");
+
+ // Set of base specs that don't need to be imported
+ baseSpecs = new HashSet<>(
+ Arrays.asList(
+ "int?",
+ "float?",
+ "list?",
+ "map?",
+ "boolean?",
+ "string?",
+ "char?",
+ "inst?",
+ "uuid?",
+ "any?"
+ )
+ );
}
@Override
@@ -88,6 +130,75 @@ public class ClojureClientCodegen extends DefaultCodegen implements CodegenConfi
return "Generates a Clojure client library.";
}
+ @Override
+ public String getTypeDeclaration(Schema p) {
+ if (p instanceof ArraySchema) {
+ ArraySchema ap = (ArraySchema) p;
+ Schema inner = ap.getItems();
+
+ return "(s/coll-of " + getTypeDeclaration(inner) + ")";
+ } else if (ModelUtils.isMapSchema(p)) {
+ Schema inner = (Schema) p.getAdditionalProperties();
+
+ return "(s/map-of string? " + getTypeDeclaration(inner) + ")";
+ }
+
+ // If it's a type we defined, we want to append the spec suffix
+ if (!typeMapping.containsKey(super.getSchemaType(p))) {
+ return super.getTypeDeclaration(p) + "-spec";
+ } else {
+ return super.getTypeDeclaration(p);
+ }
+ }
+
+ @Override
+ public String getSchemaType(Schema p) {
+ String openAPIType = super.getSchemaType(p);
+
+ if (typeMapping.containsKey(openAPIType)) {
+ return typeMapping.get(openAPIType);
+ } else {
+ return toModelName(openAPIType);
+ }
+ }
+
+ @Override
+ public String toModelName(String name) {
+ return dashize(name);
+ }
+
+ @Override
+ public String toVarName(String name) {
+ name = name.replaceAll("[^a-zA-Z0-9_-]+", ""); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
+ return name;
+ }
+
+ @Override
+ public CodegenModel fromModel(String name, Schema mod, Map allDefinitions) {
+ CodegenModel model = super.fromModel(name, mod, allDefinitions);
+
+ // If a var is a base spec we won't need to import it
+ for (CodegenProperty var : model.vars) {
+ if (baseSpecs.contains(var.complexType)) {
+ var.vendorExtensions.put(X_BASE_SPEC, true);
+ } else {
+ var.vendorExtensions.put(X_BASE_SPEC, false);
+ }
+ if (var.items != null) {
+ if (baseSpecs.contains(var.items.complexType)) {
+ var.items.vendorExtensions.put(X_BASE_SPEC, true);
+ } else {
+ var.items.vendorExtensions.put(X_BASE_SPEC, false);
+ }
+ }
+ }
+
+ // We also add all models to our model list so we can import them e.g. in operations
+ models.add(model.classname);
+
+ return model;
+ }
+
@Override
public void preprocessOpenAPI(OpenAPI openAPI) {
super.preprocessOpenAPI(openAPI);
@@ -151,12 +262,14 @@ public class ClojureClientCodegen extends DefaultCodegen implements CodegenConfi
baseNamespace = dashize(projectName);
}
apiPackage = baseNamespace + ".api";
+ modelPackage = baseNamespace + ".specs";
additionalProperties.put(PROJECT_NAME, projectName);
additionalProperties.put(PROJECT_DESCRIPTION, escapeText(projectDescription));
additionalProperties.put(PROJECT_VERSION, projectVersion);
additionalProperties.put(BASE_NAMESPACE, baseNamespace);
additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage);
+ additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage);
final String baseNamespaceFolder = sourceFolder + File.separator + namespaceToFolder(baseNamespace);
supportingFiles.add(new SupportingFile("project.mustache", "", "project.clj"));
@@ -175,6 +288,11 @@ public class ClojureClientCodegen extends DefaultCodegen implements CodegenConfi
return outputFolder + File.separator + sourceFolder + File.separator + namespaceToFolder(apiPackage);
}
+ @Override
+ public String modelFileFolder() {
+ return outputFolder + File.separator + sourceFolder + File.separator + namespaceToFolder(modelPackage);
+ }
+
@Override
public String toOperationId(String operationId) {
// throw exception if method name is empty
@@ -190,6 +308,11 @@ public class ClojureClientCodegen extends DefaultCodegen implements CodegenConfi
return underscore(toApiName(name));
}
+ @Override
+ public String toModelFilename(String name) {
+ return underscore(toModelName(name));
+ }
+
@Override
public String toApiName(String name) {
return dashize(name);
@@ -200,13 +323,6 @@ public class ClojureClientCodegen extends DefaultCodegen implements CodegenConfi
return toVarName(name);
}
- @Override
- public String toVarName(String name) {
- name = name.replaceAll("[^a-zA-Z0-9_-]+", ""); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
- name = dashize(name);
- return name;
- }
-
@Override
public String escapeText(String input) {
if (input == null) {
@@ -222,6 +338,8 @@ public class ClojureClientCodegen extends DefaultCodegen implements CodegenConfi
for (CodegenOperation op : ops) {
// Convert httpMethod to lower case, e.g. "get", "post"
op.httpMethod = op.httpMethod.toLowerCase();
+
+ op.vendorExtensions.put(X_MODELS, models);
}
return operations;
}
diff --git a/modules/openapi-generator/src/main/resources/clojure/api.mustache b/modules/openapi-generator/src/main/resources/clojure/api.mustache
index cf821cfdd3c..b38c8d55b2c 100644
--- a/modules/openapi-generator/src/main/resources/clojure/api.mustache
+++ b/modules/openapi-generator/src/main/resources/clojure/api.mustache
@@ -1,12 +1,18 @@
{{=< >=}}(ns .
- (:require [.core :refer [call-api check-required-params with-collection-format]])
+ (:require [.core :refer [call-api check-required-params with-collection-format *api-context*]]
+ [clojure.spec.alpha :as s]
+ [spec-tools.core :as st]
+ [orchestra.core :refer [defn-spec]]
+ <#operations><#operation><#-first><#vendorExtensions.x-models>[.<.> :refer :all]
+ -first>)
(:import (java.io File)))
+
<#operations><#operation>
-(defn -with-http-info
+(defn-spec -with-http-info any?
"<&summary><#notes>
<¬es>"<#hasOptionalParams>
- ([<#allParams><#required><#isFile>^File ] (-with-http-info<#allParams><#required> nil))
- <#hasOptionalParams>([<#allParams><#required><#isFile>^File <#hasOptionalParams>{:keys [<#allParams><^required><#isFile>^File ]}]<#hasRequiredParams>
+ ([<#allParams><#required><#isFile>^File <#hasMore>, ] (-with-http-info<#allParams><#required> nil))
+ <#hasOptionalParams>([<#allParams><#required><#isFile>^File <#hasMore>, <#hasOptionalParams>{:keys [<#allParams><^required><#isFile>^File <#hasMore> ]} (s/map-of keyword? any?)]<#hasRequiredParams>
<#hasOptionalParams> (check-required-params<#allParams><#required> )
<#hasOptionalParams> (call-api "" :
<#hasOptionalParams> {:path-params {<#pathParams>"" <#collectionFormat>(with-collection-format :)<^collectionFormat> }
@@ -18,10 +24,14 @@
<#hasOptionalParams> :accepts [<#produces>"<& mediaType>"<#hasMore> ]
<#hasOptionalParams> :auth-names [<#authMethods>"<&name>"<#hasMore> ]})<#hasOptionalParams>))
-(defn
+(defn-spec <#returnType><^returnType>any?
"<&summary><#notes>
<¬es>"<#hasOptionalParams>
- ([<#allParams><#required><#isFile>^File ] (<#allParams><#required> nil))
- <#hasOptionalParams>([<#allParams><#required><#isFile>^File <#hasOptionalParams>optional-params]
- <#hasOptionalParams> (:data (-with-http-info<#allParams><#required> <#hasOptionalParams> optional-params))<#hasOptionalParams>))
+ ([<#allParams><#required><#isFile>^File <#hasMore>, ] (<#allParams><#required> nil))
+ <#hasOptionalParams>([<#allParams><#required><#isFile>^File <#hasMore>, <#hasOptionalParams>optional-params any?]
+ <#hasOptionalParams> (let [res (:data (-with-http-info<#allParams><#required> <#hasOptionalParams> optional-params))]
+ <#hasOptionalParams> (if (:decode-models *api-context*)
+ <#hasOptionalParams> (st/decode <#returnType><^returnType>any? res st/string-transformer)
+ <#hasOptionalParams> res))<#hasOptionalParams>))
+
diff --git a/modules/openapi-generator/src/main/resources/clojure/core.mustache b/modules/openapi-generator/src/main/resources/clojure/core.mustache
index 4506eab9f22..b073e6c086b 100644
--- a/modules/openapi-generator/src/main/resources/clojure/core.mustache
+++ b/modules/openapi-generator/src/main/resources/clojure/core.mustache
@@ -16,6 +16,7 @@
{:base-url "<&basePath>"
:date-format "yyyy-MM-dd"
:datetime-format "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"
+ :decode-models false
:debug false
:auths {<#authMethods>"<&name>" nil<#hasMore>
}})
diff --git a/modules/openapi-generator/src/main/resources/clojure/project.mustache b/modules/openapi-generator/src/main/resources/clojure/project.mustache
index 0fe990d02c8..e7a4ea685fe 100644
--- a/modules/openapi-generator/src/main/resources/clojure/project.mustache
+++ b/modules/openapi-generator/src/main/resources/clojure/project.mustache
@@ -3,6 +3,8 @@
:url "<&projectUrl>"<#projectLicenseName>
:license {:name "<&projectLicenseName>"<#projectLicenseUrl>
:url "<&projectLicenseUrl>"}
- :dependencies [[org.clojure/clojure "1.7.0"]
- [clj-http "3.6.0"]
- [cheshire "5.5.0"]])
+ :dependencies [[org.clojure/clojure "1.9.0"]
+ [metosin/spec-tools "0.7.0"]
+ [clj-http "3.8.0"]
+ [orchestra "2017.11.12-1"]
+ [cheshire "5.8.0"]])
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/clojure/spec.mustache b/modules/openapi-generator/src/main/resources/clojure/spec.mustache
new file mode 100644
index 00000000000..9a4221ad4bc
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/clojure/spec.mustache
@@ -0,0 +1,19 @@
+{{=< >=}}(ns .
+ (:require [clojure.spec.alpha :as s]
+ [spec-tools.data-spec :as ds]
+ <#models><#model><#vars><^isContainer><^vendorExtensions.x-baseSpec>[. :refer :all]
+ <#isContainer><^vendorExtensions.x-baseSpec>[. :refer :all]
+ )
+ (:import (java.io File)))
+
+<#models><#model>
+(def -data
+ {<#vars>
+ (ds/<#required>req<^required>opt :)
+ })
+
+(def -spec
+ (ds/spec
+ {:name ::
+ :spec -data}))
+
\ No newline at end of file
diff --git a/samples/client/petstore/clojure/project.clj b/samples/client/petstore/clojure/project.clj
index 2496800da02..5e9dca8ebf3 100644
--- a/samples/client/petstore/clojure/project.clj
+++ b/samples/client/petstore/clojure/project.clj
@@ -2,6 +2,8 @@
:description "This is a sample server Petstore server. For this sample, you can use the api key \"special-key\" to test the authorization filters"
:license {:name "Apache-2.0"
:url "http://www.apache.org/licenses/LICENSE-2.0.html"}
- :dependencies [[org.clojure/clojure "1.7.0"]
- [clj-http "3.6.0"]
- [cheshire "5.5.0"]])
+ :dependencies [[org.clojure/clojure "1.9.0"]
+ [metosin/spec-tools "0.7.0"]
+ [clj-http "3.8.0"]
+ [orchestra "2017.11.12-1"]
+ [cheshire "5.8.0"]])
\ No newline at end of file
diff --git a/samples/client/petstore/clojure/src/open_api_petstore/api/pet.clj b/samples/client/petstore/clojure/src/open_api_petstore/api/pet.clj
index b0faed710bf..bd1339b46a1 100644
--- a/samples/client/petstore/clojure/src/open_api_petstore/api/pet.clj
+++ b/samples/client/petstore/clojure/src/open_api_petstore/api/pet.clj
@@ -1,11 +1,21 @@
(ns open-api-petstore.api.pet
- (:require [open-api-petstore.core :refer [call-api check-required-params with-collection-format]])
+ (:require [open-api-petstore.core :refer [call-api check-required-params with-collection-format *api-context*]]
+ [clojure.spec.alpha :as s]
+ [spec-tools.core :as st]
+ [orchestra.core :refer [defn-spec]]
+ [open-api-petstore.specs.tag :refer :all]
+ [open-api-petstore.specs.category :refer :all]
+ [open-api-petstore.specs.user :refer :all]
+ [open-api-petstore.specs.pet :refer :all]
+ [open-api-petstore.specs.order :refer :all]
+ )
(:import (java.io File)))
-(defn add-pet-with-http-info
+
+(defn-spec add-pet-with-http-info any?
"Add a new pet to the store"
([] (add-pet-with-http-info nil))
- ([{:keys [pet ]}]
+ ([{:keys [pet]} (s/map-of keyword? any?)]
(call-api "/pet" :post
{:path-params {}
:header-params {}
@@ -16,37 +26,45 @@
:accepts []
:auth-names ["petstore_auth"]})))
-(defn add-pet
+(defn-spec add-pet any?
"Add a new pet to the store"
([] (add-pet nil))
- ([optional-params]
- (:data (add-pet-with-http-info optional-params))))
+ ([optional-params any?]
+ (let [res (:data (add-pet-with-http-info optional-params))]
+ (if (:decode-models *api-context*)
+ (st/decode any? res st/string-transformer)
+ res))))
-(defn delete-pet-with-http-info
+
+(defn-spec delete-pet-with-http-info any?
"Deletes a pet"
- ([pet-id ] (delete-pet-with-http-info pet-id nil))
- ([pet-id {:keys [api-key ]}]
- (check-required-params pet-id)
+ ([petId int?, ] (delete-pet-with-http-info petId nil))
+ ([petId int?, {:keys [api_key]} (s/map-of keyword? any?)]
+ (check-required-params petId)
(call-api "/pet/{petId}" :delete
- {:path-params {"petId" pet-id }
- :header-params {"api_key" api-key }
+ {:path-params {"petId" petId }
+ :header-params {"api_key" api_key }
:query-params {}
:form-params {}
:content-types []
:accepts []
:auth-names ["petstore_auth"]})))
-(defn delete-pet
+(defn-spec delete-pet any?
"Deletes a pet"
- ([pet-id ] (delete-pet pet-id nil))
- ([pet-id optional-params]
- (:data (delete-pet-with-http-info pet-id optional-params))))
+ ([petId int?, ] (delete-pet petId nil))
+ ([petId int?, optional-params any?]
+ (let [res (:data (delete-pet-with-http-info petId optional-params))]
+ (if (:decode-models *api-context*)
+ (st/decode any? res st/string-transformer)
+ res))))
-(defn find-pets-by-status-with-http-info
+
+(defn-spec find-pets-by-status-with-http-info any?
"Finds Pets by status
Multiple status values can be provided with comma separated strings"
([] (find-pets-by-status-with-http-info nil))
- ([{:keys [status ]}]
+ ([{:keys [status]} (s/map-of keyword? any?)]
(call-api "/pet/findByStatus" :get
{:path-params {}
:header-params {}
@@ -56,18 +74,22 @@
:accepts ["application/json" "application/xml"]
:auth-names ["petstore_auth"]})))
-(defn find-pets-by-status
+(defn-spec find-pets-by-status (s/coll-of pet-spec)
"Finds Pets by status
Multiple status values can be provided with comma separated strings"
([] (find-pets-by-status nil))
- ([optional-params]
- (:data (find-pets-by-status-with-http-info optional-params))))
+ ([optional-params any?]
+ (let [res (:data (find-pets-by-status-with-http-info optional-params))]
+ (if (:decode-models *api-context*)
+ (st/decode (s/coll-of pet-spec) res st/string-transformer)
+ res))))
-(defn find-pets-by-tags-with-http-info
+
+(defn-spec find-pets-by-tags-with-http-info any?
"Finds Pets by tags
Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing."
([] (find-pets-by-tags-with-http-info nil))
- ([{:keys [tags ]}]
+ ([{:keys [tags]} (s/map-of keyword? any?)]
(call-api "/pet/findByTags" :get
{:path-params {}
:header-params {}
@@ -77,20 +99,24 @@
:accepts ["application/json" "application/xml"]
:auth-names ["petstore_auth"]})))
-(defn find-pets-by-tags
+(defn-spec find-pets-by-tags (s/coll-of pet-spec)
"Finds Pets by tags
Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing."
([] (find-pets-by-tags nil))
- ([optional-params]
- (:data (find-pets-by-tags-with-http-info optional-params))))
+ ([optional-params any?]
+ (let [res (:data (find-pets-by-tags-with-http-info optional-params))]
+ (if (:decode-models *api-context*)
+ (st/decode (s/coll-of pet-spec) res st/string-transformer)
+ res))))
-(defn get-pet-by-id-with-http-info
+
+(defn-spec get-pet-by-id-with-http-info any?
"Find pet by ID
Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions"
- [pet-id ]
- (check-required-params pet-id)
+ [petId int?]
+ (check-required-params petId)
(call-api "/pet/{petId}" :get
- {:path-params {"petId" pet-id }
+ {:path-params {"petId" petId }
:header-params {}
:query-params {}
:form-params {}
@@ -98,16 +124,20 @@
:accepts ["application/json" "application/xml"]
:auth-names ["api_key" "petstore_auth"]}))
-(defn get-pet-by-id
+(defn-spec get-pet-by-id pet-spec
"Find pet by ID
Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions"
- [pet-id ]
- (:data (get-pet-by-id-with-http-info pet-id)))
+ [petId int?]
+ (let [res (:data (get-pet-by-id-with-http-info petId))]
+ (if (:decode-models *api-context*)
+ (st/decode pet-spec res st/string-transformer)
+ res)))
-(defn update-pet-with-http-info
+
+(defn-spec update-pet-with-http-info any?
"Update an existing pet"
([] (update-pet-with-http-info nil))
- ([{:keys [pet ]}]
+ ([{:keys [pet]} (s/map-of keyword? any?)]
(call-api "/pet" :put
{:path-params {}
:header-params {}
@@ -118,19 +148,23 @@
:accepts []
:auth-names ["petstore_auth"]})))
-(defn update-pet
+(defn-spec update-pet any?
"Update an existing pet"
([] (update-pet nil))
- ([optional-params]
- (:data (update-pet-with-http-info optional-params))))
+ ([optional-params any?]
+ (let [res (:data (update-pet-with-http-info optional-params))]
+ (if (:decode-models *api-context*)
+ (st/decode any? res st/string-transformer)
+ res))))
-(defn update-pet-with-form-with-http-info
+
+(defn-spec update-pet-with-form-with-http-info any?
"Updates a pet in the store with form data"
- ([pet-id ] (update-pet-with-form-with-http-info pet-id nil))
- ([pet-id {:keys [name status ]}]
- (check-required-params pet-id)
+ ([petId string?, ] (update-pet-with-form-with-http-info petId nil))
+ ([petId string?, {:keys [name status]} (s/map-of keyword? any?)]
+ (check-required-params petId)
(call-api "/pet/{petId}" :post
- {:path-params {"petId" pet-id }
+ {:path-params {"petId" petId }
:header-params {}
:query-params {}
:form-params {"name" name "status" status }
@@ -138,29 +172,37 @@
:accepts []
:auth-names ["petstore_auth"]})))
-(defn update-pet-with-form
+(defn-spec update-pet-with-form any?
"Updates a pet in the store with form data"
- ([pet-id ] (update-pet-with-form pet-id nil))
- ([pet-id optional-params]
- (:data (update-pet-with-form-with-http-info pet-id optional-params))))
+ ([petId string?, ] (update-pet-with-form petId nil))
+ ([petId string?, optional-params any?]
+ (let [res (:data (update-pet-with-form-with-http-info petId optional-params))]
+ (if (:decode-models *api-context*)
+ (st/decode any? res st/string-transformer)
+ res))))
-(defn upload-file-with-http-info
+
+(defn-spec upload-file-with-http-info any?
"uploads an image"
- ([pet-id ] (upload-file-with-http-info pet-id nil))
- ([pet-id {:keys [additional-metadata ^File file ]}]
- (check-required-params pet-id)
+ ([petId int?, ] (upload-file-with-http-info petId nil))
+ ([petId int?, {:keys [additionalMetadata ^File file]} (s/map-of keyword? any?)]
+ (check-required-params petId)
(call-api "/pet/{petId}/uploadImage" :post
- {:path-params {"petId" pet-id }
+ {:path-params {"petId" petId }
:header-params {}
:query-params {}
- :form-params {"additionalMetadata" additional-metadata "file" file }
+ :form-params {"additionalMetadata" additionalMetadata "file" file }
:content-types ["multipart/form-data"]
:accepts []
:auth-names ["petstore_auth"]})))
-(defn upload-file
+(defn-spec upload-file any?
"uploads an image"
- ([pet-id ] (upload-file pet-id nil))
- ([pet-id optional-params]
- (:data (upload-file-with-http-info pet-id optional-params))))
+ ([petId int?, ] (upload-file petId nil))
+ ([petId int?, optional-params any?]
+ (let [res (:data (upload-file-with-http-info petId optional-params))]
+ (if (:decode-models *api-context*)
+ (st/decode any? res st/string-transformer)
+ res))))
+
diff --git a/samples/client/petstore/clojure/src/open_api_petstore/api/store.clj b/samples/client/petstore/clojure/src/open_api_petstore/api/store.clj
index 92265329577..a91c086c3fd 100644
--- a/samples/client/petstore/clojure/src/open_api_petstore/api/store.clj
+++ b/samples/client/petstore/clojure/src/open_api_petstore/api/store.clj
@@ -1,14 +1,24 @@
(ns open-api-petstore.api.store
- (:require [open-api-petstore.core :refer [call-api check-required-params with-collection-format]])
+ (:require [open-api-petstore.core :refer [call-api check-required-params with-collection-format *api-context*]]
+ [clojure.spec.alpha :as s]
+ [spec-tools.core :as st]
+ [orchestra.core :refer [defn-spec]]
+ [open-api-petstore.specs.tag :refer :all]
+ [open-api-petstore.specs.category :refer :all]
+ [open-api-petstore.specs.user :refer :all]
+ [open-api-petstore.specs.pet :refer :all]
+ [open-api-petstore.specs.order :refer :all]
+ )
(:import (java.io File)))
-(defn delete-order-with-http-info
+
+(defn-spec delete-order-with-http-info any?
"Delete purchase order by ID
For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors"
- [order-id ]
- (check-required-params order-id)
+ [orderId string?]
+ (check-required-params orderId)
(call-api "/store/order/{orderId}" :delete
- {:path-params {"orderId" order-id }
+ {:path-params {"orderId" orderId }
:header-params {}
:query-params {}
:form-params {}
@@ -16,13 +26,17 @@
:accepts []
:auth-names []}))
-(defn delete-order
+(defn-spec delete-order any?
"Delete purchase order by ID
For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors"
- [order-id ]
- (:data (delete-order-with-http-info order-id)))
+ [orderId string?]
+ (let [res (:data (delete-order-with-http-info orderId))]
+ (if (:decode-models *api-context*)
+ (st/decode any? res st/string-transformer)
+ res)))
-(defn get-inventory-with-http-info
+
+(defn-spec get-inventory-with-http-info any?
"Returns pet inventories by status
Returns a map of status codes to quantities"
[]
@@ -35,19 +49,23 @@
:accepts ["application/json" "application/xml"]
:auth-names ["api_key"]}))
-(defn get-inventory
+(defn-spec get-inventory (s/map-of string? int?)
"Returns pet inventories by status
Returns a map of status codes to quantities"
[]
- (:data (get-inventory-with-http-info)))
+ (let [res (:data (get-inventory-with-http-info))]
+ (if (:decode-models *api-context*)
+ (st/decode (s/map-of string? int?) res st/string-transformer)
+ res)))
-(defn get-order-by-id-with-http-info
+
+(defn-spec get-order-by-id-with-http-info any?
"Find purchase order by ID
For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions"
- [order-id ]
- (check-required-params order-id)
+ [orderId string?]
+ (check-required-params orderId)
(call-api "/store/order/{orderId}" :get
- {:path-params {"orderId" order-id }
+ {:path-params {"orderId" orderId }
:header-params {}
:query-params {}
:form-params {}
@@ -55,16 +73,20 @@
:accepts ["application/json" "application/xml"]
:auth-names []}))
-(defn get-order-by-id
+(defn-spec get-order-by-id order-spec
"Find purchase order by ID
For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions"
- [order-id ]
- (:data (get-order-by-id-with-http-info order-id)))
+ [orderId string?]
+ (let [res (:data (get-order-by-id-with-http-info orderId))]
+ (if (:decode-models *api-context*)
+ (st/decode order-spec res st/string-transformer)
+ res)))
-(defn place-order-with-http-info
+
+(defn-spec place-order-with-http-info any?
"Place an order for a pet"
([] (place-order-with-http-info nil))
- ([{:keys [order ]}]
+ ([{:keys [order]} (s/map-of keyword? any?)]
(call-api "/store/order" :post
{:path-params {}
:header-params {}
@@ -75,9 +97,13 @@
:accepts ["application/json" "application/xml"]
:auth-names []})))
-(defn place-order
+(defn-spec place-order order-spec
"Place an order for a pet"
([] (place-order nil))
- ([optional-params]
- (:data (place-order-with-http-info optional-params))))
+ ([optional-params any?]
+ (let [res (:data (place-order-with-http-info optional-params))]
+ (if (:decode-models *api-context*)
+ (st/decode order-spec res st/string-transformer)
+ res))))
+
diff --git a/samples/client/petstore/clojure/src/open_api_petstore/api/user.clj b/samples/client/petstore/clojure/src/open_api_petstore/api/user.clj
index fe38cf2c495..ee758efedcd 100644
--- a/samples/client/petstore/clojure/src/open_api_petstore/api/user.clj
+++ b/samples/client/petstore/clojure/src/open_api_petstore/api/user.clj
@@ -1,12 +1,22 @@
(ns open-api-petstore.api.user
- (:require [open-api-petstore.core :refer [call-api check-required-params with-collection-format]])
+ (:require [open-api-petstore.core :refer [call-api check-required-params with-collection-format *api-context*]]
+ [clojure.spec.alpha :as s]
+ [spec-tools.core :as st]
+ [orchestra.core :refer [defn-spec]]
+ [open-api-petstore.specs.tag :refer :all]
+ [open-api-petstore.specs.category :refer :all]
+ [open-api-petstore.specs.user :refer :all]
+ [open-api-petstore.specs.pet :refer :all]
+ [open-api-petstore.specs.order :refer :all]
+ )
(:import (java.io File)))
-(defn create-user-with-http-info
+
+(defn-spec create-user-with-http-info any?
"Create user
This can only be done by the logged in user."
([] (create-user-with-http-info nil))
- ([{:keys [user ]}]
+ ([{:keys [user]} (s/map-of keyword? any?)]
(call-api "/user" :post
{:path-params {}
:header-params {}
@@ -17,17 +27,21 @@
:accepts []
:auth-names []})))
-(defn create-user
+(defn-spec create-user any?
"Create user
This can only be done by the logged in user."
([] (create-user nil))
- ([optional-params]
- (:data (create-user-with-http-info optional-params))))
+ ([optional-params any?]
+ (let [res (:data (create-user-with-http-info optional-params))]
+ (if (:decode-models *api-context*)
+ (st/decode any? res st/string-transformer)
+ res))))
-(defn create-users-with-array-input-with-http-info
+
+(defn-spec create-users-with-array-input-with-http-info any?
"Creates list of users with given input array"
([] (create-users-with-array-input-with-http-info nil))
- ([{:keys [user ]}]
+ ([{:keys [user]} (s/map-of keyword? any?)]
(call-api "/user/createWithArray" :post
{:path-params {}
:header-params {}
@@ -38,16 +52,20 @@
:accepts []
:auth-names []})))
-(defn create-users-with-array-input
+(defn-spec create-users-with-array-input any?
"Creates list of users with given input array"
([] (create-users-with-array-input nil))
- ([optional-params]
- (:data (create-users-with-array-input-with-http-info optional-params))))
+ ([optional-params any?]
+ (let [res (:data (create-users-with-array-input-with-http-info optional-params))]
+ (if (:decode-models *api-context*)
+ (st/decode any? res st/string-transformer)
+ res))))
-(defn create-users-with-list-input-with-http-info
+
+(defn-spec create-users-with-list-input-with-http-info any?
"Creates list of users with given input array"
([] (create-users-with-list-input-with-http-info nil))
- ([{:keys [user ]}]
+ ([{:keys [user]} (s/map-of keyword? any?)]
(call-api "/user/createWithList" :post
{:path-params {}
:header-params {}
@@ -58,16 +76,20 @@
:accepts []
:auth-names []})))
-(defn create-users-with-list-input
+(defn-spec create-users-with-list-input any?
"Creates list of users with given input array"
([] (create-users-with-list-input nil))
- ([optional-params]
- (:data (create-users-with-list-input-with-http-info optional-params))))
+ ([optional-params any?]
+ (let [res (:data (create-users-with-list-input-with-http-info optional-params))]
+ (if (:decode-models *api-context*)
+ (st/decode any? res st/string-transformer)
+ res))))
-(defn delete-user-with-http-info
+
+(defn-spec delete-user-with-http-info any?
"Delete user
This can only be done by the logged in user."
- [username ]
+ [username string?]
(check-required-params username)
(call-api "/user/{username}" :delete
{:path-params {"username" username }
@@ -78,15 +100,19 @@
:accepts []
:auth-names []}))
-(defn delete-user
+(defn-spec delete-user any?
"Delete user
This can only be done by the logged in user."
- [username ]
- (:data (delete-user-with-http-info username)))
+ [username string?]
+ (let [res (:data (delete-user-with-http-info username))]
+ (if (:decode-models *api-context*)
+ (st/decode any? res st/string-transformer)
+ res)))
-(defn get-user-by-name-with-http-info
+
+(defn-spec get-user-by-name-with-http-info any?
"Get user by user name"
- [username ]
+ [username string?]
(check-required-params username)
(call-api "/user/{username}" :get
{:path-params {"username" username }
@@ -97,15 +123,19 @@
:accepts ["application/json" "application/xml"]
:auth-names []}))
-(defn get-user-by-name
+(defn-spec get-user-by-name user-spec
"Get user by user name"
- [username ]
- (:data (get-user-by-name-with-http-info username)))
+ [username string?]
+ (let [res (:data (get-user-by-name-with-http-info username))]
+ (if (:decode-models *api-context*)
+ (st/decode user-spec res st/string-transformer)
+ res)))
-(defn login-user-with-http-info
+
+(defn-spec login-user-with-http-info any?
"Logs user into the system"
([] (login-user-with-http-info nil))
- ([{:keys [username password ]}]
+ ([{:keys [username password]} (s/map-of keyword? any?)]
(call-api "/user/login" :get
{:path-params {}
:header-params {}
@@ -115,13 +145,17 @@
:accepts ["application/json" "application/xml"]
:auth-names []})))
-(defn login-user
+(defn-spec login-user string?
"Logs user into the system"
([] (login-user nil))
- ([optional-params]
- (:data (login-user-with-http-info optional-params))))
+ ([optional-params any?]
+ (let [res (:data (login-user-with-http-info optional-params))]
+ (if (:decode-models *api-context*)
+ (st/decode string? res st/string-transformer)
+ res))))
-(defn logout-user-with-http-info
+
+(defn-spec logout-user-with-http-info any?
"Logs out current logged in user session"
[]
(call-api "/user/logout" :get
@@ -133,16 +167,20 @@
:accepts []
:auth-names []}))
-(defn logout-user
+(defn-spec logout-user any?
"Logs out current logged in user session"
[]
- (:data (logout-user-with-http-info)))
+ (let [res (:data (logout-user-with-http-info))]
+ (if (:decode-models *api-context*)
+ (st/decode any? res st/string-transformer)
+ res)))
-(defn update-user-with-http-info
+
+(defn-spec update-user-with-http-info any?
"Updated user
This can only be done by the logged in user."
- ([username ] (update-user-with-http-info username nil))
- ([username {:keys [user ]}]
+ ([username string?, ] (update-user-with-http-info username nil))
+ ([username string?, {:keys [user]} (s/map-of keyword? any?)]
(check-required-params username)
(call-api "/user/{username}" :put
{:path-params {"username" username }
@@ -154,10 +192,14 @@
:accepts []
:auth-names []})))
-(defn update-user
+(defn-spec update-user any?
"Updated user
This can only be done by the logged in user."
- ([username ] (update-user username nil))
- ([username optional-params]
- (:data (update-user-with-http-info username optional-params))))
+ ([username string?, ] (update-user username nil))
+ ([username string?, optional-params any?]
+ (let [res (:data (update-user-with-http-info username optional-params))]
+ (if (:decode-models *api-context*)
+ (st/decode any? res st/string-transformer)
+ res))))
+
diff --git a/samples/client/petstore/clojure/src/open_api_petstore/core.clj b/samples/client/petstore/clojure/src/open_api_petstore/core.clj
index 28993e8b0d6..ef30d6d2516 100644
--- a/samples/client/petstore/clojure/src/open_api_petstore/core.clj
+++ b/samples/client/petstore/clojure/src/open_api_petstore/core.clj
@@ -16,6 +16,7 @@
{:base-url "http://petstore.swagger.io/v2"
:date-format "yyyy-MM-dd"
:datetime-format "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"
+ :decode-models false
:debug false
:auths {"api_key" nil
"petstore_auth" nil}})
diff --git a/samples/client/petstore/clojure/src/open_api_petstore/specs/category.clj b/samples/client/petstore/clojure/src/open_api_petstore/specs/category.clj
new file mode 100644
index 00000000000..21af0a6eeab
--- /dev/null
+++ b/samples/client/petstore/clojure/src/open_api_petstore/specs/category.clj
@@ -0,0 +1,17 @@
+(ns open-api-petstore.specs.category
+ (:require [clojure.spec.alpha :as s]
+ [spec-tools.data-spec :as ds]
+ )
+ (:import (java.io File)))
+
+
+(def category-data
+ {
+ (ds/opt :id) int?
+ (ds/opt :name) string?
+ })
+
+(def category-spec
+ (ds/spec
+ {:name ::category
+ :spec category-data}))
diff --git a/samples/client/petstore/clojure/src/open_api_petstore/specs/order.clj b/samples/client/petstore/clojure/src/open_api_petstore/specs/order.clj
new file mode 100644
index 00000000000..d87391bdf81
--- /dev/null
+++ b/samples/client/petstore/clojure/src/open_api_petstore/specs/order.clj
@@ -0,0 +1,21 @@
+(ns open-api-petstore.specs.order
+ (:require [clojure.spec.alpha :as s]
+ [spec-tools.data-spec :as ds]
+ )
+ (:import (java.io File)))
+
+
+(def order-data
+ {
+ (ds/opt :id) int?
+ (ds/opt :petId) int?
+ (ds/opt :quantity) int?
+ (ds/opt :shipDate) inst?
+ (ds/opt :status) string?
+ (ds/opt :complete) boolean?
+ })
+
+(def order-spec
+ (ds/spec
+ {:name ::order
+ :spec order-data}))
diff --git a/samples/client/petstore/clojure/src/open_api_petstore/specs/pet.clj b/samples/client/petstore/clojure/src/open_api_petstore/specs/pet.clj
new file mode 100644
index 00000000000..cce6965d2f8
--- /dev/null
+++ b/samples/client/petstore/clojure/src/open_api_petstore/specs/pet.clj
@@ -0,0 +1,23 @@
+(ns open-api-petstore.specs.pet
+ (:require [clojure.spec.alpha :as s]
+ [spec-tools.data-spec :as ds]
+ [open-api-petstore.specs.category :refer :all]
+ [open-api-petstore.specs.tag :refer :all]
+ )
+ (:import (java.io File)))
+
+
+(def pet-data
+ {
+ (ds/opt :id) int?
+ (ds/opt :category) category-spec
+ (ds/req :name) string?
+ (ds/req :photoUrls) (s/coll-of string?)
+ (ds/opt :tags) (s/coll-of tag-spec)
+ (ds/opt :status) string?
+ })
+
+(def pet-spec
+ (ds/spec
+ {:name ::pet
+ :spec pet-data}))
diff --git a/samples/client/petstore/clojure/src/open_api_petstore/specs/tag.clj b/samples/client/petstore/clojure/src/open_api_petstore/specs/tag.clj
new file mode 100644
index 00000000000..1f679625825
--- /dev/null
+++ b/samples/client/petstore/clojure/src/open_api_petstore/specs/tag.clj
@@ -0,0 +1,17 @@
+(ns open-api-petstore.specs.tag
+ (:require [clojure.spec.alpha :as s]
+ [spec-tools.data-spec :as ds]
+ )
+ (:import (java.io File)))
+
+
+(def tag-data
+ {
+ (ds/opt :id) int?
+ (ds/opt :name) string?
+ })
+
+(def tag-spec
+ (ds/spec
+ {:name ::tag
+ :spec tag-data}))
diff --git a/samples/client/petstore/clojure/src/open_api_petstore/specs/user.clj b/samples/client/petstore/clojure/src/open_api_petstore/specs/user.clj
new file mode 100644
index 00000000000..cac72a0c72b
--- /dev/null
+++ b/samples/client/petstore/clojure/src/open_api_petstore/specs/user.clj
@@ -0,0 +1,23 @@
+(ns open-api-petstore.specs.user
+ (:require [clojure.spec.alpha :as s]
+ [spec-tools.data-spec :as ds]
+ )
+ (:import (java.io File)))
+
+
+(def user-data
+ {
+ (ds/opt :id) int?
+ (ds/opt :username) string?
+ (ds/opt :firstName) string?
+ (ds/opt :lastName) string?
+ (ds/opt :email) string?
+ (ds/opt :password) string?
+ (ds/opt :phone) string?
+ (ds/opt :userStatus) int?
+ })
+
+(def user-spec
+ (ds/spec
+ {:name ::user
+ :spec user-data}))
diff --git a/samples/client/petstore/clojure/test/open_api_petstore/api/store_test.clj b/samples/client/petstore/clojure/test/open_api_petstore/api/store_test.clj
index 0de8d9c5883..b7f3edc31c2 100644
--- a/samples/client/petstore/clojure/test/open_api_petstore/api/store_test.clj
+++ b/samples/client/petstore/clojure/test/open_api_petstore/api/store_test.clj
@@ -32,3 +32,11 @@
(delete-order order-id)
(comment "it seems that delete-order does not really delete the order"
(is (thrown? RuntimeException (get-order-by-id order-id))))))
+
+(deftest test-order-spec-conforming
+ (with-api-context {:decode-models true}
+ (let [order (make-random-order)
+ order-id (:id order)
+ _ (place-order {:order order})
+ fetched (get-order-by-id order-id)]
+ (is (= order fetched)))))
\ No newline at end of file
diff --git a/samples/client/petstore/clojure/test/open_api_petstore/core_test.clj b/samples/client/petstore/clojure/test/open_api_petstore/core_test.clj
index 6b0487f6088..d3cfcdfdb8b 100644
--- a/samples/client/petstore/clojure/test/open_api_petstore/core_test.clj
+++ b/samples/client/petstore/clojure/test/open_api_petstore/core_test.clj
@@ -9,6 +9,7 @@
(is (= {:base-url "http://petstore.swagger.io/v2"
:date-format "yyyy-MM-dd"
:datetime-format "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"
+ :decode-models false
:debug false
:auths {"api_key" nil
"petstore_auth" nil}}
@@ -24,6 +25,7 @@
(is (= {:base-url "http://localhost"
:date-format "yyyy-MM-dd"
:datetime-format "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"
+ :decode-models false
:debug true
:auths (merge (:auths default-api-context)
{"api_key" "key1"
@@ -35,6 +37,7 @@
(is (= {:base-url "http://localhost"
:date-format "yyyy-MM-dd"
:datetime-format "yyyy-MM-dd HH:mm:ss"
+ :decode-models false
:debug true
:auths (merge (:auths default-api-context)
{"api_key" "key2"
@@ -44,6 +47,7 @@
(is (= {:base-url "http://petstore.swagger.io/v2"
:date-format "yyyy-MM-dd"
:datetime-format "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"
+ :decode-models false
:debug false
:auths {"api_key" nil
"petstore_auth" nil}}