Skip to content

Commit c5c51bb

Browse files
authored
Merge pull request #34 from shepherrrd/main
Add Unit Tests for ApiToolkitClientFactory Implementation and Interface Definition for IApiToolkitClientFactory
2 parents f27ba9b + 99b6c27 commit c5c51bb

File tree

4 files changed

+171
-2
lines changed

4 files changed

+171
-2
lines changed

ApiToolKit.cs

+31-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Newtonsoft.Json.Linq;
1010
using Newtonsoft.Json;
1111
using System.Diagnostics;
12+
using Microsoft.Extensions.DependencyInjection;
1213
using System.Text.Json;
1314
using static System.Web.HttpUtility;
1415

@@ -424,6 +425,31 @@ public class ATError
424425
public string StackTrace { get; set; }
425426
}
426427

428+
public interface IApiToolkitClientFactory
429+
{
430+
HttpClient CreateClient(ATOptions options);
431+
}
432+
433+
public class ApiToolkitClientFactory : IApiToolkitClientFactory
434+
{
435+
private readonly IHttpClientFactory _httpClientFactory;
436+
private readonly IServiceProvider _serviceProvider;
437+
438+
public ApiToolkitClientFactory(IHttpClientFactory httpClientFactory, IServiceProvider serviceProvider)
439+
{
440+
_httpClientFactory = httpClientFactory;
441+
_serviceProvider = serviceProvider;
442+
}
443+
444+
public HttpClient CreateClient(ATOptions options)
445+
{
446+
var client = _httpClientFactory.CreateClient();
447+
448+
var handler = _serviceProvider.GetRequiredService<ObservingHandler>();
449+
handler.SetOptions(options);
450+
return new HttpClient(handler);
451+
}
452+
}
427453

428454
public class ATOptions
429455
{
@@ -436,9 +462,13 @@ public class ObservingHandler : DelegatingHandler
436462
{
437463
private readonly HttpContext _context;
438464
private readonly Func<Payload, Task> _publishMessageAsync;
439-
private readonly ATOptions _options;
465+
private ATOptions _options;
440466
private readonly string _project_id;
441467
private readonly string? _msg_id;
468+
public void SetOptions(ATOptions options)
469+
{
470+
_options = options;
471+
}
442472
public ObservingHandler(Func<Payload, Task> publishMessage, string project_id, HttpContext? httpContext = null, ATOptions? options = null) : base(new HttpClientHandler())
443473
{
444474
_context = httpContext ?? throw new ArgumentNullException(nameof(httpContext));

ApiToolkitTests.cs

+74-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
using Microsoft.AspNetCore.Hosting;
1111
using Microsoft.Extensions.Hosting;
1212
using Microsoft.AspNetCore.Builder;
13-
13+
using Moq;
14+
using System.Net.Http;
15+
using Microsoft.Extensions.DependencyInjection;
1416
public class RedactTests
1517
{
1618
[Test]
@@ -208,3 +210,74 @@ public async Task MiddlewareTest_ReturnsNotFoundForRequest()
208210
}
209211
}
210212

213+
214+
public class ApiToolkitClientFactoryTests
215+
{
216+
private Mock<IHttpClientFactory> _httpClientFactoryMock;
217+
private Mock<IServiceProvider> _serviceProviderMock;
218+
private Mock<ObservingHandler> _observingHandlerMock;
219+
private IApiToolkitClientFactory _apiToolkitClientFactory;
220+
221+
[SetUp]
222+
public void SetUp()
223+
{
224+
_httpClientFactoryMock = new Mock<IHttpClientFactory>();
225+
_serviceProviderMock = new Mock<IServiceProvider>();
226+
_observingHandlerMock = new Mock<ObservingHandler>();
227+
228+
// Set up the service provider to return the observing handler mock
229+
_serviceProviderMock
230+
.Setup(sp => sp.GetService(typeof(ObservingHandler)))
231+
.Returns(_observingHandlerMock.Object);
232+
233+
// Initialize the ApiToolkitClientFactory with mocks
234+
_apiToolkitClientFactory = new ApiToolkitClientFactory(_httpClientFactoryMock.Object, _serviceProviderMock.Object);
235+
}
236+
237+
[Test]
238+
public void CreateClient_ShouldReturnHttpClient_WithConfiguredHandler()
239+
{
240+
// Arrange
241+
var options = new ATOptions
242+
{
243+
PathWildCard = "/posts/{id}",
244+
RedactHeaders = new List<string> { "User-Agent" },
245+
RedactRequestBody = new List<string> { "$.user.password" },
246+
RedactResponseBody = new List<string> { "$.user.data.email" }
247+
};
248+
249+
// Act
250+
var client = _apiToolkitClientFactory.CreateClient(options);
251+
252+
// Assert
253+
Assert.NotNull(client);
254+
_observingHandlerMock.Verify(h => h.SetOptions(options), Times.Once);
255+
}
256+
257+
[Test]
258+
public void CreateClient_ShouldUseObservingHandler_FromServiceProvider()
259+
{
260+
// Act
261+
var client = _apiToolkitClientFactory.CreateClient(new ATOptions());
262+
263+
// Assert
264+
_serviceProviderMock.Verify(sp => sp.GetService(typeof(ObservingHandler)), Times.Once);
265+
}
266+
267+
[Test]
268+
public void CreateClient_ShouldThrowException_WhenHandlerNotRegistered()
269+
{
270+
// Arrange
271+
var invalidServiceProvider = new Mock<IServiceProvider>();
272+
invalidServiceProvider.Setup(sp => sp.GetService(typeof(ObservingHandler)))
273+
.Returns(null); // Simulate missing handler registration
274+
275+
var factory = new ApiToolkitClientFactory(_httpClientFactoryMock.Object, invalidServiceProvider.Object);
276+
277+
// Act & Assert
278+
Assert.Throws<NullReferenceException>(() => factory.CreateClient(new ATOptions()));
279+
}
280+
}
281+
282+
283+

README.md

+65
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ Next, initialize APItoolkit in your application's entry point (e.g., `Program.cs
3838
using ApiToolkit.Net;
3939

4040
// Initialize the APItoolkit client
41+
builder.Services.AddTransient<ObservingHandler>();
42+
43+
// Register the custom API Toolkit Client Factory
44+
builder.Services.AddSingleton<IApiToolkitClientFactory, ApiToolkitClientFactory>();
45+
4146
var config = new Config
4247
{
4348
ApiKey = "{ENTER_YOUR_API_KEY_HERE}",
@@ -60,6 +65,66 @@ app.Use(async (context, next) =>
6065
# ...
6166
```
6267

68+
## Usage
69+
70+
You can now use the IApiToolKitClientFactory Interface to directly make your Http requests
71+
72+
```csharp
73+
public class MyService
74+
{
75+
private readonly IApiToolkitClientFactory _apiToolkitClientFactory;
76+
77+
public MyService(IApiToolkitClientFactory apiToolkitClientFactory)
78+
{
79+
_apiToolkitClientFactory = apiToolkitClientFactory;
80+
}
81+
82+
public async Task<string> GetPostAsync()
83+
{
84+
var options = new ATOptions
85+
{
86+
PathWildCard = "/posts/{id}",
87+
RedactHeaders = new[] { "User-Agent" },
88+
RedactRequestBody = new[] { "$.user.password" },
89+
RedactResponseBody = new[] { "$.user.data.email" }
90+
};
91+
92+
var client = _apiToolkitClientFactory.CreateClient(options);
93+
var response = await client.GetAsync("https://jsonplaceholder.typicode.com/posts/1");
94+
return await response.Content.ReadAsStringAsync();
95+
}
96+
}
97+
```
98+
99+
Traditional Middleware Setup
100+
If you prefer to set up the middleware traditionally, here's how you can initialize APItoolkit in your application's entry point (e.g., Program.cs):
101+
102+
```csharp
103+
using ApiToolkit.Net;
104+
105+
// Initialize the APItoolkit client
106+
var config = new Config
107+
{
108+
ApiKey = "{ENTER_YOUR_API_KEY_HERE}",
109+
Debug = false,
110+
Tags = new List<string> { "environment: production", "region: us-east-1" },
111+
ServiceVersion: "v2.0",
112+
};
113+
var client = await APIToolkit.NewClientAsync(config);
114+
115+
// Register the middleware to use the initialized client
116+
app.Use(async (context, next) =>
117+
{
118+
var apiToolkit = new APIToolkit(next, client);
119+
await apiToolkit.InvokeAsync(context);
120+
});
121+
122+
// app.UseEndpoint(..)
123+
// other middleware and logic
124+
// ...
125+
```
126+
127+
63128
> [!NOTE]
64129
>
65130
> - Please make sure the APItoolkit middleware is added before `UseEndpoint` and other middleware are initialized.

apitoolkit-dotnet.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="7.0.5" />
2929
<!-- Deprecated -->
3030
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
31+
<PackageReference Include="Moq" Version="4.20.70" />
3132
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
3233
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.2" />
3334
<PackageReference Include="NUnit" Version="3.13.3" />

0 commit comments

Comments
 (0)