Skip to content

Commit 947d240

Browse files
authored
[Backend API]Refactor OpenAPI doc version to appsettings.json (#274)
1 parent d7aab48 commit 947d240

File tree

8 files changed

+186
-14
lines changed

8 files changed

+186
-14
lines changed

.github/workflows/azure-dev-build-only.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,7 @@ jobs:
8383
- name: Create openapi.json
8484
shell: pwsh
8585
run: |
86-
$fileContent = Get-Content './src/AzureOpenAIProxy.ApiApp/Constants.cs'
87-
$API_VERSION = [regex]::Match($fileContent, 'public const string Version = "([^"]+)"').Groups[1].Value
86+
$API_VERSION = $(Get-Content ./src/AzureOpenAIProxy.ApiApp/appsettings.json | ConvertFrom-Json).OpenApi.DocVersion
8887
8988
Invoke-WebRequest -Uri "https://localhost:7001/swagger/$API_VERSION/swagger.json" -OutFile "openapi.json"
9089

.github/workflows/azure-dev.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,7 @@ jobs:
9797
- name: Create openapi.json
9898
shell: pwsh
9999
run: |
100-
$fileContent = Get-Content './src/AzureOpenAIProxy.ApiApp/Constants.cs'
101-
$API_VERSION = [regex]::Match($fileContent, 'public const string Version = "([^"]+)"').Groups[1].Value
100+
$API_VERSION = $(Get-Content ./src/AzureOpenAIProxy.ApiApp/appsettings.json | ConvertFrom-Json).OpenApi.DocVersion
102101
103102
Invoke-WebRequest -Uri "https://localhost:7001/swagger/$API_VERSION/swagger.json" -OutFile "openapi.json"
104103
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace AzureOpenAIProxy.ApiApp.Configurations;
2+
3+
/// <summary>
4+
/// This represents the settings entity for Open API.
5+
/// </summary>
6+
public class OpenApiSettings
7+
{
8+
/// <summary>
9+
/// Gets the name of the configuration settings.
10+
/// </summary>
11+
public const string Name = "OpenApi";
12+
13+
/// <summary>
14+
/// Gets or sets the Open API Doc version.
15+
/// </summary>
16+
public string? DocVersion { get; set; } = string.Empty;
17+
}

src/AzureOpenAIProxy.ApiApp/Constants.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,6 @@
55
/// </summary>
66
public static class Constants
77
{
8-
/// <summary>
9-
/// Declares the current version of the API.
10-
/// </summary>
11-
public const string Version = "v1.0.0";
12-
138
/// <summary>
149
/// Declares the title of the OpenAPI doc.
1510
/// </summary>

src/AzureOpenAIProxy.ApiApp/Extensions/ApplicationBuilderExtensions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public static IApplicationBuilder UseSwaggerUI(this WebApplication app, string b
1818
return app;
1919
}
2020

21+
var settings = app.Services.GetOpenApiSettings();
22+
2123
app.UseSwagger(options =>
2224
{
2325
//options.RouteTemplate = $"swagger/{Constants.Version}/swagger.json";
@@ -32,7 +34,7 @@ public static IApplicationBuilder UseSwaggerUI(this WebApplication app, string b
3234

3335
app.UseSwaggerUI(options =>
3436
{
35-
options.SwaggerEndpoint($"{Constants.Version}/swagger.json", Constants.Title);
37+
options.SwaggerEndpoint($"{settings.DocVersion}/swagger.json", Constants.Title);
3638
});
3739

3840
return app;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using AzureOpenAIProxy.ApiApp.Configurations;
2+
3+
namespace AzureOpenAIProxy.ApiApp.Extensions;
4+
5+
/// <summary>
6+
/// This represents the extension entity for the <see cref="OpenApiSettings"/> class.
7+
/// </summary>
8+
public static class OpenApiSettingsExtensions
9+
{
10+
/// <summary>
11+
/// Gets the OpenApi configuration settings by reading appsettings.json.
12+
/// </summary>
13+
/// <param name="serviceProvider"><see cref="IServiceProvider"/> instance.</param>
14+
/// <returns>Returns <see cref="OpenApiSettings"/> instance.</returns>
15+
public static OpenApiSettings GetOpenApiSettings(this IServiceProvider serviceProvider)
16+
{
17+
var configuration = serviceProvider.GetService<IConfiguration>()
18+
?? throw new InvalidOperationException($"{nameof(IConfiguration)} service is not registered.");
19+
20+
var settings = configuration.GetSection(OpenApiSettings.Name).Get<OpenApiSettings>()
21+
?? throw new InvalidOperationException($"{nameof(OpenApiSettings)} could not be retrieved from the configuration.");
22+
23+
return settings;
24+
}
25+
26+
/// <summary>
27+
/// Gets the OpenApi configuration settings by reading appsettings.json.
28+
/// </summary>
29+
/// <param name="services"><see cref="IServiceCollection"/> instance.</param>
30+
/// <returns>Returns <see cref="OpenApiSettings"/> instance.</returns>
31+
public static OpenApiSettings GetOpenApiSettings(this IServiceCollection services)
32+
{
33+
var serviceProvider = services.BuildServiceProvider();
34+
35+
return serviceProvider.GetOpenApiSettings();
36+
}
37+
}

src/AzureOpenAIProxy.ApiApp/Extensions/ServiceCollectionExtensions.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Azure.Identity;
1+
using Azure.Identity;
22
using Azure.Security.KeyVault.Secrets;
33

44
using AzureOpenAIProxy.ApiApp.Builders;
@@ -88,13 +88,15 @@ public static IServiceCollection AddOpenAIService(this IServiceCollection servic
8888
/// <returns>Returns <see cref="IServiceCollection"/> instance.</returns>
8989
public static IServiceCollection AddOpenApiService(this IServiceCollection services)
9090
{
91+
var settings = services.GetOpenApiSettings();
92+
9193
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
9294
services.AddEndpointsApiExplorer();
9395
services.AddSwaggerGen(options =>
9496
{
9597
var info = new OpenApiInfo()
9698
{
97-
Version = Constants.Version,
99+
Version = settings.DocVersion,
98100
Title = Constants.Title,
99101
Description = "Providing a proxy service to Azure OpenAI API",
100102
Contact = new OpenApiContact()
@@ -104,7 +106,7 @@ public static IServiceCollection AddOpenApiService(this IServiceCollection servi
104106
Url = new Uri("https://aka.ms/aoai-proxy.net")
105107
},
106108
};
107-
options.SwaggerDoc(Constants.Version, info);
109+
options.SwaggerDoc(settings.DocVersion, info);
108110

109111
options.AddSecurityDefinition(
110112
"apiKey",
@@ -132,4 +134,4 @@ public static IServiceCollection AddOpenApiService(this IServiceCollection servi
132134

133135
return services;
134136
}
135-
}
137+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
using AzureOpenAIProxy.ApiApp.Extensions;
2+
3+
using FluentAssertions;
4+
5+
using Microsoft.Extensions.Configuration;
6+
using Microsoft.Extensions.DependencyInjection;
7+
8+
using NSubstitute;
9+
10+
namespace AzureOpenAIProxy.ApiApp.Tests.Extensions;
11+
12+
public class OpenApiSettingsExtensionsTests
13+
{
14+
[Fact]
15+
public void Given_Null_OpenApiSettings_When_Added_ToServiceProvider_Then_It_Should_Throw_Exception()
16+
{
17+
// Arrange
18+
var config = default(IConfiguration);
19+
20+
var sp = Substitute.For<IServiceProvider>();
21+
ServiceProviderServiceExtensions.GetService<IConfiguration>(sp).Returns(config);
22+
23+
// Act
24+
Action action = () => sp.GetOpenApiSettings();
25+
26+
// Assert
27+
action.Should().Throw<InvalidOperationException>();
28+
}
29+
30+
[Fact]
31+
public void Given_Empty_OpenApiSettings_When_Added_ToServiceProvider_Then_It_Should_Throw_Exception()
32+
{
33+
// Arrange
34+
var dict = new Dictionary<string, string>()
35+
{
36+
{ "OpenApi", "" }
37+
};
38+
#pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
39+
var config = new ConfigurationBuilder().AddInMemoryCollection(dict).Build();
40+
#pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
41+
42+
var sp = Substitute.For<IServiceProvider>();
43+
ServiceProviderServiceExtensions.GetService<IConfiguration>(sp).Returns(config);
44+
45+
// Act
46+
Action action = () => sp.GetOpenApiSettings();
47+
48+
// Assert
49+
action.Should().Throw<InvalidOperationException>();
50+
}
51+
52+
[Fact]
53+
public void Given_Empty_OpenApiSettings_When_Added_ToServiceCollection_Then_It_Should_Throw_Exception()
54+
{
55+
// Arrange
56+
var dict = new Dictionary<string, string>()
57+
{
58+
{ "OpenApi", "" }
59+
};
60+
#pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
61+
var config = new ConfigurationBuilder().AddInMemoryCollection(dict).Build();
62+
#pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
63+
64+
var sc = new ServiceCollection();
65+
sc.AddSingleton<IConfiguration>(config);
66+
67+
// Act
68+
Action action = () => sc.GetOpenApiSettings();
69+
70+
// Assert
71+
action.Should().Throw<InvalidOperationException>();
72+
}
73+
74+
[Theory]
75+
[InlineData("")]
76+
[InlineData("v1.0.0")]
77+
public void Given_OpenApiSettings_When_Added_ToServiceProvider_Then_It_Should_Return_DocVersion(string docVersion)
78+
{
79+
// Arrange
80+
var dict = new Dictionary<string, string>()
81+
{
82+
{ "OpenApi:DocVersion", docVersion }
83+
};
84+
#pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
85+
var config = new ConfigurationBuilder().AddInMemoryCollection(dict).Build();
86+
#pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
87+
88+
var sp = Substitute.For<IServiceProvider>();
89+
ServiceProviderServiceExtensions.GetService<IConfiguration>(sp).Returns(config);
90+
91+
// Act
92+
var result = sp.GetOpenApiSettings();
93+
94+
// Assert
95+
result.DocVersion.Should().Be(docVersion);
96+
}
97+
98+
[Theory]
99+
[InlineData("")]
100+
[InlineData("v1.0.0")]
101+
public void Given_OpenApiSettings_When_Added_ToServiceCollection_Then_It_Should_Return_DocVersion(string docVersion)
102+
{
103+
// Arrange
104+
var dict = new Dictionary<string, string>()
105+
{
106+
{ "OpenApi:DocVersion", docVersion }
107+
};
108+
#pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
109+
var config = new ConfigurationBuilder().AddInMemoryCollection(dict).Build();
110+
#pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
111+
112+
var sc = new ServiceCollection();
113+
sc.AddSingleton<IConfiguration>(config);
114+
115+
// Act
116+
var result = sc.GetOpenApiSettings();
117+
118+
// Assert
119+
result.DocVersion.Should().Be(docVersion);
120+
}
121+
}

0 commit comments

Comments
 (0)