Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
dawkaka committed Aug 11, 2024
2 parents d07a00a + c5c51bb commit 361af49
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 7 deletions.
32 changes: 31 additions & 1 deletion ApiToolKit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.Diagnostics;
using Microsoft.Extensions.DependencyInjection;
using System.Text.Json;
using static System.Web.HttpUtility;

Expand Down Expand Up @@ -424,6 +425,31 @@ public class ATError
public string StackTrace { get; set; }
}

public interface IApiToolkitClientFactory
{
HttpClient CreateClient(ATOptions options);
}

public class ApiToolkitClientFactory : IApiToolkitClientFactory
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly IServiceProvider _serviceProvider;

public ApiToolkitClientFactory(IHttpClientFactory httpClientFactory, IServiceProvider serviceProvider)
{
_httpClientFactory = httpClientFactory;
_serviceProvider = serviceProvider;
}

public HttpClient CreateClient(ATOptions options)
{
var client = _httpClientFactory.CreateClient();

var handler = _serviceProvider.GetRequiredService<ObservingHandler>();
handler.SetOptions(options);
return new HttpClient(handler);
}
}

public class ATOptions
{
Expand All @@ -436,9 +462,13 @@ public class ObservingHandler : DelegatingHandler
{
private readonly HttpContext _context;
private readonly Func<Payload, Task> _publishMessageAsync;
private readonly ATOptions _options;
private ATOptions _options;
private readonly string _project_id;
private readonly string? _msg_id;

Check warning on line 467 in ApiToolKit.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
public void SetOptions(ATOptions options)
{
_options = options;
}
public ObservingHandler(Func<Payload, Task> publishMessage, string project_id, HttpContext? httpContext = null, ATOptions? options = null) : base(new HttpClientHandler())

Check warning on line 472 in ApiToolKit.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 472 in ApiToolKit.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
_context = httpContext ?? throw new ArgumentNullException(nameof(httpContext));
Expand Down
75 changes: 74 additions & 1 deletion ApiToolkitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Builder;

using Moq;
using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
public class RedactTests
{
[Test]
Expand Down Expand Up @@ -208,3 +210,74 @@ public async Task MiddlewareTest_ReturnsNotFoundForRequest()
}
}


public class ApiToolkitClientFactoryTests
{
private Mock<IHttpClientFactory> _httpClientFactoryMock;
private Mock<IServiceProvider> _serviceProviderMock;
private Mock<ObservingHandler> _observingHandlerMock;
private IApiToolkitClientFactory _apiToolkitClientFactory;

[SetUp]
public void SetUp()
{
_httpClientFactoryMock = new Mock<IHttpClientFactory>();
_serviceProviderMock = new Mock<IServiceProvider>();
_observingHandlerMock = new Mock<ObservingHandler>();

// Set up the service provider to return the observing handler mock
_serviceProviderMock
.Setup(sp => sp.GetService(typeof(ObservingHandler)))
.Returns(_observingHandlerMock.Object);

// Initialize the ApiToolkitClientFactory with mocks
_apiToolkitClientFactory = new ApiToolkitClientFactory(_httpClientFactoryMock.Object, _serviceProviderMock.Object);
}

[Test]
public void CreateClient_ShouldReturnHttpClient_WithConfiguredHandler()
{
// Arrange
var options = new ATOptions
{
PathWildCard = "/posts/{id}",
RedactHeaders = new List<string> { "User-Agent" },
RedactRequestBody = new List<string> { "$.user.password" },
RedactResponseBody = new List<string> { "$.user.data.email" }
};

// Act
var client = _apiToolkitClientFactory.CreateClient(options);

// Assert
Assert.NotNull(client);
_observingHandlerMock.Verify(h => h.SetOptions(options), Times.Once);
}

[Test]
public void CreateClient_ShouldUseObservingHandler_FromServiceProvider()
{
// Act
var client = _apiToolkitClientFactory.CreateClient(new ATOptions());

// Assert
_serviceProviderMock.Verify(sp => sp.GetService(typeof(ObservingHandler)), Times.Once);
}

[Test]
public void CreateClient_ShouldThrowException_WhenHandlerNotRegistered()
{
// Arrange
var invalidServiceProvider = new Mock<IServiceProvider>();
invalidServiceProvider.Setup(sp => sp.GetService(typeof(ObservingHandler)))
.Returns(null); // Simulate missing handler registration

var factory = new ApiToolkitClientFactory(_httpClientFactoryMock.Object, invalidServiceProvider.Object);

// Act & Assert
Assert.Throws<NullReferenceException>(() => factory.CreateClient(new ATOptions()));
}
}



75 changes: 70 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

## .NET Core SDK

[![APItoolkit SDK](https://img.shields.io/badge/APItoolkit-SDK-0068ff?logo=dotnet)](https://github.com/topics/apitoolkit-sdk) [![Join Discord Server](https://img.shields.io/badge/Chat-Discord-7289da)](https://discord.gg/dEB6EjQnKB) [![APItoolkit Docs](https://img.shields.io/badge/Read-Docs-0068ff)](https://apitoolkit.io/docs/sdks/dotnet/dotnetcore?utm_source=github-sdks) [![Build Status](https://github.com/apitoolkit/apitoolkit-dotnet/workflows/.NET/badge.svg)](https://github.com/apitoolkit/apitoolkit-dotnet1/actions?query=workflow%3ACI) [![NuGet](https://img.shields.io/nuget/v/ApiToolkit.Net.svg)](https://nuget.org/packages/ApiToolkit.Net) [![Nuget](https://img.shields.io/nuget/dt/ApiToolkit.Net.svg)](https://nuget.org/packages/ApiToolkit.Net)
[![APItoolkit SDK](https://img.shields.io/badge/APItoolkit-SDK-0068ff?logo=dotnet)](https://github.com/topics/apitoolkit-sdk) [![Join Discord Server](https://img.shields.io/badge/Chat-Discord-7289da)](https://apitoolkit.io/discord?utm_campaign=devrel&utm_medium=github&utm_source=sdks_readme) [![APItoolkit Docs](https://img.shields.io/badge/Read-Docs-0068ff)](https://apitoolkit.io/docs/sdks/dotnet/dotnetcore?utm_campaign=devrel&utm_medium=github&utm_source=sdks_readme) [![Build Status](https://github.com/apitoolkit/apitoolkit-dotnet/workflows/.NET/badge.svg)](https://github.com/apitoolkit/apitoolkit-dotnet1/actions?query=workflow%3ACI) [![NuGet](https://img.shields.io/nuget/v/ApiToolkit.Net.svg)](https://nuget.org/packages/ApiToolkit.Net) [![Nuget](https://img.shields.io/nuget/dt/ApiToolkit.Net.svg)](https://nuget.org/packages/ApiToolkit.Net)

APItoolkit is an end-to-end API and web services management toolkit for engineers and customer support teams. To integrate .Net web services with APItoolkit, you need to use this SDK to monitor incoming traffic, aggregate the requests, and then deliver them to the APItoolkit's servers.

Expand Down Expand Up @@ -38,6 +38,11 @@ Next, initialize APItoolkit in your application's entry point (e.g., `Program.cs
using ApiToolkit.Net;

// Initialize the APItoolkit client
builder.Services.AddTransient<ObservingHandler>();

// Register the custom API Toolkit Client Factory
builder.Services.AddSingleton<IApiToolkitClientFactory, ApiToolkitClientFactory>();

var config = new Config
{
ApiKey = "{ENTER_YOUR_API_KEY_HERE}",
Expand All @@ -60,22 +65,82 @@ app.Use(async (context, next) =>
# ...
```

## Usage

You can now use the IApiToolKitClientFactory Interface to directly make your Http requests

```csharp
public class MyService
{
private readonly IApiToolkitClientFactory _apiToolkitClientFactory;

public MyService(IApiToolkitClientFactory apiToolkitClientFactory)
{
_apiToolkitClientFactory = apiToolkitClientFactory;
}

public async Task<string> GetPostAsync()
{
var options = new ATOptions
{
PathWildCard = "/posts/{id}",
RedactHeaders = new[] { "User-Agent" },
RedactRequestBody = new[] { "$.user.password" },
RedactResponseBody = new[] { "$.user.data.email" }
};

var client = _apiToolkitClientFactory.CreateClient(options);
var response = await client.GetAsync("https://jsonplaceholder.typicode.com/posts/1");
return await response.Content.ReadAsStringAsync();
}
}
```

Traditional Middleware Setup
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):

```csharp
using ApiToolkit.Net;

// Initialize the APItoolkit client
var config = new Config
{
ApiKey = "{ENTER_YOUR_API_KEY_HERE}",
Debug = false,
Tags = new List<string> { "environment: production", "region: us-east-1" },
ServiceVersion: "v2.0",
};
var client = await APIToolkit.NewClientAsync(config);

// Register the middleware to use the initialized client
app.Use(async (context, next) =>
{
var apiToolkit = new APIToolkit(next, client);
await apiToolkit.InvokeAsync(context);
});

// app.UseEndpoint(..)
// other middleware and logic
// ...
```


> [!NOTE]
>
> - Please make sure the APItoolkit middleware is added before `UseEndpoint` and other middleware are initialized.
> - The `{ENTER_YOUR_API_KEY_HERE}` demo string should be replaced with the [API key](https://apitoolkit.io/docs/dashboard/settings-pages/api-keys?utm_source=github-sdks) generated from the APItoolkit dashboard.
> - The `{ENTER_YOUR_API_KEY_HERE}` demo string should be replaced with the [API key](https://apitoolkit.io/docs/dashboard/settings-pages/api-keys?utm_campaign=devrel&utm_medium=github&utm_source=sdks_readme) generated from the APItoolkit dashboard.
<br />

> [!IMPORTANT]
>
> To learn more configuration options (redacting fields, error reporting, outgoing requests, etc.), please read this [SDK documentation](https://apitoolkit.io/docs/sdks/dotnet/dotnetcore?utm_source=github-sdks).
> To learn more configuration options (redacting fields, error reporting, outgoing requests, etc.), please read this [SDK documentation](https://apitoolkit.io/docs/sdks/dotnet/dotnetcore?utm_campaign=devrel&utm_medium=github&utm_source=sdks_readme).
## Contributing and Help

To contribute to the development of this SDK or request help from the community and our team, kindly do any of the following:
- Read our [Contributors Guide](https://github.com/apitoolkit/.github/blob/main/CONTRIBUTING.md).
- Join our community [Discord Server](https://discord.gg/dEB6EjQnKB).
- Join our community [Discord Server](https://apitoolkit.io/discord?utm_campaign=devrel&utm_medium=github&utm_source=sdks_readme).
- Create a [new issue](https://github.com/apitoolkit/apitoolkit-dotnet/issues/new/choose) in this repository.

## License
Expand All @@ -86,6 +151,6 @@ This repository is published under the [MIT](LICENSE) license.

<div align="center">

<a href="https://apitoolkit.io?utm_source=github-sdks" target="_blank" rel="noopener noreferrer"><img src="https://github.com/apitoolkit/.github/blob/main/images/icon.png?raw=true" width="40" /></a>
<a href="https://apitoolkit.io?utm_campaign=devrel&utm_medium=github&utm_source=sdks_readme" target="_blank" rel="noopener noreferrer"><img src="https://github.com/apitoolkit/.github/blob/main/images/icon.png?raw=true" width="40" /></a>

</div>
1 change: 1 addition & 0 deletions apitoolkit-dotnet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="7.0.5" />
<!-- Deprecated -->
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.2" />
<PackageReference Include="NUnit" Version="3.13.3" />
Expand Down

0 comments on commit 361af49

Please sign in to comment.