Skip to content

Commit 0e60c96

Browse files
authored
KTOR-5283 Support Default Value for missing Env Variables in YAML (#3288)
1 parent 04a9791 commit 0e60c96

2 files changed

Lines changed: 42 additions & 5 deletions

File tree

ktor-server/ktor-server-config-yaml/jvmAndNix/src/io/ktor/server/config/yaml/YamlConfig.kt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public class YamlConfigLoader : ConfigLoader {
1515
/**
1616
* Tries loading an application configuration from the specified [path].
1717
*
18-
* @return configuration or null if the path is not found or configuration format is not supported.
18+
* @return configuration or null if the path is not found or a configuration format is not supported.
1919
*/
2020
override fun load(path: String?): ApplicationConfig? {
2121
return YamlConfig(path)?.apply { checkEnvironmentVariables() }
@@ -24,14 +24,14 @@ public class YamlConfigLoader : ConfigLoader {
2424

2525
/**
2626
* Loads a configuration from the YAML file, if found.
27-
* On JVM, loads a configuration from application resources, if exist; otherwise, reads a configuration from a file.
27+
* On JVM, loads a configuration from application resources, if exists; otherwise, reads a configuration from a file.
2828
* On Native, always reads a configuration from a file.
2929
*/
3030
public expect fun YamlConfig(path: String?): YamlConfig?
3131

3232
/**
3333
* Implements [ApplicationConfig] by loading a configuration from a YAML file.
34-
* Values can reference to environment variables with `$ENV_VAR` syntax.
34+
* Values can reference to environment variables with `$ENV_VAR` or `"$ENV_VAR:default_value"` syntax.
3535
*/
3636
public class YamlConfig(private val yaml: YamlMap) : ApplicationConfig {
3737

@@ -125,9 +125,18 @@ public class YamlConfig(private val yaml: YamlMap) : ApplicationConfig {
125125
private fun resolveValue(value: String): String {
126126
val isEnvVariable = value.startsWith("\$")
127127
if (!isEnvVariable) return value
128-
val key = value.drop(1)
128+
val keyWithDefault = value.drop(1)
129+
val separatorIndex = keyWithDefault.indexOf(':')
130+
val (key, default) = if (separatorIndex == -1) {
131+
keyWithDefault to null
132+
} else {
133+
keyWithDefault.substring(0, separatorIndex) to keyWithDefault.substring(separatorIndex + 1)
134+
}
129135
return getEnvironmentValue(key)
130-
?: throw ApplicationConfigurationException("Environment variable \"$key\" not found")
136+
?: default
137+
?: throw ApplicationConfigurationException(
138+
"Environment variable \"$key\" not found and no default value is present"
139+
)
131140
}
132141

133142
internal expect fun getEnvironmentValue(key: String): String?

ktor-server/ktor-server-config-yaml/jvmAndNix/test/YamlConfigTest.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,34 @@ class YamlConfigTest {
133133
}
134134
}
135135

136+
@Test
137+
fun testMissingEnvironmentVariableWithDefault() {
138+
val content = """
139+
ktor:
140+
variable: "${'$'}NON_EXISTING_VARIABLE:DEFAULT_VALUE"
141+
""".trimIndent()
142+
val yaml = Yaml.decodeYamlFromString(content)
143+
val config = YamlConfig(yaml as YamlMap)
144+
config.checkEnvironmentVariables()
145+
assertEquals("DEFAULT_VALUE", config.property("ktor.variable").getString())
146+
}
147+
148+
@Test
149+
fun testExistingEnvironmentVariableWithDefault() {
150+
val content = """
151+
ktor:
152+
variable: "${'$'}PATH:DEFAULT_VALUE"
153+
""".trimIndent()
154+
val yaml = Yaml.decodeYamlFromString(content)
155+
val config = YamlConfig(yaml as YamlMap)
156+
config.checkEnvironmentVariables()
157+
158+
val value = config.property("ktor.variable").getString()
159+
assertTrue(value.isNotEmpty())
160+
assertFalse(value.contains("PATH"))
161+
assertFalse(value.contains("DEFAULT_VALUE"))
162+
}
163+
136164
@Test
137165
fun testToMap() {
138166
val content = """

0 commit comments

Comments
 (0)