-
Notifications
You must be signed in to change notification settings - Fork 242
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add server variable substitution logic. (#1783)
* Add server variable substitution logic.
- Loading branch information
1 parent
aa62dc0
commit 42dda81
Showing
9 changed files
with
283 additions
and
10 deletions.
There are no files selected for viewing
57 changes: 57 additions & 0 deletions
57
src/Microsoft.OpenApi/Extensions/OpenApiServerExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using Microsoft.OpenApi.Models; | ||
using Microsoft.OpenApi.Properties; | ||
|
||
namespace Microsoft.OpenApi.Extensions; | ||
|
||
/// <summary> | ||
/// Extension methods for <see cref="OpenApiServer"/> serialization. | ||
/// </summary> | ||
public static class OpenApiServerExtensions | ||
{ | ||
/// <summary> | ||
/// Replaces URL variables in a server's URL | ||
/// </summary> | ||
/// <param name="server">The OpenAPI server object</param> | ||
/// <param name="values">The server variable values that will be used to replace the default values.</param> | ||
/// <returns>A URL with the provided variables substituted.</returns> | ||
/// <exception cref="ArgumentException"> | ||
/// Thrown when: | ||
/// 1. A substitution has no valid value in both the supplied dictionary and the default | ||
/// 2. A substitution's value is not available in the enum provided | ||
/// </exception> | ||
public static string ReplaceServerUrlVariables(this OpenApiServer server, IDictionary<string, string> values = null) | ||
{ | ||
var parsedUrl = server.Url; | ||
foreach (var variable in server.Variables) | ||
{ | ||
// Try to get the value from the provided values | ||
if (values is not { } v || !v.TryGetValue(variable.Key, out var value) || string.IsNullOrEmpty(value)) | ||
{ | ||
// Fall back to the default value | ||
value = variable.Value.Default; | ||
} | ||
|
||
// Validate value | ||
if (string.IsNullOrEmpty(value)) | ||
{ | ||
// According to the spec, the variable's default value is required. | ||
// This code path should be hit when a value isn't provided & a default value isn't available | ||
throw new ArgumentException( | ||
string.Format(SRResource.ParseServerUrlDefaultValueNotAvailable, variable.Key), nameof(server)); | ||
} | ||
|
||
// If an enum is provided, the array should not be empty & the value should exist in the enum | ||
if (variable.Value.Enum is {} e && (e.Count == 0 || !e.Contains(value))) | ||
{ | ||
throw new ArgumentException( | ||
string.Format(SRResource.ParseServerUrlValueNotValid, value, variable.Key), nameof(values)); | ||
} | ||
|
||
parsedUrl = parsedUrl.Replace($"{{{variable.Key}}}", value); | ||
} | ||
|
||
return parsedUrl; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
104 changes: 104 additions & 0 deletions
104
test/Microsoft.OpenApi.Tests/Extensions/OpenApiServerExtensionsTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using FluentAssertions; | ||
using Microsoft.OpenApi.Extensions; | ||
using Microsoft.OpenApi.Models; | ||
using Xunit; | ||
|
||
namespace Microsoft.OpenApi.Tests.Extensions; | ||
|
||
public class OpenApiServerExtensionsTests | ||
{ | ||
[Fact] | ||
public void ShouldSubstituteServerVariableWithProvidedValues() | ||
{ | ||
var variable = new OpenApiServer | ||
{ | ||
Url = "http://example.com/api/{version}", | ||
Description = string.Empty, | ||
Variables = new Dictionary<string, OpenApiServerVariable> | ||
{ | ||
{ "version", new OpenApiServerVariable { Default = "v1", Enum = ["v1", "v2"]} } | ||
} | ||
}; | ||
|
||
var url = variable.ReplaceServerUrlVariables(new Dictionary<string, string> {{"version", "v2"}}); | ||
|
||
url.Should().Be("http://example.com/api/v2"); | ||
} | ||
|
||
[Fact] | ||
public void ShouldSubstituteServerVariableWithDefaultValues() | ||
{ | ||
var variable = new OpenApiServer | ||
{ | ||
Url = "http://example.com/api/{version}", | ||
Description = string.Empty, | ||
Variables = new Dictionary<string, OpenApiServerVariable> | ||
{ | ||
{ "version", new OpenApiServerVariable { Default = "v1", Enum = ["v1", "v2"]} } | ||
} | ||
}; | ||
|
||
var url = variable.ReplaceServerUrlVariables(new Dictionary<string, string>(0)); | ||
|
||
url.Should().Be("http://example.com/api/v1"); | ||
} | ||
|
||
[Fact] | ||
public void ShouldFailIfNoValueIsAvailable() | ||
{ | ||
var variable = new OpenApiServer | ||
{ | ||
Url = "http://example.com/api/{version}", | ||
Description = string.Empty, | ||
Variables = new Dictionary<string, OpenApiServerVariable> | ||
{ | ||
{ "version", new OpenApiServerVariable { Enum = ["v1", "v2"]} } | ||
} | ||
}; | ||
|
||
Assert.Throws<ArgumentException>(() => | ||
{ | ||
variable.ReplaceServerUrlVariables(new Dictionary<string, string>(0)); | ||
}); | ||
} | ||
|
||
[Fact] | ||
public void ShouldFailIfProvidedValueIsNotInEnum() | ||
{ | ||
var variable = new OpenApiServer | ||
{ | ||
Url = "http://example.com/api/{version}", | ||
Description = string.Empty, | ||
Variables = new Dictionary<string, OpenApiServerVariable> | ||
{ | ||
{ "version", new OpenApiServerVariable { Enum = ["v1", "v2"]} } | ||
} | ||
}; | ||
|
||
Assert.Throws<ArgumentException>(() => | ||
{ | ||
variable.ReplaceServerUrlVariables(new Dictionary<string, string> {{"version", "v3"}}); | ||
}); | ||
} | ||
|
||
[Fact] | ||
public void ShouldFailIfEnumIsEmpty() | ||
{ | ||
var variable = new OpenApiServer | ||
{ | ||
Url = "http://example.com/api/{version}", | ||
Description = string.Empty, | ||
Variables = new Dictionary<string, OpenApiServerVariable> | ||
{ | ||
{ "version", new OpenApiServerVariable { Enum = []} } | ||
} | ||
}; | ||
|
||
Assert.Throws<ArgumentException>(() => | ||
{ | ||
variable.ReplaceServerUrlVariables(new Dictionary<string, string> {{"version", "v1"}}); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters