forked from loafle/openapi-generator-original
Generate merge spec (#14387)
This commit is contained in:
parent
0816008f1e
commit
2bc963f00c
@ -32,6 +32,7 @@ import java.util.stream.Stream;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.openapitools.codegen.*;
|
import org.openapitools.codegen.*;
|
||||||
import org.openapitools.codegen.config.CodegenConfigurator;
|
import org.openapitools.codegen.config.CodegenConfigurator;
|
||||||
|
import org.openapitools.codegen.config.MergedSpecBuilder;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -57,6 +58,13 @@ public class Generate extends OpenApiGeneratorCommand {
|
|||||||
description = "location of the OpenAPI spec, as URL or file (required if not loaded via config using -c)")
|
description = "location of the OpenAPI spec, as URL or file (required if not loaded via config using -c)")
|
||||||
private String spec;
|
private String spec;
|
||||||
|
|
||||||
|
@Option(name = "--input-spec-root-directory", title = "Folder with spec(s)",
|
||||||
|
description = "Local root folder with spec file(s)")
|
||||||
|
private String inputSpecRootDirectory;
|
||||||
|
|
||||||
|
@Option(name = "--merged-spec-filename", title = "Name of resulted merged specs file (used along with --input-spec-root-directory option)")
|
||||||
|
private String mergedFileName;
|
||||||
|
|
||||||
@Option(name = {"-t", "--template-dir"}, title = "template directory",
|
@Option(name = {"-t", "--template-dir"}, title = "template directory",
|
||||||
description = "folder containing the template files")
|
description = "folder containing the template files")
|
||||||
private String templateDir;
|
private String templateDir;
|
||||||
@ -283,6 +291,12 @@ public class Generate extends OpenApiGeneratorCommand {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
|
if (StringUtils.isNotBlank(inputSpecRootDirectory)) {
|
||||||
|
spec = new MergedSpecBuilder(inputSpecRootDirectory, StringUtils.isBlank(mergedFileName) ? "_merged_spec" : mergedFileName)
|
||||||
|
.buildMergedSpec();
|
||||||
|
System.out.println("Merge input spec would be used - " + spec);
|
||||||
|
}
|
||||||
|
|
||||||
if (logToStderr != null) {
|
if (logToStderr != null) {
|
||||||
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
|
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||||
Stream.of(Logger.ROOT_LOGGER_NAME, "io.swagger", "org.openapitools")
|
Stream.of(Logger.ROOT_LOGGER_NAME, "io.swagger", "org.openapitools")
|
||||||
|
@ -39,6 +39,7 @@ import org.openapitools.codegen.CodegenConstants
|
|||||||
import org.openapitools.codegen.DefaultGenerator
|
import org.openapitools.codegen.DefaultGenerator
|
||||||
import org.openapitools.codegen.config.CodegenConfigurator
|
import org.openapitools.codegen.config.CodegenConfigurator
|
||||||
import org.openapitools.codegen.config.GlobalSettings
|
import org.openapitools.codegen.config.GlobalSettings
|
||||||
|
import org.openapitools.codegen.config.MergedSpecBuilder
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A task which generates the desired code.
|
* A task which generates the desired code.
|
||||||
@ -96,6 +97,21 @@ open class GenerateTask : DefaultTask() {
|
|||||||
@PathSensitive(PathSensitivity.RELATIVE)
|
@PathSensitive(PathSensitivity.RELATIVE)
|
||||||
val inputSpec = project.objects.property<String>()
|
val inputSpec = project.objects.property<String>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local root folder with spec files
|
||||||
|
*/
|
||||||
|
@Optional
|
||||||
|
@get:InputFile
|
||||||
|
@PathSensitive(PathSensitivity.RELATIVE)
|
||||||
|
val inputSpecRootDirectory = project.objects.property<String>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the file that will contains all merged specs
|
||||||
|
*/
|
||||||
|
@Input
|
||||||
|
@Optional
|
||||||
|
val mergedFileName = project.objects.property<String>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The remote Open API 2.0/3.x specification URL location.
|
* The remote Open API 2.0/3.x specification URL location.
|
||||||
*/
|
*/
|
||||||
@ -527,6 +543,11 @@ open class GenerateTask : DefaultTask() {
|
|||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@TaskAction
|
@TaskAction
|
||||||
fun doWork() {
|
fun doWork() {
|
||||||
|
inputSpecRootDirectory.ifNotEmpty { inputSpecRootDirectoryValue -> {
|
||||||
|
inputSpec.set(MergedSpecBuilder(inputSpecRootDirectoryValue, mergedFileName.get()).buildMergedSpec())
|
||||||
|
logger.info("Merge input spec would be used - {}", inputSpec.get())
|
||||||
|
}}
|
||||||
|
|
||||||
cleanupOutput.ifNotEmpty { cleanup ->
|
cleanupOutput.ifNotEmpty { cleanup ->
|
||||||
if (cleanup) {
|
if (cleanup) {
|
||||||
project.delete(outputDir)
|
project.delete(outputDir)
|
||||||
|
@ -125,8 +125,6 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<swagger-annotations-version>1.5.8</swagger-annotations-version>
|
<swagger-annotations-version>1.5.8</swagger-annotations-version>
|
||||||
|
|
||||||
<spring-boot-starter-web.version>2.2.1.RELEASE</spring-boot-starter-web.version>
|
|
||||||
<springfox-version>2.8.0</springfox-version>
|
<springfox-version>2.8.0</springfox-version>
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
||||||
|
@ -59,6 +59,7 @@ import org.openapitools.codegen.DefaultGenerator;
|
|||||||
import org.openapitools.codegen.auth.AuthParser;
|
import org.openapitools.codegen.auth.AuthParser;
|
||||||
import org.openapitools.codegen.config.CodegenConfigurator;
|
import org.openapitools.codegen.config.CodegenConfigurator;
|
||||||
import org.openapitools.codegen.config.GlobalSettings;
|
import org.openapitools.codegen.config.GlobalSettings;
|
||||||
|
import org.openapitools.codegen.config.MergedSpecBuilder;
|
||||||
import org.sonatype.plexus.build.incremental.BuildContext;
|
import org.sonatype.plexus.build.incremental.BuildContext;
|
||||||
import org.sonatype.plexus.build.incremental.DefaultBuildContext;
|
import org.sonatype.plexus.build.incremental.DefaultBuildContext;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -104,6 +105,18 @@ public class CodeGenMojo extends AbstractMojo {
|
|||||||
@Parameter(name = "inputSpec", property = "openapi.generator.maven.plugin.inputSpec", required = true)
|
@Parameter(name = "inputSpec", property = "openapi.generator.maven.plugin.inputSpec", required = true)
|
||||||
private String inputSpec;
|
private String inputSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local root folder with spec files
|
||||||
|
*/
|
||||||
|
@Parameter(name = "inputSpecRootDirectory", property = "openapi.generator.maven.plugin.inputSpecRootDirectory")
|
||||||
|
private String inputSpecRootDirectory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the file that will contains all merged specs
|
||||||
|
*/
|
||||||
|
@Parameter(name = "mergedFileName", property = "openapi.generator.maven.plugin.mergedFileName", defaultValue = "_merged_spec")
|
||||||
|
private String mergedFileName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Git host, e.g. gitlab.com.
|
* Git host, e.g. gitlab.com.
|
||||||
*/
|
*/
|
||||||
@ -468,6 +481,12 @@ public class CodeGenMojo extends AbstractMojo {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() throws MojoExecutionException {
|
public void execute() throws MojoExecutionException {
|
||||||
|
if (StringUtils.isNotBlank(inputSpecRootDirectory)) {
|
||||||
|
inputSpec = new MergedSpecBuilder(inputSpecRootDirectory, mergedFileName)
|
||||||
|
.buildMergedSpec();
|
||||||
|
LOGGER.info("Merge input spec would be used - {}", inputSpec);
|
||||||
|
}
|
||||||
|
|
||||||
File inputSpecFile = new File(inputSpec);
|
File inputSpecFile = new File(inputSpec);
|
||||||
|
|
||||||
if (output == null) {
|
if (output == null) {
|
||||||
|
@ -0,0 +1,151 @@
|
|||||||
|
package org.openapitools.codegen.config;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
|
import io.swagger.parser.OpenAPIParser;
|
||||||
|
import io.swagger.v3.oas.models.OpenAPI;
|
||||||
|
import io.swagger.v3.parser.core.models.ParseOptions;
|
||||||
|
|
||||||
|
public class MergedSpecBuilder {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(MergedSpecBuilder.class);
|
||||||
|
|
||||||
|
private final String inputSpecRootDirectory;
|
||||||
|
private final String mergeFileName;
|
||||||
|
|
||||||
|
public MergedSpecBuilder(final String rootDirectory, final String mergeFileName) {
|
||||||
|
this.inputSpecRootDirectory = rootDirectory;
|
||||||
|
this.mergeFileName = mergeFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String buildMergedSpec() {
|
||||||
|
deleteMergedFileFromPreviousRun();
|
||||||
|
List<String> specRelatedPaths = getAllSpecFilesInDirectory();
|
||||||
|
if (specRelatedPaths.isEmpty()) {
|
||||||
|
throw new RuntimeException("Spec directory doesn't contains any specification");
|
||||||
|
}
|
||||||
|
LOGGER.info("In spec root directory {} found specs {}", inputSpecRootDirectory, specRelatedPaths);
|
||||||
|
|
||||||
|
String openapiVersion = null;
|
||||||
|
boolean isJson = false;
|
||||||
|
ParseOptions options = new ParseOptions();
|
||||||
|
options.setResolve(true);
|
||||||
|
List<SpecWithPaths> allPaths = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String specRelatedPath : specRelatedPaths) {
|
||||||
|
String specPath = inputSpecRootDirectory + File.separator + specRelatedPath;
|
||||||
|
try {
|
||||||
|
LOGGER.info("Reading spec: {}", specPath);
|
||||||
|
|
||||||
|
OpenAPI result = new OpenAPIParser()
|
||||||
|
.readLocation(specPath, new ArrayList<>(), options)
|
||||||
|
.getOpenAPI();
|
||||||
|
|
||||||
|
if (openapiVersion == null) {
|
||||||
|
openapiVersion = result.getOpenapi();
|
||||||
|
if (specRelatedPath.toLowerCase(Locale.ROOT).endsWith(".json")) {
|
||||||
|
isJson = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allPaths.add(new SpecWithPaths(specRelatedPath, result.getPaths().keySet()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("Failed to read file: {}. It would be ignored", specPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> mergedSpec = generatedMergedSpec(openapiVersion, allPaths);
|
||||||
|
String mergedFilename = this.mergeFileName + (isJson ? ".json" : ".yaml");
|
||||||
|
Path mergedFilePath = Paths.get(inputSpecRootDirectory, mergedFilename);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ObjectMapper objectMapper = isJson ? new ObjectMapper() : new ObjectMapper(new YAMLFactory());
|
||||||
|
Files.write(mergedFilePath, objectMapper.writeValueAsBytes(mergedSpec), StandardOpenOption.CREATE, StandardOpenOption.WRITE);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mergedFilePath.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Object> generatedMergedSpec(String openapiVersion, List<SpecWithPaths> allPaths) {
|
||||||
|
Map<String, Object> spec = generateHeader(openapiVersion);
|
||||||
|
Map<String, Object> paths = new HashMap<>();
|
||||||
|
spec.put("paths", paths);
|
||||||
|
|
||||||
|
for(SpecWithPaths specWithPaths : allPaths) {
|
||||||
|
for (String path : specWithPaths.paths) {
|
||||||
|
String specRelatedPath = "./" + specWithPaths.specRelatedPath + "#/paths/" + path.replace("/", "~1");
|
||||||
|
paths.put(path, ImmutableMap.of(
|
||||||
|
"$ref", specRelatedPath
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Object> generateHeader(String openapiVersion) {
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
map.put("openapi", openapiVersion);
|
||||||
|
map.put("info", ImmutableMap.of(
|
||||||
|
"title", "merged spec",
|
||||||
|
"description", "merged spec",
|
||||||
|
"version", "1.0.0"
|
||||||
|
));
|
||||||
|
map.put("servers", Collections.singleton(
|
||||||
|
ImmutableMap.of("url", "http://localhost:8080")
|
||||||
|
));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getAllSpecFilesInDirectory() {
|
||||||
|
Path rootDirectory = new File(inputSpecRootDirectory).toPath();
|
||||||
|
try {
|
||||||
|
return Files.walk(rootDirectory)
|
||||||
|
.filter(path -> !Files.isDirectory(path))
|
||||||
|
.map(path -> rootDirectory.relativize(path).toString())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Exception while listing files in spec root directory: " + inputSpecRootDirectory, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteMergedFileFromPreviousRun() {
|
||||||
|
try {
|
||||||
|
Files.deleteIfExists(Paths.get(inputSpecRootDirectory + File.separator + mergeFileName + ".json"));
|
||||||
|
} catch (IOException e) { }
|
||||||
|
try {
|
||||||
|
Files.deleteIfExists(Paths.get(inputSpecRootDirectory + File.separator + mergeFileName + ".yaml"));
|
||||||
|
} catch (IOException e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SpecWithPaths {
|
||||||
|
private final String specRelatedPath;
|
||||||
|
private final Set<String> paths;
|
||||||
|
|
||||||
|
private SpecWithPaths(final String specRelatedPath, final Set<String> paths) {
|
||||||
|
this.specRelatedPath = specRelatedPath;
|
||||||
|
this.paths = paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
package org.openapitools.codegen.config;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.openapitools.codegen.ClientOptInput;
|
||||||
|
import org.openapitools.codegen.DefaultGenerator;
|
||||||
|
import org.openapitools.codegen.java.assertions.JavaFileAssert;
|
||||||
|
import org.openapitools.codegen.languages.SpringCodegen;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
|
import io.swagger.parser.OpenAPIParser;
|
||||||
|
import io.swagger.v3.oas.models.OpenAPI;
|
||||||
|
import io.swagger.v3.parser.core.models.ParseOptions;
|
||||||
|
|
||||||
|
public class MergedSpecBuilderTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldMergeYamlSpecs() throws IOException {
|
||||||
|
mergeSpecs("yaml");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldMergeJsonSpecs() throws IOException {
|
||||||
|
mergeSpecs("json");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mergeSpecs(String fileExt) throws IOException {
|
||||||
|
File output = Files.createTempDirectory("spec-directory").toFile().getCanonicalFile();
|
||||||
|
output.deleteOnExit();
|
||||||
|
|
||||||
|
Files.copy(Paths.get("src/test/resources/bugs/mergerTest/spec1." + fileExt), output.toPath().resolve("spec1." + fileExt));
|
||||||
|
Files.copy(Paths.get("src/test/resources/bugs/mergerTest/spec2." + fileExt), output.toPath().resolve("spec2." + fileExt));
|
||||||
|
|
||||||
|
String outputPath = output.getAbsolutePath().replace('\\', '/');
|
||||||
|
|
||||||
|
String mergedSpec = new MergedSpecBuilder(outputPath, "_merged_file")
|
||||||
|
.buildMergedSpec();
|
||||||
|
|
||||||
|
assertFilesFromMergedSpec(mergedSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertFilesFromMergedSpec(String mergedSpec) throws IOException {
|
||||||
|
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
|
||||||
|
output.deleteOnExit();
|
||||||
|
|
||||||
|
ParseOptions parseOptions = new ParseOptions();
|
||||||
|
parseOptions.setResolve(true);
|
||||||
|
OpenAPI openAPI = new OpenAPIParser()
|
||||||
|
.readLocation(mergedSpec, null, parseOptions).getOpenAPI();
|
||||||
|
|
||||||
|
SpringCodegen codegen = new SpringCodegen();
|
||||||
|
codegen.setOutputDir(output.getAbsolutePath());
|
||||||
|
|
||||||
|
ClientOptInput input = new ClientOptInput();
|
||||||
|
input.openAPI(openAPI);
|
||||||
|
input.config(codegen);
|
||||||
|
|
||||||
|
DefaultGenerator generator = new DefaultGenerator();
|
||||||
|
Map<String, File> files = generator.opts(input).generate().stream()
|
||||||
|
.collect(Collectors.toMap(File::getName, Function.identity()));
|
||||||
|
|
||||||
|
JavaFileAssert.assertThat(files.get("Spec1Api.java"))
|
||||||
|
.assertMethod("spec1Operation").hasReturnType("ResponseEntity<Spec1Model>")
|
||||||
|
|
||||||
|
.toFileAssert()
|
||||||
|
|
||||||
|
.assertMethod("spec1OperationComplex")
|
||||||
|
.hasReturnType("ResponseEntity<Spec1Model>")
|
||||||
|
.assertMethodAnnotations()
|
||||||
|
.containsWithNameAndAttributes("RequestMapping", ImmutableMap.of("value", "\"/spec1/complex/{param1}/path\""))
|
||||||
|
.toMethod()
|
||||||
|
.hasParameter("param1")
|
||||||
|
.withType("String")
|
||||||
|
.assertParameterAnnotations()
|
||||||
|
.containsWithNameAndAttributes("PathVariable", ImmutableMap.of("value", "\"param1\""));
|
||||||
|
|
||||||
|
JavaFileAssert.assertThat(files.get("Spec2Api.java"))
|
||||||
|
.assertMethod("spec2Operation").hasReturnType("ResponseEntity<Spec2Model>");
|
||||||
|
|
||||||
|
JavaFileAssert.assertThat(files.get("Spec1Model.java"))
|
||||||
|
.assertMethod("getSpec1Field").hasReturnType("String");
|
||||||
|
|
||||||
|
JavaFileAssert.assertThat(files.get("Spec2Model.java"))
|
||||||
|
.assertMethod("getSpec2Field").hasReturnType("BigDecimal");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"openapi": "3.0.3",
|
||||||
|
"info": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Specification to reproduce nullable issue with Array",
|
||||||
|
"title": "ArrayNullableTest Api"
|
||||||
|
},
|
||||||
|
"paths": {
|
||||||
|
"/spec1": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"spec1"
|
||||||
|
],
|
||||||
|
"summary": "dummy",
|
||||||
|
"operationId": "spec1Operation",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/Spec1Model"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/spec1/complex/{param1}/path": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"spec1"
|
||||||
|
],
|
||||||
|
"summary": "dummy",
|
||||||
|
"operationId": "spec1OperationComplex",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "param1",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/Spec1Model"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"schemas": {
|
||||||
|
"Spec1Model": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"spec1Field": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
openapi: 3.0.3
|
||||||
|
info:
|
||||||
|
version: 1.0.0
|
||||||
|
description: Specification to reproduce nullable issue with Array
|
||||||
|
title: ArrayNullableTest Api
|
||||||
|
paths:
|
||||||
|
/spec1:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- spec1
|
||||||
|
summary: dummy
|
||||||
|
operationId: spec1Operation
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Spec1Model'
|
||||||
|
/spec1/complex/{param1}/path:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- spec1
|
||||||
|
summary: dummy
|
||||||
|
operationId: spec1OperationComplex
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: param1
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Spec1Model'
|
||||||
|
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
Spec1Model:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec1Field:
|
||||||
|
type: string
|
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"openapi": "3.0.3",
|
||||||
|
"info": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Specification to reproduce nullable issue with Array",
|
||||||
|
"title": "ArrayNullableTest Api"
|
||||||
|
},
|
||||||
|
"paths": {
|
||||||
|
"/spec2": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"spec2"
|
||||||
|
],
|
||||||
|
"summary": "dummy",
|
||||||
|
"operationId": "spec2Operation",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/Spec2Model"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"schemas": {
|
||||||
|
"Spec2Model": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"spec2Field": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
openapi: 3.0.3
|
||||||
|
info:
|
||||||
|
version: 1.0.0
|
||||||
|
description: Specification to reproduce nullable issue with Array
|
||||||
|
title: ArrayNullableTest Api
|
||||||
|
paths:
|
||||||
|
/spec2:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- spec2
|
||||||
|
summary: dummy
|
||||||
|
operationId: spec2Operation
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Spec2Model'
|
||||||
|
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
Spec2Model:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec2Field:
|
||||||
|
type: number
|
Loading…
x
Reference in New Issue
Block a user