Skip to content
This repository was archived by the owner on Dec 25, 2024. It is now read-only.

Commit c54b632

Browse files
committed
v3 simplifies validation (#185)
* Schema mixnins and base classes removed, validate added, output classes written for dict + tuple types * Updates passed types in api_client and api_response * Does not run validation twice for unstances of ouput clas for object and array * Adds tests that verify that array and object validations are not run twice * Fixes schema ouput class instantiation to use super new * Renames two new templates to validate * Renames two last new templates to _helper_prefix_ref_property_value_type + _helper_prefix_property_value_type * Removes two unused templates * Adds new method to array output class * Adds new method to object output classes * Adds test_dict_validate_using_output_class * Adds test_list_validate_using_output_class * Replaces immutabledict.immutabledict with schemas.immutabledict * Removes unneeded init methods for dict output classes * Removes unneeded immutabledict imports * Fixes operation code samples in docs * Silences schema not found warnings * Adds requestBodySchemas to codegenOperation * Updates RequestBodySchemas jsonPathPiece names * Adds request body schema imports * Shortens request body schema imports in operation.py * Reverts content schema imports to be direct * Fixes response ApiRespinse body definition * Removes content and content type init imports * Fixes testResponseWithNoSchemaInHeaders * Fixes bug in detecting param required that broke two java tests * Samples regenerated * Fixes test of noncomplintdisc sample * Fixes some tests * Fixes path test validate typo * Allows int or float into int schemas because values like 1.0 need to be accepted * Adds Bool class and uses it during validation only * Fixes the last of the unit test sample tests * Samples updated * Fixes two python tests * Fixes last broken test in petstore
1 parent 413fbd6 commit c54b632

File tree

1,968 files changed

+32252
-41658
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,968 files changed

+32252
-41658
lines changed

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/DefaultCodegen.java

+193-67
Large diffs are not rendered by default.

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/DefaultGenerator.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -581,8 +581,10 @@ private void generateContent(List<File> files, LinkedHashMap<CodegenKey, Codegen
581581
String templateFile = contentTypeEntry.getKey();
582582
String outputFile = contentTypeEntry.getValue();
583583
String outputFilepath = config.getFilepath(contentTypeJsonPath) + File.separatorChar + outputFile;
584+
HashMap<String, Object> contentTypeTemplateData = new HashMap<>();
585+
contentTypeTemplateData.put("schema", schema);
584586
try {
585-
File written = processTemplateToFile(new HashMap<>(), templateFile, outputFilepath, true, CodegenConstants.CONTENT);
587+
File written = processTemplateToFile(contentTypeTemplateData, templateFile, outputFilepath, true, CodegenConstants.CONTENT);
586588
if (written != null) {
587589
files.add(written);
588590
if (config.isEnablePostProcessFile() && !dryRun) {
@@ -602,8 +604,10 @@ private void generateContent(List<File> files, LinkedHashMap<CodegenKey, Codegen
602604
String contentTemplateFile = contentEntry.getKey();
603605
String outputFile = contentEntry.getValue();
604606
String outputFilepath = config.getFilepath(contentJsonPath) + File.separatorChar + outputFile;
607+
HashMap<String, Object> contentTemplateData = new HashMap<>();
608+
contentTemplateData.put("content", content);
605609
try {
606-
File written = processTemplateToFile(new HashMap<>(), contentTemplateFile, outputFilepath, true, CodegenConstants.CONTENT);
610+
File written = processTemplateToFile(contentTemplateData, contentTemplateFile, outputFilepath, true, CodegenConstants.CONTENT);
607611
if (written != null) {
608612
files.add(written);
609613
if (config.isEnablePostProcessFile() && !dryRun) {

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/languages/AbstractPythonCodegen.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public AbstractPythonCodegen() {
6969
"False", "async", "await",
7070
// imports, imports_schema_types.handlebars, include these to prevent name collision
7171
"datetime", "decimal", "functools", "io", "re",
72-
"typing", "typing_extensions", "uuid", "frozendict", "schemas"
72+
"typing", "typing_extensions", "uuid", "immutabledict", "schemas"
7373
));
7474

7575
languageSpecificPrimitives.clear();

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/languages/PythonClientCodegen.java

+85-19
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ public PythonClientCodegen() {
257257
"return", "def", "for", "lambda", "try", "self", "nonlocal", "None", "True",
258258
"False", "async", "await",
259259
// types
260-
"float", "int", "str", "bool", "dict", "frozendict", "list", "tuple"));
260+
"float", "int", "str", "bool", "dict", "immutabledict", "list", "tuple"));
261261

262262
regexModifiers = new HashMap<>();
263263
regexModifiers.put('i', "IGNORECASE");
@@ -310,13 +310,13 @@ public PythonClientCodegen() {
310310
GlobalSettings.setProperty("x-disallow-additional-properties-if-not-present", "false");
311311

312312
// this tells users what openapi types turn in to
313-
instantiationTypes.put("object", "frozendict.frozendict");
313+
instantiationTypes.put("object", "immutabledict.immutabledict");
314314
instantiationTypes.put("array", "tuple");
315315
instantiationTypes.put("string", "str");
316-
instantiationTypes.put("number", "decimal.Decimal");
317-
instantiationTypes.put("integer", "decimal.Decimal");
318-
instantiationTypes.put("boolean", "schemas.BoolClass");
319-
instantiationTypes.put("null", "schemas.NoneClass");
316+
instantiationTypes.put("number", "typing.Union[float, int]");
317+
instantiationTypes.put("integer", "int");
318+
instantiationTypes.put("boolean", "bool");
319+
instantiationTypes.put("null", "None");
320320

321321
languageSpecificPrimitives.add("file_type");
322322
languageSpecificPrimitives.add("none_type");
@@ -722,7 +722,11 @@ public void processOpts() {
722722
supportingFiles.add(new SupportingFile("api_client.hbs", packagePath(), "api_client.py"));
723723
supportingFiles.add(new SupportingFile("api_response.hbs", packagePath(), "api_response.py"));
724724
supportingFiles.add(new SupportingFile("rest.hbs", packagePath(), "rest.py"));
725-
supportingFiles.add(new SupportingFile("schemas.hbs", packagePath(), "schemas.py"));
725+
supportingFiles.add(new SupportingFile("schemas/__init__.hbs", packagePath() + File.separator + "schemas", "__init__.py"));
726+
supportingFiles.add(new SupportingFile("schemas/validation.hbs", packagePath() + File.separator + "schemas", "validation.py"));
727+
supportingFiles.add(new SupportingFile("schemas/schema.hbs", packagePath() + File.separator + "schemas", "schema.py"));
728+
supportingFiles.add(new SupportingFile("schemas/schemas.hbs", packagePath() + File.separator + "schemas", "schemas.py"));
729+
supportingFiles.add(new SupportingFile("schemas/format.hbs", packagePath() + File.separator + "schemas", "format.py"));
726730
supportingFiles.add(new SupportingFile("security_schemes.hbs", packagePath(), "security_schemes.py"));
727731
supportingFiles.add(new SupportingFile("server.hbs", packagePath(), "server.py"));
728732

@@ -1299,10 +1303,16 @@ private String toExampleValueRecursive(String modelName, Schema schema, Object o
12991303
}
13001304
if (null != schema.get$ref()) {
13011305
Map<String, Schema> allDefinitions = ModelUtils.getSchemas(this.openAPI);
1302-
String ref = ModelUtils.getSimpleRef(schema.get$ref());
1306+
String refValue = schema.get$ref();
1307+
String ref = ModelUtils.getSimpleRef(refValue);
13031308
Schema refSchema = allDefinitions.get(ref);
13041309
if (null == refSchema) {
1305-
LOGGER.warn("Unable to find referenced schema " + schema.get$ref() + "\n");
1310+
if (refValue.startsWith("#/components/schemas/")) {
1311+
LOGGER.warn("Unable to find referenced schema " + refValue + "\n");
1312+
}
1313+
// TODO get examples working for refs like
1314+
// #/paths/~1fake~1parameterCollisions~1{1}~1{aB}~1{Ab}~1{self}~1{A-B}~1/post/parameters/5/schema
1315+
// #/components/responses/SuccessInlineContentAndHeader/headers/someHeader/schema
13061316
return fullPrefix + "None" + closeChars;
13071317
}
13081318
String refModelName = getRefClassWithRefModule(schema);
@@ -1858,15 +1868,6 @@ public Map<String, Object> postProcessSupportingFileData(Map<String, Object> dat
18581868
return data;
18591869
}
18601870

1861-
@Override
1862-
protected String getImport(String className, CodegenSchema schema) {
1863-
if (className == null) {
1864-
return "from " + packageName() + ".components.schema import " + schema.refInfo.refModule;
1865-
}
1866-
String[] classPieces = className.split("\\.");
1867-
return "from " + packageName() + ".components.schema import " + classPieces[0];
1868-
}
1869-
18701871
@Override
18711872
protected String getRefClassWithModule(String ref, String sourceJsonPath) {
18721873
String refModule = toRefModule(ref, sourceJsonPath, "schemas");
@@ -1961,14 +1962,79 @@ private String toSchemaRefClass(String ref, String sourceJsonPath) {
19611962
if (sourceJsonPath != null && ref.startsWith(sourceJsonPath + "/")) {
19621963
// internal in-schema reference, no import needed
19631964
// TODO handle this in the future
1964-
return null;
1965+
if (getFilepath(sourceJsonPath).equals(getFilepath(ref))) {
1966+
// TODO ensure that getFilepath returns the same file for somePath/get/QueryParameters
1967+
// TODO ensure that getFilepath returns the same file for schemas/SomeSchema...
1968+
return null;
1969+
}
19651970
}
19661971
// reference is external, import needed
19671972
// module info is stored in refModule
19681973
if (ref.startsWith("#/components/schemas/") && refPieces.length == 4) {
19691974
String schemaName = refPieces[3];
19701975
return toModelName(schemaName, ref);
19711976
}
1977+
if (ref.startsWith("#/components/parameters/")) {
1978+
if (refPieces.length == 5) {
1979+
// #/components/parameters/PathUserName/schema
1980+
String schemaName = refPieces[4];
1981+
return toModelName(schemaName, ref);
1982+
}
1983+
if (refPieces.length == 7) {
1984+
// #/components/parameters/PathUserName/content/mediaType/schema
1985+
String schemaName = refPieces[6];
1986+
return toModelName(schemaName, ref);
1987+
}
1988+
}
1989+
if (ref.startsWith("#/components/headers/")) {
1990+
if (refPieces.length == 5) {
1991+
// #/components/headers/Int32JsonContentTypeHeader/schema
1992+
String schemaName = refPieces[4];
1993+
return toModelName(schemaName, ref);
1994+
}
1995+
if (refPieces.length == 7) {
1996+
// #/components/headers/Int32JsonContentTypeHeader/content/application~1json/schema
1997+
String schemaName = refPieces[6];
1998+
return toModelName(schemaName, ref);
1999+
}
2000+
}
2001+
if (ref.startsWith("#/components/responses/")) {
2002+
if (refPieces.length == 7) {
2003+
// #/components/responses/SuccessInlineContentAndHeader/headers/someHeader/schema
2004+
String schemaName = refPieces[6];
2005+
return toModelName(schemaName, ref);
2006+
}
2007+
if (refPieces.length == 9) {
2008+
// #/components/responses/SuccessInlineContentAndHeader/headers/someHeader/content/application~1json/schema
2009+
String schemaName = refPieces[8];
2010+
return toModelName(schemaName, ref);
2011+
}
2012+
}
2013+
if (ref.startsWith("#/paths/")) {
2014+
if (refPieces.length == 7) {
2015+
// #/paths/~1pet~1{petId}/get/parameters/0/schema
2016+
String schemaName = refPieces[6];
2017+
return toModelName(schemaName, ref);
2018+
} else if (refPieces.length == 8) {
2019+
// #/paths/~1user~1login/get/responses/200/headers/X-Rate-Limit/schema
2020+
String schemaName = refPieces[7];
2021+
return toModelName(schemaName, ref);
2022+
} else if (refPieces.length == 9) {
2023+
// #/paths/~1pet~1{petId}/get/parameters/0/content/mediaType/schema
2024+
// #/paths/~1user~1login/get/responses/200/headers/X-Rate-Limit/schema
2025+
String schemaName = refPieces[8];
2026+
return toModelName(schemaName, ref);
2027+
} else if (refPieces.length == 10) {
2028+
// #/paths/~1user~1login/get/responses/200/headers/X-Rate-Limit/content/application~1json/schema
2029+
String schemaName = refPieces[9];
2030+
return toModelName(schemaName, ref);
2031+
} else if (refPieces.length == 11) {
2032+
// #/paths/~1user~1login/get/responses/200/headers/X-Rate-Limit/content/application~1json/schema
2033+
String schemaName = refPieces[10];
2034+
return toModelName(schemaName, ref);
2035+
}
2036+
2037+
}
19722038
return null;
19732039
}
19742040

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/model/CodegenHeader.java

+25
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,31 @@ public CodegenHeader(String description, String unescapedDescription, String exa
6262
this.refInfo = refInfo;
6363
}
6464

65+
public CodegenHeader getSelfOrDeepestRef() {
66+
CodegenHeader selfOrRefParam = this;
67+
while (selfOrRefParam.refInfo != null) {
68+
selfOrRefParam = selfOrRefParam.refInfo.ref;
69+
}
70+
return selfOrRefParam;
71+
}
72+
73+
public String getSchemaJsonPath() {
74+
CodegenHeader selfOrRefParam = this;
75+
while (selfOrRefParam.refInfo != null) {
76+
selfOrRefParam = selfOrRefParam.refInfo.ref;
77+
}
78+
// parameter is now de-referenced
79+
CodegenSchema schema = null;
80+
if (selfOrRefParam.schema != null) {
81+
schema = selfOrRefParam.schema;
82+
} else {
83+
CodegenKey contentTypeKey = selfOrRefParam.content.keySet().iterator().next();
84+
schema = selfOrRefParam.content.get(contentTypeKey).schema;
85+
}
86+
schema = schema.getSelfOrDeepestRef();
87+
return schema.jsonPath;
88+
}
89+
6590
@Override
6691
public int hashCode() {
6792
return Objects.hash(jsonPathPiece, explode, description, unescapedDescription, style, example, vendorExtensions, deprecated, required, schema, content, refInfo, imports, componentModule);

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/model/CodegenOperation.java

+14-54
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,16 @@ public class CodegenOperation {
3030
public final LinkedHashSet<String> produces;
3131
public final List<CodegenServer> servers;
3232
public final CodegenRequestBody requestBody;
33+
public final List<CodegenSchema> requestBodySchemas;
3334
public final List<CodegenParameter> allParams;
3435
public final List<CodegenParameter> pathParams;
35-
public final boolean hasRequiredPathParams;
36+
public final CodegenSchema pathParameters;
3637
public final List<CodegenParameter> queryParams;
37-
public final boolean hasRequiredQueryParams;
38+
public final CodegenSchema queryParameters;
3839
public final List<CodegenParameter> headerParams;
39-
public final boolean hasRequiredHeaderParams;
40+
public final CodegenSchema headerParameters;
4041
public final List<CodegenParameter> cookieParams;
41-
public final boolean hasRequiredCookieParams;
42+
public final CodegenSchema cookieParameters;
4243
public final boolean hasRequiredParamOrBody;
4344
public final boolean hasOptionalParamOrBody;
4445
public final List<HashMap<String, CodegenSecurityRequirementValue>> security;
@@ -54,7 +55,7 @@ public class CodegenOperation {
5455
public final CodegenKey operationId;
5556
public final CodegenKey jsonPathPiece;
5657

57-
public CodegenOperation(Boolean deprecated, boolean hasErrorResponseObject, String summary, String unescapedDescription, String description, LinkedHashSet<String> produces, List<CodegenServer> servers, CodegenRequestBody requestBody, List<CodegenParameter> allParams, List<CodegenParameter> pathParams, List<CodegenParameter> queryParams, List<CodegenParameter> headerParams, List<CodegenParameter> cookieParams, boolean hasRequiredParamOrBody, boolean hasOptionalParamOrBody, List<HashMap<String, CodegenSecurityRequirementValue>> security, Map<String, CodegenTag> tags, TreeMap<String, CodegenResponse> responses, TreeMap<Integer, CodegenResponse> statusCodeResponses, TreeMap<Integer, CodegenResponse> wildcardCodeResponses, TreeMap<String, CodegenResponse> nonDefaultResponses, CodegenResponse defaultResponse, List<CodegenCallback> callbacks, ExternalDocumentation externalDocs, Map<String, Object> vendorExtensions, CodegenKey operationId, CodegenKey jsonPathPiece) {
58+
public CodegenOperation(Boolean deprecated, boolean hasErrorResponseObject, String summary, String unescapedDescription, String description, LinkedHashSet<String> produces, List<CodegenServer> servers, CodegenRequestBody requestBody, List<CodegenSchema> requestBodySchemas, List<CodegenParameter> allParams, List<CodegenParameter> pathParams, CodegenSchema pathParameters, List<CodegenParameter> queryParams, CodegenSchema queryParameters, List<CodegenParameter> headerParams, CodegenSchema headerParameters, List<CodegenParameter> cookieParams, CodegenSchema cookieParameters, boolean hasRequiredParamOrBody, boolean hasOptionalParamOrBody, List<HashMap<String, CodegenSecurityRequirementValue>> security, Map<String, CodegenTag> tags, TreeMap<String, CodegenResponse> responses, TreeMap<Integer, CodegenResponse> statusCodeResponses, TreeMap<Integer, CodegenResponse> wildcardCodeResponses, TreeMap<String, CodegenResponse> nonDefaultResponses, CodegenResponse defaultResponse, List<CodegenCallback> callbacks, ExternalDocumentation externalDocs, Map<String, Object> vendorExtensions, CodegenKey operationId, CodegenKey jsonPathPiece) {
5859
this.deprecated = deprecated;
5960
this.hasErrorResponseObject = hasErrorResponseObject;
6061
this.summary = summary;
@@ -63,59 +64,16 @@ public CodegenOperation(Boolean deprecated, boolean hasErrorResponseObject, Stri
6364
this.produces = produces;
6465
this.servers = servers;
6566
this.requestBody = requestBody;
67+
this.requestBodySchemas = requestBodySchemas;
6668
this.allParams = allParams;
6769
this.pathParams = pathParams;
68-
if (pathParams == null) {
69-
this.hasRequiredPathParams = false;
70-
} else {
71-
boolean val = false;
72-
for (CodegenParameter p: pathParams) {
73-
if (Boolean.TRUE.equals(p.required)) {
74-
val = true;
75-
break;
76-
}
77-
}
78-
this.hasRequiredPathParams = val;
79-
}
70+
this.pathParameters = pathParameters;
8071
this.queryParams = queryParams;
81-
if (queryParams == null) {
82-
this.hasRequiredQueryParams = false;
83-
} else {
84-
boolean val = false;
85-
for (CodegenParameter p: queryParams) {
86-
if (Boolean.TRUE.equals(p.required)) {
87-
val = true;
88-
break;
89-
}
90-
}
91-
this.hasRequiredQueryParams = val;
92-
}
72+
this.queryParameters = queryParameters;
9373
this.headerParams = headerParams;
94-
if (headerParams == null) {
95-
this.hasRequiredHeaderParams = false;
96-
} else {
97-
boolean val = false;
98-
for (CodegenParameter p: headerParams) {
99-
if (Boolean.TRUE.equals(p.required)) {
100-
val = true;
101-
break;
102-
}
103-
}
104-
this.hasRequiredHeaderParams = val;
105-
}
74+
this.headerParameters = headerParameters;
10675
this.cookieParams = cookieParams;
107-
if (cookieParams == null) {
108-
this.hasRequiredCookieParams = false;
109-
} else {
110-
boolean val = false;
111-
for (CodegenParameter p: cookieParams) {
112-
if (Boolean.TRUE.equals(p.required)) {
113-
val = true;
114-
break;
115-
}
116-
}
117-
this.hasRequiredCookieParams = val;
118-
}
76+
this.cookieParameters = cookieParameters;
11977
this.hasRequiredParamOrBody = hasRequiredParamOrBody;
12078
this.hasOptionalParamOrBody = hasOptionalParamOrBody;
12179
this.security = security;
@@ -221,6 +179,7 @@ public String toString() {
221179
sb.append(", produces=").append(produces);
222180
sb.append(", servers=").append(servers);
223181
sb.append(", requestBody=").append(requestBody);
182+
sb.append(", requestBodySchemas=").append(requestBodySchemas);
224183
sb.append(", allParams=").append(allParams);
225184
sb.append(", pathParams=").append(pathParams);
226185
sb.append(", queryParams=").append(queryParams);
@@ -256,6 +215,7 @@ public boolean equals(Object o) {
256215
Objects.equals(produces, that.produces) &&
257216
Objects.equals(servers, that.servers) &&
258217
Objects.equals(requestBody, that.requestBody) &&
218+
Objects.equals(requestBodySchemas, that.requestBodySchemas) &&
259219
Objects.equals(allParams, that.allParams) &&
260220
Objects.equals(pathParams, that.pathParams) &&
261221
Objects.equals(queryParams, that.queryParams) &&
@@ -280,7 +240,7 @@ public int hashCode() {
280240

281241
return Objects.hash(deprecated, operationId,
282242
summary, unescapedDescription, description, defaultResponse,
283-
produces, servers, requestBody, allParams,
243+
produces, servers, requestBody, requestBodySchemas, allParams,
284244
pathParams, queryParams, headerParams, cookieParams, hasRequiredParamOrBody, hasOptionalParamOrBody,
285245
security, tags, responses, callbacks, externalDocs,
286246
vendorExtensions, statusCodeResponses, wildcardCodeResponses,

0 commit comments

Comments
 (0)