[core][gradle] User-defined server variable substitutions (#3363)

* [core] Initial support for server variable overrides
* [gradle] Support user overrides for serverVariables
* [core] Clarify server variable overrides, and propagate them to templates in the "servers" array
This commit is contained in:
Jim Schubert 2019-08-11 09:57:36 -04:00 committed by GitHub
parent 07381e7275
commit 06533b977c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 305 additions and 101 deletions

View File

@ -449,7 +449,6 @@ NAME
SYNOPSIS SYNOPSIS
openapi-generator-cli generate openapi-generator-cli generate
[(-a <authorization> | --auth <authorization>)] [(-a <authorization> | --auth <authorization>)]
[--additional-properties <additional properties>...]
[--api-package <api package>] [--artifact-id <artifact id>] [--api-package <api package>] [--artifact-id <artifact id>]
[--artifact-version <artifact version>] [--artifact-version <artifact version>]
[(-c <configuration file> | --config <configuration file>)] [(-c <configuration file> | --config <configuration file>)]
@ -470,12 +469,13 @@ SYNOPSIS
[--model-name-prefix <model name prefix>] [--model-name-prefix <model name prefix>]
[--model-name-suffix <model name suffix>] [--model-name-suffix <model name suffix>]
[--model-package <model package>] [--model-package <model package>]
[(-o <output directory> | --output <output directory>)] [(-o <output directory> | --output <output directory>)]
[(-p <additional properties> | --additional-properties <additional properties>)...]
[--package-name <package name>] [--release-note <release note>] [--package-name <package name>] [--release-note <release note>]
[--remove-operation-id-prefix] [--remove-operation-id-prefix]
[--reserved-words-mappings <reserved word mappings>...] [--reserved-words-mappings <reserved word mappings>...]
[(-s | --skip-overwrite)] [--skip-validate-spec] [(-s | --skip-overwrite)] [--server-variables <server variables>...]
[--strict-spec <true/false strict behavior>] [--skip-validate-spec] [--strict-spec <true/false strict behavior>]
[(-t <template directory> | --template-dir <template directory>)] [(-t <template directory> | --template-dir <template directory>)]
[--type-mappings <type mappings>...] [(-v | --verbose)] [--type-mappings <type mappings>...] [(-v | --verbose)]

View File

@ -235,7 +235,6 @@ NAME
SYNOPSIS SYNOPSIS
openapi-generator-cli generate openapi-generator-cli generate
[(-a <authorization> | --auth <authorization>)] [(-a <authorization> | --auth <authorization>)]
[--additional-properties <additional properties>...]
[--api-package <api package>] [--artifact-id <artifact id>] [--api-package <api package>] [--artifact-id <artifact id>]
[--artifact-version <artifact version>] [--artifact-version <artifact version>]
[(-c <configuration file> | --config <configuration file>)] [(-c <configuration file> | --config <configuration file>)]
@ -256,15 +255,15 @@ SYNOPSIS
[--model-name-prefix <model name prefix>] [--model-name-prefix <model name prefix>]
[--model-name-suffix <model name suffix>] [--model-name-suffix <model name suffix>]
[--model-package <model package>] [--model-package <model package>]
[(-o <output directory> | --output <output directory>)] [(-o <output directory> | --output <output directory>)]
[(-p <additional properties> | --additional-properties <additional properties>)...]
[--package-name <package name>] [--release-note <release note>] [--package-name <package name>] [--release-note <release note>]
[--remove-operation-id-prefix] [--remove-operation-id-prefix]
[--reserved-words-mappings <reserved word mappings>...] [--reserved-words-mappings <reserved word mappings>...]
[(-s | --skip-overwrite)] [--skip-validate-spec] [(-s | --skip-overwrite)] [--server-variables <server variables>...]
[--strict-spec <true/false strict behavior>] [--skip-validate-spec] [--strict-spec <true/false strict behavior>]
[(-t <template directory> | --template-dir <template directory>)] [(-t <template directory> | --template-dir <template directory>)]
[--type-mappings <type mappings>...] [(-v | --verbose)] [--type-mappings <type mappings>...] [(-v | --verbose)]
``` ```
<details> <details>
@ -277,19 +276,16 @@ OPTIONS
remotely. Pass in a URL-encoded string of name:header with a comma remotely. Pass in a URL-encoded string of name:header with a comma
separating multiple values separating multiple values
--additional-properties <additional properties>
sets additional properties that can be referenced by the mustache
templates in the format of name=value,name=value. You can also have
multiple occurrences of this option.
--api-package <api package> --api-package <api package>
package for generated api classes package for generated api classes
--artifact-id <artifact id> --artifact-id <artifact id>
artifactId in generated pom.xml artifactId in generated pom.xml. This also becomes part of the
generated library's filename
--artifact-version <artifact version> --artifact-version <artifact version>
artifact version in generated pom.xml artifact version in generated pom.xml. This also becomes part of the
generated library's filename
-c <configuration file>, --config <configuration file> -c <configuration file>, --config <configuration file>
Path to configuration file configuration file. It can be json or Path to configuration file configuration file. It can be json or
@ -382,6 +378,12 @@ OPTIONS
-o <output directory>, --output <output directory> -o <output directory>, --output <output directory>
where to write the generated files (current dir by default) where to write the generated files (current dir by default)
-p <additional properties>, --additional-properties <additional
properties>
sets additional properties that can be referenced by the mustache
templates in the format of name=value,name=value. You can also have
multiple occurrences of this option.
--package-name <package name> --package-name <package name>
package for generated classes (where supported) package for generated classes (where supported)
@ -400,6 +402,10 @@ OPTIONS
specifies if the existing files should be overwritten during the specifies if the existing files should be overwritten during the
generation. generation.
--server-variables <server variables>
sets server variables for spec documents which support variable
templating of servers.
--skip-validate-spec --skip-validate-spec
Skips the default behavior of validating an input specification. Skips the default behavior of validating an input specification.

View File

@ -18,13 +18,7 @@
package org.openapitools.codegen.cmd; package org.openapitools.codegen.cmd;
import static org.apache.commons.lang3.StringUtils.isNotEmpty; import static org.apache.commons.lang3.StringUtils.isNotEmpty;
import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyAdditionalPropertiesKvpList; import static org.openapitools.codegen.config.CodegenConfiguratorUtils.*;
import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyImportMappingsKvpList;
import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyInstantiationTypesKvpList;
import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyLanguageSpecificPrimitivesCsvList;
import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyReservedWordsMappingsKvpList;
import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applySystemPropertiesKvpList;
import static org.openapitools.codegen.config.CodegenConfiguratorUtils.applyTypeMappingsKvpList;
import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.spi.FilterAttachable; import ch.qos.logback.core.spi.FilterAttachable;
@ -160,6 +154,12 @@ public class Generate implements Runnable {
+ " You can also have multiple occurrences of this option.") + " You can also have multiple occurrences of this option.")
private List<String> importMappings = new ArrayList<>(); private List<String> importMappings = new ArrayList<>();
@Option(
name = {"--server-variables"},
title = "server variables",
description = "sets server variables overrides for spec documents which support variable templating of servers.")
private List<String> serverVariableOverrides = new ArrayList<>();
@Option(name = {"--invoker-package"}, title = "invoker package", @Option(name = {"--invoker-package"}, title = "invoker package",
description = CodegenConstants.INVOKER_PACKAGE_DESC) description = CodegenConstants.INVOKER_PACKAGE_DESC)
private String invokerPackage; private String invokerPackage;
@ -393,6 +393,7 @@ public class Generate implements Runnable {
applyAdditionalPropertiesKvpList(additionalProperties, configurator); applyAdditionalPropertiesKvpList(additionalProperties, configurator);
applyLanguageSpecificPrimitivesCsvList(languageSpecificPrimitives, configurator); applyLanguageSpecificPrimitivesCsvList(languageSpecificPrimitives, configurator);
applyReservedWordsMappingsKvpList(reservedWordsMappings, configurator); applyReservedWordsMappingsKvpList(reservedWordsMappings, configurator);
applyServerVariablesKvpList(serverVariableOverrides, configurator);
try { try {
final ClientOptInput clientOptInput = configurator.toClientOptInput(); final ClientOptInput clientOptInput = configurator.toClientOptInput();

View File

@ -52,6 +52,7 @@ public final class GeneratorSettings implements Serializable {
private ImmutableMap<String, String> importMappings; private ImmutableMap<String, String> importMappings;
private ImmutableSet<String> languageSpecificPrimitives; private ImmutableSet<String> languageSpecificPrimitives;
private ImmutableMap<String, String> reservedWordMappings; private ImmutableMap<String, String> reservedWordMappings;
private ImmutableMap<String, String> serverVariables;
private String gitUserId; private String gitUserId;
private String gitRepoId; private String gitRepoId;
@ -245,6 +246,17 @@ public final class GeneratorSettings implements Serializable {
return reservedWordMappings; return reservedWordMappings;
} }
/**
* Gets server variable. Values defined here will be attempted to be replaced within a templated server object.
*
* @return the server variables
*/
public Map<String, String> getServerVariables() {
return serverVariables;
}
/** /**
* Gets git user id. e.g. <strong>openapitools</strong>. * Gets git user id. e.g. <strong>openapitools</strong>.
* <p> * <p>
@ -311,6 +323,7 @@ public final class GeneratorSettings implements Serializable {
importMappings = ImmutableMap.copyOf(builder.importMappings); importMappings = ImmutableMap.copyOf(builder.importMappings);
languageSpecificPrimitives = ImmutableSet.copyOf(builder.languageSpecificPrimitives); languageSpecificPrimitives = ImmutableSet.copyOf(builder.languageSpecificPrimitives);
reservedWordMappings = ImmutableMap.copyOf(builder.reservedWordMappings); reservedWordMappings = ImmutableMap.copyOf(builder.reservedWordMappings);
serverVariables = ImmutableMap.copyOf(builder.serverVariables);
gitUserId = builder.gitUserId; gitUserId = builder.gitUserId;
gitRepoId = builder.gitRepoId; gitRepoId = builder.gitRepoId;
releaseNote = builder.releaseNote; releaseNote = builder.releaseNote;
@ -373,6 +386,7 @@ public final class GeneratorSettings implements Serializable {
importMappings = ImmutableMap.of(); importMappings = ImmutableMap.of();
languageSpecificPrimitives = ImmutableSet.of(); languageSpecificPrimitives = ImmutableSet.of();
reservedWordMappings = ImmutableMap.of(); reservedWordMappings = ImmutableMap.of();
serverVariables = ImmutableMap.of();
} }
private void setDefaults() { private void setDefaults() {
@ -394,12 +408,6 @@ public final class GeneratorSettings implements Serializable {
return new Builder(); return new Builder();
} }
/**
* New builder builder.
*
* @param copy the copy
* @return the builder
*/
public static Builder newBuilder(GeneratorSettings copy) { public static Builder newBuilder(GeneratorSettings copy) {
Builder builder = new Builder(); Builder builder = new Builder();
builder.generatorName = copy.getGeneratorName(); builder.generatorName = copy.getGeneratorName();
@ -419,6 +427,7 @@ public final class GeneratorSettings implements Serializable {
builder.importMappings = new HashMap<>(copy.getImportMappings()); builder.importMappings = new HashMap<>(copy.getImportMappings());
builder.languageSpecificPrimitives = new HashSet<>(copy.getLanguageSpecificPrimitives()); builder.languageSpecificPrimitives = new HashSet<>(copy.getLanguageSpecificPrimitives());
builder.reservedWordMappings = new HashMap<>(copy.getReservedWordMappings()); builder.reservedWordMappings = new HashMap<>(copy.getReservedWordMappings());
builder.serverVariables = new HashMap<>(copy.getServerVariables());
builder.gitUserId = copy.getGitUserId(); builder.gitUserId = copy.getGitUserId();
builder.gitRepoId = copy.getGitRepoId(); builder.gitRepoId = copy.getGitRepoId();
builder.releaseNote = copy.getReleaseNote(); builder.releaseNote = copy.getReleaseNote();
@ -449,6 +458,7 @@ public final class GeneratorSettings implements Serializable {
private Map<String, String> importMappings; private Map<String, String> importMappings;
private Set<String> languageSpecificPrimitives; private Set<String> languageSpecificPrimitives;
private Map<String, String> reservedWordMappings; private Map<String, String> reservedWordMappings;
private Map<String, String> serverVariables;
private String gitUserId; private String gitUserId;
private String gitRepoId; private String gitRepoId;
private String releaseNote; private String releaseNote;
@ -464,6 +474,7 @@ public final class GeneratorSettings implements Serializable {
importMappings = new HashMap<>(); importMappings = new HashMap<>();
languageSpecificPrimitives = new HashSet<>(); languageSpecificPrimitives = new HashSet<>();
reservedWordMappings = new HashMap<>(); reservedWordMappings = new HashMap<>();
serverVariables = new HashMap<>();
gitUserId = DEFAULT_GIT_USER_ID; gitUserId = DEFAULT_GIT_USER_ID;
gitRepoId = DEFAULT_GIT_REPO_ID; gitRepoId = DEFAULT_GIT_REPO_ID;
@ -617,6 +628,17 @@ public final class GeneratorSettings implements Serializable {
return this; return this;
} }
/**
* Sets the {@code serverVariables} and returns a reference to this Builder so that the methods can be chained together.
*
* @param serverVariables the {@code serverVariables} to set
* @return a reference to this Builder
*/
public Builder withServerVariables(Map<String, String> serverVariables) {
this.serverVariables = serverVariables;
return this;
}
/** /**
* Sets the {@code typeMappings} and returns a reference to this Builder so that the methods can be chained together. * Sets the {@code typeMappings} and returns a reference to this Builder so that the methods can be chained together.
* *
@ -731,6 +753,22 @@ public final class GeneratorSettings implements Serializable {
return this; return this;
} }
/**
* Sets a single {@code serverVariables} and returns a reference to this Builder so that the methods can be chained together.
*
* @param key A key for some server variable
* @param value The value of some server variable to be replaced in a templated server object.
* @return a reference to this Builder
*/
public Builder withServerVariable(String key, String value) {
if (this.serverVariables == null) {
this.serverVariables = new HashMap<>();
}
this.serverVariables.put(key, value);
return this;
}
/** /**
* Sets the {@code gitUserId} and returns a reference to this Builder so that the methods can be chained together. * Sets the {@code gitUserId} and returns a reference to this Builder so that the methods can be chained together.
* *

View File

@ -1,6 +1,7 @@
buildscript { buildscript {
ext.kotlin_version = '1.2.61' ext.kotlin_version = '1.2.61'
repositories { repositories {
mavenLocal()
mavenCentral() mavenCentral()
maven { maven {
url "https://plugins.gradle.org/m2/" url "https://plugins.gradle.org/m2/"

View File

@ -99,6 +99,7 @@ class OpenApiGeneratorPlugin : Plugin<Project> {
instantiationTypes.set(generate.instantiationTypes) instantiationTypes.set(generate.instantiationTypes)
typeMappings.set(generate.typeMappings) typeMappings.set(generate.typeMappings)
additionalProperties.set(generate.additionalProperties) additionalProperties.set(generate.additionalProperties)
serverVariables.set(generate.serverVariables)
languageSpecificPrimitives.set(generate.languageSpecificPrimitives) languageSpecificPrimitives.set(generate.languageSpecificPrimitives)
importMappings.set(generate.importMappings) importMappings.set(generate.importMappings)
invokerPackage.set(generate.invokerPackage) invokerPackage.set(generate.invokerPackage)

View File

@ -120,6 +120,11 @@ open class OpenApiGeneratorGenerateExtension(project: Project) {
*/ */
val additionalProperties = project.objects.property<Map<String, String>>() val additionalProperties = project.objects.property<Map<String, String>>()
/**
* Sets server variable for server URL template substitution, in the format of name=value,name=value.
*/
val serverVariables = project.objects.property<Map<String, String>>()
/** /**
* Specifies additional language specific primitive types in the format of type1,type2,type3,type3. For example: String,boolean,Boolean,Double. * Specifies additional language specific primitive types in the format of type1,type2,type3,type3. For example: String,boolean,Boolean,Double.
*/ */

View File

@ -155,6 +155,13 @@ open class GenerateTask : DefaultTask() {
@get:Internal @get:Internal
val additionalProperties = project.objects.property<Map<String, String>>() val additionalProperties = project.objects.property<Map<String, String>>()
/**
* Sets server variable for server URL template substitution, in the format of name=value,name=value.
* You can also have multiple occurrences of this option.
*/
@get:Internal
val serverVariables = project.objects.property<Map<String, String>>()
/** /**
* Specifies additional language specific primitive types in the format of type1,type2,type3,type3. For example: String,boolean,Boolean,Double. * Specifies additional language specific primitive types in the format of type1,type2,type3,type3. For example: String,boolean,Boolean,Double.
*/ */
@ -573,6 +580,12 @@ open class GenerateTask : DefaultTask() {
} }
} }
if (serverVariables.isPresent) {
serverVariables.get().forEach { entry ->
configurator.addServerVariable(entry.key, entry.value)
}
}
if (languageSpecificPrimitives.isPresent) { if (languageSpecificPrimitives.isPresent) {
languageSpecificPrimitives.get().forEach { languageSpecificPrimitives.get().forEach {
configurator.addLanguageSpecificPrimitive(it) configurator.addLanguageSpecificPrimitive(it)

View File

@ -698,10 +698,10 @@ public class CodeGenMojo extends AbstractMojo {
// Store a checksum of the input spec // Store a checksum of the input spec
File storedInputSpecHashFile = getHashFile(inputSpecFile); File storedInputSpecHashFile = getHashFile(inputSpecFile);
ByteSource inputSpecByteSource = ByteSource inputSpecByteSource =
inputSpecFile.exists() inputSpecFile.exists()
? Files.asByteSource(inputSpecFile) ? Files.asByteSource(inputSpecFile)
: CharSource.wrap(ClasspathHelper.loadFileFromClasspath(inputSpecFile.toString().replaceAll("\\\\","/"))) : CharSource.wrap(ClasspathHelper.loadFileFromClasspath(inputSpecFile.toString().replaceAll("\\\\","/")))
.asByteSource(Charsets.UTF_8); .asByteSource(Charsets.UTF_8);
String inputSpecHash =inputSpecByteSource.hash(Hashing.sha256()).toString(); String inputSpecHash =inputSpecByteSource.hash(Hashing.sha256()).toString();
if (storedInputSpecHashFile.getParent() != null && !new File(storedInputSpecHashFile.getParent()).exists()) { if (storedInputSpecHashFile.getParent() != null && !new File(storedInputSpecHashFile.getParent()).exists()) {

View File

@ -43,6 +43,8 @@ public interface CodegenConfig {
Map<String, Object> additionalProperties(); Map<String, Object> additionalProperties();
Map<String, String> serverVariableOverrides();
Map<String, Object> vendorExtensions(); Map<String, Object> vendorExtensions();
String testPackage(); String testPackage();

View File

@ -7,4 +7,5 @@ public class CodegenServerVariable {
public String defaultValue; public String defaultValue;
public String description; public String description;
public List<String> enumValues; public List<String> enumValues;
public String value;
} }

View File

@ -97,6 +97,7 @@ public class DefaultCodegen implements CodegenConfig {
protected String embeddedTemplateDir; protected String embeddedTemplateDir;
protected String commonTemplateDir = "_common"; protected String commonTemplateDir = "_common";
protected Map<String, Object> additionalProperties = new HashMap<String, Object>(); protected Map<String, Object> additionalProperties = new HashMap<String, Object>();
protected Map<String, String> serverVariables = new HashMap<String, String>();
protected Map<String, Object> vendorExtensions = new HashMap<String, Object>(); protected Map<String, Object> vendorExtensions = new HashMap<String, Object>();
protected List<SupportingFile> supportingFiles = new ArrayList<SupportingFile>(); protected List<SupportingFile> supportingFiles = new ArrayList<SupportingFile>();
protected List<CliOption> cliOptions = new ArrayList<CliOption>(); protected List<CliOption> cliOptions = new ArrayList<CliOption>();
@ -503,12 +504,12 @@ public class DefaultCodegen implements CodegenConfig {
public void postProcessParameter(CodegenParameter parameter) { public void postProcessParameter(CodegenParameter parameter) {
} }
//override with any special handling of the entire swagger spec //override with any special handling of the entire OpenAPI spec document
@SuppressWarnings("unused") @SuppressWarnings("unused")
public void preprocessOpenAPI(OpenAPI openAPI) { public void preprocessOpenAPI(OpenAPI openAPI) {
} }
// override with any special handling of the entire swagger spec // override with any special handling of the entire OpenAPI spec document
@SuppressWarnings("unused") @SuppressWarnings("unused")
public void processOpenAPI(OpenAPI openAPI) { public void processOpenAPI(OpenAPI openAPI) {
} }
@ -722,6 +723,10 @@ public class DefaultCodegen implements CodegenConfig {
return additionalProperties; return additionalProperties;
} }
public Map<String, String> serverVariableOverrides() {
return serverVariables;
}
public Map<String, Object> vendorExtensions() { public Map<String, Object> vendorExtensions() {
return vendorExtensions; return vendorExtensions;
} }
@ -5053,14 +5058,34 @@ public class DefaultCodegen implements CodegenConfig {
if (variables == null) { if (variables == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
Map<String, String> variableOverrides = serverVariableOverrides();
List<CodegenServerVariable> codegenServerVariables = new LinkedList<>(); List<CodegenServerVariable> codegenServerVariables = new LinkedList<>();
for (Entry<String, ServerVariable> variableEntry : variables.entrySet()) { for (Entry<String, ServerVariable> variableEntry : variables.entrySet()) {
CodegenServerVariable codegenServerVariable = new CodegenServerVariable(); CodegenServerVariable codegenServerVariable = new CodegenServerVariable();
ServerVariable variable = variableEntry.getValue(); ServerVariable variable = variableEntry.getValue();
List<String> enums = variable.getEnum();
codegenServerVariable.defaultValue = variable.getDefault(); codegenServerVariable.defaultValue = variable.getDefault();
codegenServerVariable.description = escapeText(variable.getDescription()); codegenServerVariable.description = escapeText(variable.getDescription());
codegenServerVariable.enumValues = variable.getEnum(); codegenServerVariable.enumValues = enums;
codegenServerVariable.name = variableEntry.getKey(); codegenServerVariable.name = variableEntry.getKey();
// Sets the override value for a server variable pattern.
// NOTE: OpenAPI Specification doesn't prevent multiple server URLs with variables. If multiple objects have the same
// variables pattern, user overrides will apply to _all_ of these patterns. We may want to consider indexed overrides.
if (variableOverrides != null && !variableOverrides.isEmpty()) {
String value = variableOverrides.getOrDefault(variableEntry.getKey(), variable.getDefault());
codegenServerVariable.value = value;
if (enums != null && !enums.isEmpty() && !enums.contains(value)) {
LOGGER.warn("Variable override of '{}' is not listed in the enum of allowed values ({}).", value, StringUtils.join(enums, ","));
}
} else {
codegenServerVariable.value = variable.getDefault();
}
codegenServerVariables.add(codegenServerVariable); codegenServerVariables.add(codegenServerVariable);
} }
return codegenServerVariables; return codegenServerVariables;

View File

@ -207,10 +207,12 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
config.vendorExtensions().putAll(openAPI.getExtensions()); config.vendorExtensions().putAll(openAPI.getExtensions());
} }
URL url = URLPathUtils.getServerURL(openAPI); // TODO: Allow user to define _which_ servers object in the array to target.
// Configures contextPath/basePath according to api document's servers
URL url = URLPathUtils.getServerURL(openAPI, config.serverVariableOverrides());
contextPath = config.escapeText(url.getPath()).replaceAll("/$", ""); // for backward compatibility contextPath = config.escapeText(url.getPath()).replaceAll("/$", ""); // for backward compatibility
basePathWithoutHost = contextPath; basePathWithoutHost = contextPath;
basePath = config.escapeText(URLPathUtils.getHost(openAPI)).replaceAll("/$", ""); basePath = config.escapeText(URLPathUtils.getHost(openAPI, config.serverVariableOverrides())).replaceAll("/$", "");
} }
private void configureOpenAPIInfo() { private void configureOpenAPIInfo() {
@ -548,7 +550,7 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
} }
}); });
Map<String, Object> operation = processOperations(config, tag, ops, allModels); Map<String, Object> operation = processOperations(config, tag, ops, allModels);
URL url = URLPathUtils.getServerURL(openAPI); URL url = URLPathUtils.getServerURL(openAPI, config.serverVariableOverrides());
operation.put("basePath", basePath); operation.put("basePath", basePath);
operation.put("basePathWithoutHost", config.encodePath(url.getPath()).replaceAll("/$", "")); operation.put("basePathWithoutHost", config.encodePath(url.getPath()).replaceAll("/$", ""));
operation.put("contextPath", contextPath); operation.put("contextPath", contextPath);
@ -819,7 +821,7 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
Map<String, Object> apis = new HashMap<String, Object>(); Map<String, Object> apis = new HashMap<String, Object>();
apis.put("apis", allOperations); apis.put("apis", allOperations);
URL url = URLPathUtils.getServerURL(openAPI); URL url = URLPathUtils.getServerURL(openAPI, config.serverVariableOverrides());
bundle.put("openAPI", openAPI); bundle.put("openAPI", openAPI);
bundle.put("basePath", basePath); bundle.put("basePath", basePath);

View File

@ -67,6 +67,7 @@ public class CodegenConfigurator {
private Map<String, String> importMappings = new HashMap<>(); private Map<String, String> importMappings = new HashMap<>();
private Set<String> languageSpecificPrimitives = new HashSet<>(); private Set<String> languageSpecificPrimitives = new HashSet<>();
private Map<String, String> reservedWordMappings = new HashMap<>(); private Map<String, String> reservedWordMappings = new HashMap<>();
private Map<String, String> serverVariables = new HashMap<>();
private String auth; private String auth;
public CodegenConfigurator() { public CodegenConfigurator() {
@ -98,6 +99,12 @@ public class CodegenConfigurator {
return null; return null;
} }
public CodegenConfigurator addServerVariable(String key, String value) {
this.serverVariables.put(key, value);
generatorSettingsBuilder.withServerVariable(key, value);
return this;
}
public CodegenConfigurator addAdditionalProperty(String key, Object value) { public CodegenConfigurator addAdditionalProperty(String key, Object value) {
this.additionalProperties.put(key, value); this.additionalProperties.put(key, value);
generatorSettingsBuilder.withAdditionalProperty(key, value); generatorSettingsBuilder.withAdditionalProperty(key, value);
@ -146,6 +153,18 @@ public class CodegenConfigurator {
return this; return this;
} }
public CodegenConfigurator setServerVariables(Map<String, String> serverVariables) {
this.serverVariables = serverVariables;
generatorSettingsBuilder.withServerVariables(serverVariables);
return this;
}
public CodegenConfigurator setReservedWordsMappings(Map<String, String> reservedWordMappings) {
this.reservedWordMappings = reservedWordMappings;
generatorSettingsBuilder.withReservedWordMappings(reservedWordMappings);
return this;
}
public CodegenConfigurator setApiPackage(String apiPackage) { public CodegenConfigurator setApiPackage(String apiPackage) {
generatorSettingsBuilder.withApiPackage(apiPackage); generatorSettingsBuilder.withApiPackage(apiPackage);
return this; return this;
@ -247,6 +266,7 @@ public class CodegenConfigurator {
public CodegenConfigurator setLanguageSpecificPrimitives( public CodegenConfigurator setLanguageSpecificPrimitives(
Set<String> languageSpecificPrimitives) { Set<String> languageSpecificPrimitives) {
this.languageSpecificPrimitives = languageSpecificPrimitives;
generatorSettingsBuilder.withLanguageSpecificPrimitives(languageSpecificPrimitives); generatorSettingsBuilder.withLanguageSpecificPrimitives(languageSpecificPrimitives);
return this; return this;
} }
@ -296,12 +316,6 @@ public class CodegenConfigurator {
return this; return this;
} }
public CodegenConfigurator setReservedWordsMappings(Map<String, String> reservedWordMappings) {
this.reservedWordMappings = reservedWordMappings;
generatorSettingsBuilder.withReservedWordMappings(reservedWordMappings);
return this;
}
public CodegenConfigurator setSkipOverwrite(boolean skipOverwrite) { public CodegenConfigurator setSkipOverwrite(boolean skipOverwrite) {
workflowSettingsBuilder.withSkipOverwrite(skipOverwrite); workflowSettingsBuilder.withSkipOverwrite(skipOverwrite);
return this; return this;
@ -459,6 +473,13 @@ public class CodegenConfigurator {
config.reservedWordsMappings().putAll(generatorSettings.getReservedWordMappings()); config.reservedWordsMappings().putAll(generatorSettings.getReservedWordMappings());
config.additionalProperties().putAll(generatorSettings.getAdditionalProperties()); config.additionalProperties().putAll(generatorSettings.getAdditionalProperties());
Map<String, String> serverVariables = generatorSettings.getServerVariables();
if (!serverVariables.isEmpty()) {
// This is currently experimental due to vagueness in the specification
LOGGER.warn("user-defined server variable support is experimental.");
config.serverVariableOverrides().putAll(serverVariables);
}
// any other additional properties? // any other additional properties?
String templateDir = workflowSettings.getTemplateDir(); String templateDir = workflowSettings.getTemplateDir();
if (templateDir != null) { if (templateDir != null) {

View File

@ -107,6 +107,19 @@ public final class CodegenConfiguratorUtils {
} }
} }
public static void applyServerVariablesKvpList(List<String> values, CodegenConfigurator configurator) {
for(String value : values) {
applyServerVariablesKvp(value, configurator);
}
}
public static void applyServerVariablesKvp(String values, CodegenConfigurator configurator) {
final Map<String, String> map = createMapFromKeyValuePairs(values);
for (Map.Entry<String, String> entry : map.entrySet()) {
configurator.addServerVariable(entry.getKey(), entry.getValue());
}
}
public static void applyLanguageSpecificPrimitivesCsvList(List<String> languageSpecificPrimitives, CodegenConfigurator configurator) { public static void applyLanguageSpecificPrimitivesCsvList(List<String> languageSpecificPrimitives, CodegenConfigurator configurator) {
for(String propString : languageSpecificPrimitives) { for(String propString : languageSpecificPrimitives) {
applyLanguageSpecificPrimitivesCsv(propString, configurator); applyLanguageSpecificPrimitivesCsv(propString, configurator);

View File

@ -296,7 +296,7 @@ abstract public class AbstractCppCodegen extends DefaultCodegen implements Codeg
@Override @Override
public void preprocessOpenAPI(OpenAPI openAPI) { public void preprocessOpenAPI(OpenAPI openAPI) {
URL url = URLPathUtils.getServerURL(openAPI); URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
String port = URLPathUtils.getPort(url, ""); String port = URLPathUtils.getPort(url, "");
String host = url.getHost(); String host = url.getHost();
if(!port.isEmpty()) { if(!port.isEmpty()) {

View File

@ -110,7 +110,7 @@ public abstract class AbstractJavaJAXRSServerCodegen extends AbstractJavaCodegen
*/ */
if (!this.additionalProperties.containsKey(SERVER_PORT)) { if (!this.additionalProperties.containsKey(SERVER_PORT)) {
URL url = URLPathUtils.getServerURL(openAPI); URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
// 8080 is the default value for a JEE Server: // 8080 is the default value for a JEE Server:
this.additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, serverPort)); this.additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, serverPort));
} }

View File

@ -268,7 +268,7 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
@Override @Override
public void preprocessOpenAPI(OpenAPI openAPI) { public void preprocessOpenAPI(OpenAPI openAPI) {
super.preprocessOpenAPI(openAPI); super.preprocessOpenAPI(openAPI);
URL url = URLPathUtils.getServerURL(openAPI); URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
additionalProperties.put("serverHost", url.getHost()); additionalProperties.put("serverHost", url.getHost());
additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080)); additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080));
} }

View File

@ -359,7 +359,7 @@ public class CSharpNancyFXServerCodegen extends AbstractCSharpCodegen {
@Override @Override
public void preprocessOpenAPI(final OpenAPI openAPI) { public void preprocessOpenAPI(final OpenAPI openAPI) {
URL url = URLPathUtils.getServerURL(openAPI); URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
String path = URLPathUtils.getPath(url, "/"); String path = URLPathUtils.getPath(url, "/");
final String packageContextOption = (String) additionalProperties.get(PACKAGE_CONTEXT); final String packageContextOption = (String) additionalProperties.get(PACKAGE_CONTEXT);
additionalProperties.put("packageContext", packageContextOption == null ? sanitizeName(path) : packageContextOption); additionalProperties.put("packageContext", packageContextOption == null ? sanitizeName(path) : packageContextOption);

View File

@ -23,20 +23,14 @@ import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenOperation; import org.openapitools.codegen.CodegenOperation;
import org.openapitools.codegen.CodegenType; import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.SupportingFile; import org.openapitools.codegen.SupportingFile;
import org.openapitools.codegen.CodegenModel;
import org.openapitools.codegen.CodegenProperty;
import org.openapitools.codegen.utils.URLPathUtils; import org.openapitools.codegen.utils.URLPathUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File; import java.io.File;
import java.net.URL; import java.net.URL;
import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.List;
import java.util.ArrayList;
import static java.util.UUID.randomUUID; import static java.util.UUID.randomUUID;
@ -165,7 +159,7 @@ public class FsharpGiraffeServerCodegen extends AbstractFSharpCodegen {
@Override @Override
public void preprocessOpenAPI(OpenAPI openAPI) { public void preprocessOpenAPI(OpenAPI openAPI) {
super.preprocessOpenAPI(openAPI); super.preprocessOpenAPI(openAPI);
URL url = URLPathUtils.getServerURL(openAPI); URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
additionalProperties.put("serverHost", url.getHost()); additionalProperties.put("serverHost", url.getHost());
additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080)); additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080));
} }

View File

@ -538,7 +538,7 @@ public class JavaPKMSTServerCodegen extends AbstractJavaCodegen {
additionalProperties.put(TITLE, this.title); additionalProperties.put(TITLE, this.title);
} }
URL url = URLPathUtils.getServerURL(openAPI); URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
this.additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080)); this.additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080));
if (openAPI.getPaths() != null) { if (openAPI.getPaths() != null) {

View File

@ -221,7 +221,7 @@ public class JavaVertXServerCodegen extends AbstractJavaCodegen {
super.preprocessOpenAPI(openAPI); super.preprocessOpenAPI(openAPI);
// add server port from the swagger file, 8080 by default // add server port from the swagger file, 8080 by default
URL url = URLPathUtils.getServerURL(openAPI); URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
this.additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080)); this.additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080));
// retrieve api version from swagger file, 1.0.0-SNAPSHOT by default // retrieve api version from swagger file, 1.0.0-SNAPSHOT by default

View File

@ -407,7 +407,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
} }
if (!additionalProperties.containsKey(SERVER_PORT)) { if (!additionalProperties.containsKey(SERVER_PORT)) {
URL url = URLPathUtils.getServerURL(openAPI); URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
this.additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, 8080)); this.additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, 8080));
} }

View File

@ -300,7 +300,7 @@ public class NodeJSExpressServerCodegen extends DefaultCodegen implements Codege
@Override @Override
public void preprocessOpenAPI(OpenAPI openAPI) { public void preprocessOpenAPI(OpenAPI openAPI) {
URL url = URLPathUtils.getServerURL(openAPI); URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
String host = URLPathUtils.getProtocolAndHost(url); String host = URLPathUtils.getProtocolAndHost(url);
String port = URLPathUtils.getPort(url, defaultServerPort) ; String port = URLPathUtils.getPort(url, defaultServerPort) ;
String basePath = url.getPath(); String basePath = url.getPath();

View File

@ -358,7 +358,7 @@ public class NodeJSServerCodegen extends DefaultCodegen implements CodegenConfig
@Override @Override
public void preprocessOpenAPI(OpenAPI openAPI) { public void preprocessOpenAPI(OpenAPI openAPI) {
URL url = URLPathUtils.getServerURL(openAPI); URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
String host = URLPathUtils.getProtocolAndHost(url); String host = URLPathUtils.getProtocolAndHost(url);
String port = URLPathUtils.getPort(url, defaultServerPort) ; String port = URLPathUtils.getPort(url, defaultServerPort) ;
String basePath = url.getPath(); String basePath = url.getPath();

View File

@ -24,9 +24,7 @@ import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.FileSchema; import io.swagger.v3.oas.models.media.FileSchema;
import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.media.StringSchema;
import io.swagger.v3.oas.models.media.XML; import io.swagger.v3.oas.models.media.XML;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.parameters.RequestBody; import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.servers.Server; import io.swagger.v3.oas.models.servers.Server;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -291,7 +289,7 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
} }
info.setVersion(StringUtils.join(versionComponents, ".")); info.setVersion(StringUtils.join(versionComponents, "."));
URL url = URLPathUtils.getServerURL(openAPI); URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
additionalProperties.put("serverHost", url.getHost()); additionalProperties.put("serverHost", url.getHost());
additionalProperties.put("serverPort", URLPathUtils.getPort(url, 80)); additionalProperties.put("serverPort", URLPathUtils.getPort(url, 80));
} }

View File

@ -515,8 +515,8 @@ public class SpringCodegen extends AbstractJavaCodegen
additionalProperties.put(TITLE, this.title); additionalProperties.put(TITLE, this.title);
} }
if (!additionalProperties.containsKey(SERVER_PORT)) { if(!additionalProperties.containsKey(SERVER_PORT)) {
URL url = URLPathUtils.getServerURL(openAPI); URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
this.additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, 8080)); this.additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, 8080));
} }

View File

@ -17,6 +17,7 @@
package org.openapitools.codegen.utils; package org.openapitools.codegen.utils;
import com.google.common.collect.ImmutableMap;
import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.servers.Server; import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.oas.models.servers.ServerVariable; import io.swagger.v3.oas.models.servers.ServerVariable;
@ -28,9 +29,7 @@ import org.slf4j.LoggerFactory;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.HashSet; import java.util.*;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -40,24 +39,28 @@ public class URLPathUtils {
public static final String LOCAL_HOST = "http://localhost"; public static final String LOCAL_HOST = "http://localhost";
public static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{([^\\}]+)\\}"); public static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{([^\\}]+)\\}");
public static URL getServerURL(OpenAPI openAPI) { // TODO: This should probably be moved into generator/workflow type rather than a static like this.
public static URL getServerURL(OpenAPI openAPI, Map<String, String> userDefinedVariables) {
final List<Server> servers = openAPI.getServers(); final List<Server> servers = openAPI.getServers();
if (servers == null || servers.isEmpty()) { if (servers == null || servers.isEmpty()) {
LOGGER.warn("Server information seems not defined in the spec. Default to {}.", LOCAL_HOST); LOGGER.warn("Server information seems not defined in the spec. Default to {}.", LOCAL_HOST);
return getDefaultUrl(); return getDefaultUrl();
} }
// TODO need a way to obtain all server URLs // TODO need a way to obtain all server URLs
return getServerURL(servers.get(0)); return getServerURL(servers.get(0), userDefinedVariables);
} }
public static URL getServerURL(final Server server) { public static URL getServerURL(final Server server, final Map<String, String> userDefinedVariables) {
String url = server.getUrl(); String url = server.getUrl();
ServerVariables variables = server.getVariables(); ServerVariables variables = server.getVariables();
if (variables == null) { if (variables == null) {
variables = new ServerVariables(); variables = new ServerVariables();
} }
Map<String, String> userVariables = userDefinedVariables == null ? new HashMap<>() : ImmutableMap.copyOf(userDefinedVariables);
if (StringUtils.isNotBlank(url)) { if (StringUtils.isNotBlank(url)) {
url = extractUrl(server, url, variables); url = extractUrl(server, url, variables, userVariables);
url = sanitizeUrl(url); url = sanitizeUrl(url);
try { try {
@ -69,26 +72,37 @@ public class URLPathUtils {
return getDefaultUrl(); return getDefaultUrl();
} }
private static String extractUrl(Server server, String url, ServerVariables variables) { private static String extractUrl(Server server, String url, ServerVariables variables, Map<String, String> userVariables) {
Set<String> replacedVariables = new HashSet<>(); Set<String> replacedVariables = new HashSet<>();
Matcher matcher = VARIABLE_PATTERN.matcher(url); Matcher matcher = VARIABLE_PATTERN.matcher(url);
while (matcher.find()) { while (matcher.find()) {
if (!replacedVariables.contains(matcher.group())) { if (!replacedVariables.contains(matcher.group())) {
ServerVariable variable = variables.get(matcher.group(1)); String variableName = matcher.group(1);
ServerVariable variable = variables.get(variableName);
String replacement; String replacement;
if (variable != null) { if (variable != null) {
if (variable.getDefault() != null) { String defaultValue = variable.getDefault();
replacement = variable.getDefault(); List<String> enumValues = variable.getEnum() == null ? new ArrayList<>() : variable.getEnum();
} else if (variable.getEnum() != null && !variable.getEnum().isEmpty()) { if (defaultValue == null && !enumValues.isEmpty()) {
replacement = variable.getEnum().get(0); defaultValue = enumValues.get(0);
} else { } else if (defaultValue == null) {
LOGGER.warn("No value found for variable '{}' in server definition '{}', default to empty string.", matcher.group(1), server.getUrl()); defaultValue = "";
replacement = ""; }
replacement = userVariables.getOrDefault(variableName, defaultValue);
if (!enumValues.isEmpty() && !enumValues.contains(replacement)) {
LOGGER.warn("Variable override of '{}' is not listed in the enum of allowed values ({}).", replacement, StringUtils.join(enumValues, ","));
} }
} else { } else {
LOGGER.warn("No variable '{}' found in server definition '{}', default to empty string.", matcher.group(1), server.getUrl()); replacement = userVariables.getOrDefault(variableName, "");
replacement = "";
} }
if (StringUtils.isEmpty(replacement)) {
replacement = "";
LOGGER.warn("No value found for variable '{}' in server definition '{}' and no user override specified, default to empty string.", variableName, server.getUrl());
}
url = url.replace(matcher.group(), replacement); url = url.replace(matcher.group(), replacement);
replacedVariables.add(matcher.group()); replacedVariables.add(matcher.group());
matcher = VARIABLE_PATTERN.matcher(url); matcher = VARIABLE_PATTERN.matcher(url);
@ -98,7 +112,7 @@ public class URLPathUtils {
} }
public static String getScheme(OpenAPI openAPI, CodegenConfig config) { public static String getScheme(OpenAPI openAPI, CodegenConfig config) {
URL url = getServerURL(openAPI); URL url = getServerURL(openAPI, config.serverVariableOverrides());
return getScheme(url, config); return getScheme(url, config);
} }
@ -176,11 +190,12 @@ public class URLPathUtils {
* Return the first complete URL from the OpenAPI specification * Return the first complete URL from the OpenAPI specification
* *
* @param openAPI current OpenAPI specification * @param openAPI current OpenAPI specification
* @param userDefinedVariables User overrides for server variable templating
* @return host * @return host
*/ */
public static String getHost(OpenAPI openAPI) { public static String getHost(OpenAPI openAPI, final Map<String, String> userDefinedVariables) {
if (openAPI.getServers() != null && openAPI.getServers().size() > 0) { if (openAPI.getServers() != null && openAPI.getServers().size() > 0) {
return sanitizeUrl(getServerURL(openAPI.getServers().get(0)).toString()); return sanitizeUrl(getServerURL(openAPI.getServers().get(0), userDefinedVariables).toString());
} }
return LOCAL_HOST; return LOCAL_HOST;
} }

View File

@ -26,13 +26,15 @@ import org.testng.annotations.Test;
import java.net.URL; import java.net.URL;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class URLPathUtilsTest { public class URLPathUtilsTest {
@Test @Test
public void testDefaultValues() { public void testDefaultValues() {
OpenAPI openAPI = new OpenAPI(); OpenAPI openAPI = new OpenAPI();
URL serverURL = URLPathUtils.getServerURL(openAPI); URL serverURL = URLPathUtils.getServerURL(openAPI, null);
Assert.assertEquals(serverURL.getHost(), "localhost"); Assert.assertEquals(serverURL.getHost(), "localhost");
Assert.assertEquals(serverURL.getPort(), -1); Assert.assertEquals(serverURL.getPort(), -1);
@ -47,7 +49,7 @@ public class URLPathUtilsTest {
public void testUrl() { public void testUrl() {
OpenAPI openAPI = new OpenAPI(); OpenAPI openAPI = new OpenAPI();
openAPI.addServersItem(new Server().url("https://abcdef.xyz:9999/some/path")); openAPI.addServersItem(new Server().url("https://abcdef.xyz:9999/some/path"));
URL serverURL = URLPathUtils.getServerURL(openAPI); URL serverURL = URLPathUtils.getServerURL(openAPI, null);
Assert.assertEquals(serverURL.getHost(), "abcdef.xyz"); Assert.assertEquals(serverURL.getHost(), "abcdef.xyz");
Assert.assertEquals(serverURL.getPort(), 9999); Assert.assertEquals(serverURL.getPort(), 9999);
@ -74,51 +76,117 @@ public class URLPathUtilsTest {
OpenAPI openAPI = new OpenAPI(); OpenAPI openAPI = new OpenAPI();
openAPI.addServersItem(new Server().url(t[0])); openAPI.addServersItem(new Server().url(t[0]));
Assert.assertEquals(URLPathUtils.getServerURL(openAPI).toString(), t[1]); Assert.assertEquals(URLPathUtils.getServerURL(openAPI, null).toString(), t[1]);
} }
} }
@Test @Test
public void testGetServerURLWithVariables() { public void testGetServerURLWithVariables() {
Server s1 = new Server().url("http://localhost:{port}/").variables(new ServerVariables().addServerVariable("port", new ServerVariable()._default("8080").description("the server port"))); Server s1 = new Server().url("http://localhost:{port}/").variables(new ServerVariables().addServerVariable("port", new ServerVariable()._default("8080").description("the server port")));
Assert.assertEquals(URLPathUtils.getServerURL(s1).toString(), "http://localhost:8080/"); Assert.assertEquals(URLPathUtils.getServerURL(s1, null).toString(), "http://localhost:8080/");
Server s2 = new Server().url("http://{version}.test.me/{version}").variables(new ServerVariables().addServerVariable("version", new ServerVariable()._default("v1"))); Server s2 = new Server().url("http://{version}.test.me/{version}").variables(new ServerVariables().addServerVariable("version", new ServerVariable()._default("v1")));
Assert.assertEquals(URLPathUtils.getServerURL(s2).toString(), "http://v1.test.me/v1"); Assert.assertEquals(URLPathUtils.getServerURL(s2, null).toString(), "http://v1.test.me/v1");
Server s3 = new Server().url("http://localhost:{port}/{version}").variables( Server s3 = new Server().url("http://localhost:{port}/{version}").variables(
new ServerVariables().addServerVariable("version", new ServerVariable()._default("v4")) new ServerVariables().addServerVariable("version", new ServerVariable()._default("v4"))
.addServerVariable("port", new ServerVariable()._default("8080")) .addServerVariable("port", new ServerVariable()._default("8080"))
.addServerVariable("other", new ServerVariable()._default("something")) .addServerVariable("other", new ServerVariable()._default("something"))
); );
Assert.assertEquals(URLPathUtils.getServerURL(s3).toString(), "http://localhost:8080/v4"); Assert.assertEquals(URLPathUtils.getServerURL(s3, null).toString(), "http://localhost:8080/v4");
Server s4 = new Server().url("http://91.161.147.64/{targetEnv}").variables(new ServerVariables().addServerVariable("targetEnv", new ServerVariable().description("target environment")._enum(Arrays.asList("dev", "int", "prd"))._default("prd"))); Server s4 = new Server().url("http://91.161.147.64/{targetEnv}").variables(new ServerVariables().addServerVariable("targetEnv", new ServerVariable().description("target environment")._enum(Arrays.asList("dev", "int", "prd"))._default("prd")));
Assert.assertEquals(URLPathUtils.getServerURL(s4).toString(), "http://91.161.147.64/prd"); Assert.assertEquals(URLPathUtils.getServerURL(s4, null).toString(), "http://91.161.147.64/prd");
Server s5 = new Server().url("https://api.stats.com/{country1}").variables(new ServerVariables().addServerVariable("country1", new ServerVariable()._enum(Arrays.asList("france", "germany", "italy")))); Server s5 = new Server().url("https://api.stats.com/{country1}").variables(new ServerVariables().addServerVariable("country1", new ServerVariable()._enum(Arrays.asList("france", "germany", "italy"))));
Assert.assertEquals(URLPathUtils.getServerURL(s5).toString(), "https://api.stats.com/france"); Assert.assertEquals(URLPathUtils.getServerURL(s5, null).toString(), "https://api.stats.com/france");
Server s6 = new Server().url("https://api.example.com/{wrong}"); Server s6 = new Server().url("https://api.example.com/{wrong}");
Assert.assertEquals(URLPathUtils.getServerURL(s6).toString(), "https://api.example.com/"); Assert.assertEquals(URLPathUtils.getServerURL(s6, null).toString(), "https://api.example.com/");
Server s7 = new Server().url("https://api.example.com/{wrong}").variables(new ServerVariables()); Server s7 = new Server().url("https://api.example.com/{wrong}").variables(new ServerVariables());
Assert.assertEquals(URLPathUtils.getServerURL(s7).toString(), "https://api.example.com/"); Assert.assertEquals(URLPathUtils.getServerURL(s7, null).toString(), "https://api.example.com/");
Server s8 = new Server().url("https://api.example.com/{wrong}").variables(new ServerVariables().addServerVariable("other", new ServerVariable()._default("something"))); Server s8 = new Server().url("https://api.example.com/{wrong}").variables(new ServerVariables().addServerVariable("other", new ServerVariable()._default("something")));
Assert.assertEquals(URLPathUtils.getServerURL(s8).toString(), "https://api.example.com/"); Assert.assertEquals(URLPathUtils.getServerURL(s8, null).toString(), "https://api.example.com/");
Server s9 = new Server().url("https://{user}.example.com/{version}").variables( Server s9 = new Server().url("https://{user}.example.com/{version}").variables(
new ServerVariables().addServerVariable("version", new ServerVariable()._default("v1")) new ServerVariables().addServerVariable("version", new ServerVariable()._default("v1"))
.addServerVariable("user", new ServerVariable()._default("{user}"))); .addServerVariable("user", new ServerVariable()._default("{user}")));
Assert.assertEquals(URLPathUtils.getServerURL(s9).toString(), "https://{user}.example.com/v1"); Assert.assertEquals(URLPathUtils.getServerURL(s9, null).toString(), "https://{user}.example.com/v1");
}
private ServerVariables serverVariables(String... entries) {
ServerVariables variables = new ServerVariables();
for (int i = 0; i < entries.length; i+=2) {
String key = entries[i];
String value = "";
if (i+1 < entries.length) {
value = entries[i+1];
}
variables.addServerVariable(key, new ServerVariable()._default(value).description("variable for: " + key));
}
return variables;
}
@Test
public void testGetServerURLWithVariablesAndUserOverrides() {
Server s1 = new Server().url("http://localhost:{port}/").variables(
serverVariables("port", "8080")
);
Assert.assertEquals(URLPathUtils.getServerURL(s1, new HashMap<String, String>() {{ put("port", "1234"); }}).toString(), "http://localhost:1234/");
Server s2 = new Server().url("http://{version}.test.me/{version}").variables(
serverVariables("version", "v1")
);
Assert.assertEquals(URLPathUtils.getServerURL(s2, new HashMap<String, String>() {{ put("version", "v2" ); }}).toString(), "http://v2.test.me/v2");
Server s3 = new Server().url("http://localhost:{port}/{version}").variables(
serverVariables(
"version", "v4",
"port", "8080",
"other", "something"
)
);
Assert.assertEquals(URLPathUtils.getServerURL(s3, new HashMap<String, String>() {{ put("port", "5678"); }}).toString(), "http://localhost:5678/v4");
Server s4 = new Server().url("http://91.161.147.64/{targetEnv}").variables(
new ServerVariables().addServerVariable("targetEnv", new ServerVariable().description("target environment")._enum(Arrays.asList("dev", "int", "prd"))._default("prd")));
Assert.assertEquals(URLPathUtils.getServerURL(s4, new HashMap<String, String>() {{ put("targetEnv", "int" ); }}).toString(), "http://91.161.147.64/int");
Server s5 = new Server().url("https://api.stats.com/{country1}").variables(
new ServerVariables().addServerVariable("country1", new ServerVariable()._enum(Arrays.asList("france", "germany", "italy")))
);
Assert.assertEquals(URLPathUtils.getServerURL(s5, new HashMap<String, String>() {{ put("country1", "italy" ); }}).toString(), "https://api.stats.com/italy");
Server s6 = new Server().url("https://api.example.com/{wrong}");
Assert.assertEquals(URLPathUtils.getServerURL(s6, new HashMap<String, String>() {{ put("port", "8080" ); }}).toString(), "https://api.example.com/");
Server s7 = new Server().url("https://api.example.com/{wrong}").variables(new ServerVariables());
Assert.assertEquals(URLPathUtils.getServerURL(s7, new HashMap<String, String>() {{ put("", "8080" ); }}).toString(), "https://api.example.com/");
Server s8 = new Server().url("https://api.example.com/{wrong}").variables(
serverVariables("other", "something")
);
Assert.assertEquals(URLPathUtils.getServerURL(s8, new HashMap<String, String>() {{ put("something", "other" ); }}).toString(), "https://api.example.com/");
Server s9 = new Server().url("https://{user}.example.com/{version}").variables(
serverVariables(
"version", "v1",
"user", "{user}"
)
);
Assert.assertEquals(URLPathUtils.getServerURL(s9, new HashMap<String, String>() {{
put("version", "v2" );
put("user", "jim");
}}).toString(), "https://jim.example.com/v2");
} }
@Test @Test
public void useDefaultUrlWhenServerUrlIsNull() { public void useDefaultUrlWhenServerUrlIsNull() {
Server server = new Server().url(null); Server server = new Server().url(null);
URL serverURL = URLPathUtils.getServerURL(server); URL serverURL = URLPathUtils.getServerURL(server, null);
Assert.assertEquals(serverURL.toString(), "http://localhost"); Assert.assertEquals(serverURL.toString(), "http://localhost");
} }
} }