diff --git a/docs/testing.md b/docs/testing.md
index 1a2c24ec..af151c70 100644
--- a/docs/testing.md
+++ b/docs/testing.md
@@ -19,8 +19,10 @@ IGeoLocationApiClient
├── .GeoLookup (IVersionedGeoLookupApi)
│ ├── .V1 (IGeoLookupApi) → GetGeoLocation, GetGeoLocations, DeleteMetadata
│ └── .V1_1 (IGeoLookupApi) → GetCityGeoLocation, GetInsightsGeoLocation
-├── .ApiInfo (IApiInfoApi) → GetApiInfo
-└── .ApiHealth (IApiHealthApi) → CheckHealth
+├── .ApiInfo (IVersionedApiInfoApi)
+│ └── .V1 (IApiInfoApi) → GetApiInfo
+└── .ApiHealth (IVersionedApiHealthApi)
+ └── .V1 (IApiHealthApi) → CheckHealth
```
Without the testing package, each test needs 3+ levels of nested mocks just to call a single method. Additionally, all DTO properties use `internal set`, so external consumers cannot construct DTOs with custom values.
diff --git a/src/MX.GeoLocation.Abstractions.V1/Interfaces/IVersionedGeoLookupApi.cs b/src/MX.GeoLocation.Abstractions.V1/Interfaces/IVersionedGeoLookupApi.cs
deleted file mode 100644
index 0a68f469..00000000
--- a/src/MX.GeoLocation.Abstractions.V1/Interfaces/IVersionedGeoLookupApi.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using MX.GeoLocation.Abstractions.Interfaces.V1;
-
-namespace MX.GeoLocation.Abstractions.Interfaces
-{
- ///
- /// Provides versioned access to geo lookup APIs
- ///
- public interface IVersionedGeoLookupApi
- {
- ///
- /// Gets the V1 implementation of the geo lookup API
- ///
- V1.IGeoLookupApi V1 { get; }
-
- ///
- /// Gets the V1.1 implementation of the geo lookup API
- ///
- V1_1.IGeoLookupApi V1_1 { get; }
- }
-}
diff --git a/src/MX.GeoLocation.Abstractions.V1/README.md b/src/MX.GeoLocation.Abstractions.V1/README.md
index e924addf..de9bab79 100644
--- a/src/MX.GeoLocation.Abstractions.V1/README.md
+++ b/src/MX.GeoLocation.Abstractions.V1/README.md
@@ -35,15 +35,7 @@ public interface IGeoLookupApi
### IVersionedGeoLookupApi
-Wraps both API versions for version-aware consumers:
-
-```csharp
-public interface IVersionedGeoLookupApi
-{
- V1.IGeoLookupApi V1 { get; }
- V1_1.IGeoLookupApi V1_1 { get; }
-}
-```
+> **Note:** Version selector interfaces (`IVersionedGeoLookupApi`, `IVersionedApiHealthApi`, `IVersionedApiInfoApi`) are defined in the `MX.GeoLocation.Api.Client.V1` package, not in this abstractions package.
## Data Models
diff --git a/src/MX.GeoLocation.Api.Client.Testing.Tests/FakeGeoLocationApiClientTests.cs b/src/MX.GeoLocation.Api.Client.Testing.Tests/FakeGeoLocationApiClientTests.cs
index d9927630..7512d0a2 100644
--- a/src/MX.GeoLocation.Api.Client.Testing.Tests/FakeGeoLocationApiClientTests.cs
+++ b/src/MX.GeoLocation.Api.Client.Testing.Tests/FakeGeoLocationApiClientTests.cs
@@ -38,7 +38,7 @@ public async Task ApiInfo_DelegatesToInfoFake()
var client = new FakeGeoLocationApiClient();
client.InfoApi.WithInfo(GeoLocationDtoFactory.CreateApiInfo(buildVersion: "2.0.0.1"));
- var result = await client.ApiInfo.GetApiInfo();
+ var result = await client.ApiInfo.V1.GetApiInfo();
Assert.Equal("2.0.0.1", result.Result!.Data!.BuildVersion);
}
@@ -49,7 +49,7 @@ public async Task ApiHealth_DelegatesToHealthFake()
var client = new FakeGeoLocationApiClient();
client.HealthApi.WithStatusCode(System.Net.HttpStatusCode.ServiceUnavailable);
- var result = await client.ApiHealth.CheckHealth();
+ var result = await client.ApiHealth.V1.CheckHealth();
Assert.Equal(System.Net.HttpStatusCode.ServiceUnavailable, result.StatusCode);
}
diff --git a/src/MX.GeoLocation.Api.Client.Testing.Tests/ServiceCollectionExtensionsTests.cs b/src/MX.GeoLocation.Api.Client.Testing.Tests/ServiceCollectionExtensionsTests.cs
index 5244481b..78ba1d2b 100644
--- a/src/MX.GeoLocation.Api.Client.Testing.Tests/ServiceCollectionExtensionsTests.cs
+++ b/src/MX.GeoLocation.Api.Client.Testing.Tests/ServiceCollectionExtensionsTests.cs
@@ -26,6 +26,8 @@ public void AddFakeGeoLocationApiClient_RegistersAllServices()
Assert.NotNull(provider.GetRequiredService());
Assert.NotNull(provider.GetRequiredService());
+ Assert.NotNull(provider.GetRequiredService());
+ Assert.NotNull(provider.GetRequiredService());
Assert.NotNull(provider.GetRequiredService());
Assert.NotNull(provider.GetRequiredService());
Assert.NotNull(provider.GetRequiredService());
diff --git a/src/MX.GeoLocation.Api.Client.Testing/FakeGeoLocationApiClient.cs b/src/MX.GeoLocation.Api.Client.Testing/FakeGeoLocationApiClient.cs
index c2c4fa05..d3f4ce0a 100644
--- a/src/MX.GeoLocation.Api.Client.Testing/FakeGeoLocationApiClient.cs
+++ b/src/MX.GeoLocation.Api.Client.Testing/FakeGeoLocationApiClient.cs
@@ -6,6 +6,32 @@
namespace MX.GeoLocation.Api.Client.Testing;
+///
+/// In-memory fake of for tests.
+///
+public class FakeVersionedApiHealthApi : IVersionedApiHealthApi
+{
+ public FakeVersionedApiHealthApi(FakeApiHealthApi v1)
+ {
+ V1 = v1;
+ }
+
+ public IApiHealthApi V1 { get; }
+}
+
+///
+/// In-memory fake of for tests.
+///
+public class FakeVersionedApiInfoApi : IVersionedApiInfoApi
+{
+ public FakeVersionedApiInfoApi(FakeApiInfoApi v1)
+ {
+ V1 = v1;
+ }
+
+ public IApiInfoApi V1 { get; }
+}
+
///
/// In-memory fake of composing the V1 and V1.1 fakes.
///
@@ -61,15 +87,19 @@ public class FakeGeoLocationApiClient : IGeoLocationApiClient
public FakeApiHealthApi HealthApi { get; } = new();
private readonly Lazy _geoLookup;
+ private readonly Lazy _apiHealth;
+ private readonly Lazy _apiInfo;
public FakeGeoLocationApiClient()
{
_geoLookup = new Lazy(() => new FakeVersionedGeoLookupApi(V1Lookup, V1_1Lookup));
+ _apiHealth = new Lazy(() => new FakeVersionedApiHealthApi(HealthApi));
+ _apiInfo = new Lazy(() => new FakeVersionedApiInfoApi(InfoApi));
}
public IVersionedGeoLookupApi GeoLookup => _geoLookup.Value;
- public IApiInfoApi ApiInfo => InfoApi;
- public IApiHealthApi ApiHealth => HealthApi;
+ public IVersionedApiInfoApi ApiInfo => _apiInfo.Value;
+ public IVersionedApiHealthApi ApiHealth => _apiHealth.Value;
///
/// Resets all fakes to their initial state, clearing configured responses,
diff --git a/src/MX.GeoLocation.Api.Client.Testing/ServiceCollectionExtensions.cs b/src/MX.GeoLocation.Api.Client.Testing/ServiceCollectionExtensions.cs
index dc287764..e35d7095 100644
--- a/src/MX.GeoLocation.Api.Client.Testing/ServiceCollectionExtensions.cs
+++ b/src/MX.GeoLocation.Api.Client.Testing/ServiceCollectionExtensions.cs
@@ -38,6 +38,8 @@ public static IServiceCollection AddFakeGeoLocationApiClient(
services.RemoveAll();
services.RemoveAll();
+ services.RemoveAll();
+ services.RemoveAll();
services.RemoveAll();
services.RemoveAll();
services.RemoveAll();
@@ -45,6 +47,8 @@ public static IServiceCollection AddFakeGeoLocationApiClient(
services.AddSingleton(fakeClient);
services.AddSingleton(fakeClient.GeoLookup);
+ services.AddSingleton(fakeClient.ApiHealth);
+ services.AddSingleton(fakeClient.ApiInfo);
services.AddSingleton(fakeClient.V1Lookup);
services.AddSingleton(fakeClient.V1_1Lookup);
services.AddSingleton(fakeClient.InfoApi);
diff --git a/src/MX.GeoLocation.Api.Client.V1/Api/ApiHealthApi.cs b/src/MX.GeoLocation.Api.Client.V1/Api/V1/ApiHealthApi.cs
similarity index 100%
rename from src/MX.GeoLocation.Api.Client.V1/Api/ApiHealthApi.cs
rename to src/MX.GeoLocation.Api.Client.V1/Api/V1/ApiHealthApi.cs
diff --git a/src/MX.GeoLocation.Api.Client.V1/Api/ApiInfoApi.cs b/src/MX.GeoLocation.Api.Client.V1/Api/V1/ApiInfoApi.cs
similarity index 100%
rename from src/MX.GeoLocation.Api.Client.V1/Api/ApiInfoApi.cs
rename to src/MX.GeoLocation.Api.Client.V1/Api/V1/ApiInfoApi.cs
diff --git a/src/MX.GeoLocation.Api.Client.V1/VersionedGeoLookupApi.cs b/src/MX.GeoLocation.Api.Client.V1/ApiVersionSelectorImplementations.cs
similarity index 51%
rename from src/MX.GeoLocation.Api.Client.V1/VersionedGeoLookupApi.cs
rename to src/MX.GeoLocation.Api.Client.V1/ApiVersionSelectorImplementations.cs
index 5ee2ddfa..e586e413 100644
--- a/src/MX.GeoLocation.Api.Client.V1/VersionedGeoLookupApi.cs
+++ b/src/MX.GeoLocation.Api.Client.V1/ApiVersionSelectorImplementations.cs
@@ -3,28 +3,36 @@
namespace MX.GeoLocation.Api.Client.V1
{
- ///
- /// Provides version-specific access to the GeoLookup API endpoints
- ///
+ // Implementation classes for version selectors
public class VersionedGeoLookupApi : IVersionedGeoLookupApi
{
- ///
- /// Initializes a new instance of the class
- ///
public VersionedGeoLookupApi(IGeoLookupApi v1, Abstractions.Interfaces.V1_1.IGeoLookupApi v1_1)
{
V1 = v1;
V1_1 = v1_1;
}
- ///
- /// Gets the V1 GeoLookup API implementation
- ///
public IGeoLookupApi V1 { get; }
-
- ///
- /// Gets the V1.1 GeoLookup API implementation
- ///
public Abstractions.Interfaces.V1_1.IGeoLookupApi V1_1 { get; }
}
+
+ public class VersionedApiHealthApi : IVersionedApiHealthApi
+ {
+ public VersionedApiHealthApi(IApiHealthApi v1)
+ {
+ V1 = v1;
+ }
+
+ public IApiHealthApi V1 { get; }
+ }
+
+ public class VersionedApiInfoApi : IVersionedApiInfoApi
+ {
+ public VersionedApiInfoApi(IApiInfoApi v1)
+ {
+ V1 = v1;
+ }
+
+ public IApiInfoApi V1 { get; }
+ }
}
diff --git a/src/MX.GeoLocation.Api.Client.V1/ApiVersionSelectors.cs b/src/MX.GeoLocation.Api.Client.V1/ApiVersionSelectors.cs
new file mode 100644
index 00000000..f5c1a9e0
--- /dev/null
+++ b/src/MX.GeoLocation.Api.Client.V1/ApiVersionSelectors.cs
@@ -0,0 +1,22 @@
+using MX.GeoLocation.Abstractions.Interfaces;
+using MX.GeoLocation.Abstractions.Interfaces.V1;
+
+namespace MX.GeoLocation.Api.Client.V1
+{
+ // Version selectors for GeoLookup API (V1 and V1.1)
+ public interface IVersionedGeoLookupApi
+ {
+ IGeoLookupApi V1 { get; }
+ Abstractions.Interfaces.V1_1.IGeoLookupApi V1_1 { get; }
+ }
+
+ public interface IVersionedApiHealthApi
+ {
+ IApiHealthApi V1 { get; }
+ }
+
+ public interface IVersionedApiInfoApi
+ {
+ IApiInfoApi V1 { get; }
+ }
+}
diff --git a/src/MX.GeoLocation.Api.Client.V1/GeoLocationApiClient.cs b/src/MX.GeoLocation.Api.Client.V1/GeoLocationApiClient.cs
index df5692a7..3ad80e03 100644
--- a/src/MX.GeoLocation.Api.Client.V1/GeoLocationApiClient.cs
+++ b/src/MX.GeoLocation.Api.Client.V1/GeoLocationApiClient.cs
@@ -1,6 +1,4 @@
-using MX.GeoLocation.Abstractions.Interfaces;
-
-namespace MX.GeoLocation.Api.Client.V1
+namespace MX.GeoLocation.Api.Client.V1
{
///
/// Implementation of the GeoLocation API client that provides access to versioned API endpoints
@@ -11,9 +9,9 @@ public class GeoLocationApiClient : IGeoLocationApiClient
/// Initializes a new instance of the class
///
/// The versioned GeoLookup API
- /// The API info endpoint
- /// The API health endpoint
- public GeoLocationApiClient(IVersionedGeoLookupApi versionedGeoLookupApi, IApiInfoApi apiInfoApi, IApiHealthApi apiHealthApi)
+ /// The versioned API info endpoint
+ /// The versioned API health endpoint
+ public GeoLocationApiClient(IVersionedGeoLookupApi versionedGeoLookupApi, IVersionedApiInfoApi apiInfoApi, IVersionedApiHealthApi apiHealthApi)
{
GeoLookup = versionedGeoLookupApi;
ApiInfo = apiInfoApi;
@@ -26,13 +24,13 @@ public GeoLocationApiClient(IVersionedGeoLookupApi versionedGeoLookupApi, IApiIn
public IVersionedGeoLookupApi GeoLookup { get; }
///
- /// Gets the API info endpoint
+ /// Gets the versioned API info endpoint
///
- public IApiInfoApi ApiInfo { get; }
+ public IVersionedApiInfoApi ApiInfo { get; }
///
- /// Gets the API health endpoint
+ /// Gets the versioned API health endpoint
///
- public IApiHealthApi ApiHealth { get; }
+ public IVersionedApiHealthApi ApiHealth { get; }
}
}
\ No newline at end of file
diff --git a/src/MX.GeoLocation.Api.Client.V1/IGeoLocationApiClient.cs b/src/MX.GeoLocation.Api.Client.V1/IGeoLocationApiClient.cs
index 910f74ab..c2293ec6 100644
--- a/src/MX.GeoLocation.Api.Client.V1/IGeoLocationApiClient.cs
+++ b/src/MX.GeoLocation.Api.Client.V1/IGeoLocationApiClient.cs
@@ -1,6 +1,4 @@
-using MX.GeoLocation.Abstractions.Interfaces;
-
-namespace MX.GeoLocation.Api.Client.V1
+namespace MX.GeoLocation.Api.Client.V1
{
///
/// Interface for the GeoLocation API client
@@ -13,13 +11,13 @@ public interface IGeoLocationApiClient
IVersionedGeoLookupApi GeoLookup { get; }
///
- /// Gets the API info endpoint
+ /// Gets the versioned API info endpoint
///
- IApiInfoApi ApiInfo { get; }
+ IVersionedApiInfoApi ApiInfo { get; }
///
- /// Gets the API health endpoint
+ /// Gets the versioned API health endpoint
///
- IApiHealthApi ApiHealth { get; }
+ IVersionedApiHealthApi ApiHealth { get; }
}
}
\ No newline at end of file
diff --git a/src/MX.GeoLocation.Api.Client.V1/ServiceCollectionExtensions.cs b/src/MX.GeoLocation.Api.Client.V1/ServiceCollectionExtensions.cs
index e088f2d6..dbda59be 100644
--- a/src/MX.GeoLocation.Api.Client.V1/ServiceCollectionExtensions.cs
+++ b/src/MX.GeoLocation.Api.Client.V1/ServiceCollectionExtensions.cs
@@ -1,6 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
-using MX.GeoLocation.Api.Client.V1;
using MX.GeoLocation.Abstractions.Interfaces;
using MX.GeoLocation.Abstractions.Interfaces.V1;
@@ -35,10 +34,12 @@ public static IServiceCollection AddGeoLocationApiClient(
// Register API health endpoint
serviceCollection.AddTypedApiClient(configureOptions);
- // Register versioned API wrapper
+ // Register version selectors as scoped
serviceCollection.AddScoped();
+ serviceCollection.AddScoped();
+ serviceCollection.AddScoped();
- // Register main client
+ // Register the unified client as scoped
serviceCollection.AddScoped();
return serviceCollection;
diff --git a/src/MX.GeoLocation.Api.V1/Program.cs b/src/MX.GeoLocation.Api.V1/Program.cs
index a878633c..996cc306 100644
--- a/src/MX.GeoLocation.Api.V1/Program.cs
+++ b/src/MX.GeoLocation.Api.V1/Program.cs
@@ -134,6 +134,8 @@
app.MapControllers();
+app.MapGet("/", () => Results.Ok()).ExcludeFromDescription();
+
app.Run();
// Make Program accessible for WebApplicationFactory in integration tests
diff --git a/terraform/azurerm_api_management_product_policy.tf b/terraform/azurerm_api_management_product_policy.tf
index 5556b820..f5f8394b 100644
--- a/terraform/azurerm_api_management_product_policy.tf
+++ b/terraform/azurerm_api_management_product_policy.tf
@@ -10,20 +10,27 @@ resource "azurerm_api_management_product_policy" "api_product_policy" {
-
-
-
- ${local.entra_api_identifier_uri}
-
-
- https://sts.windows.net/${data.azuread_client_config.current.tenant_id}/
-
-
-
- LookupApiUser
-
-
-
+
+
+
+
+
+
+
+
+ ${local.entra_api_identifier_uri}
+
+
+ https://sts.windows.net/${data.azuread_client_config.current.tenant_id}/
+
+
+
+ LookupApiUser
+
+
+
+
+