Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🚀 Feature: Proposal for Building a separate API SDK - "Appwrite.Core" for Modern .NET Version (6+ onwards) Using Refit, System.Text, and HttpClientFactory #25

Closed
2 tasks done
initinll opened this issue Jul 18, 2023 · 4 comments
Assignees
Labels
enhancement New feature or request

Comments

@initinll
Copy link

🔖 Feature description

The proposed feature involves building a separate API SDK - "Appwrite.Core" based on the existing API SDK to make it compatible with modern .NET versions (specifically .NET 6 and beyond). The new approach will utilize the Refit library, System.Text, and HttpClientFactory to optimize the SDK's performance, simplify the development process, and provide a seamless integration experience for developers.

🎤 Pitch

Why Implement this Feature:

Upgrading the API SDK for modern .NET versions is essential to keep up with the latest advancements and ensure that our SDK remains relevant and efficient. By rebuilding the SDK using Refit, System.Text, and HttpClientFactory, we can leverage their capabilities to enhance the overall development experience and the quality of our SDK.

Advantages of the Proposed Approach:

a) Refit Integration:
Refit is a powerful library that simplifies the creation of type-safe API clients. By utilizing Refit, we can eliminate the need for writing boilerplate code to handle HTTP requests and responses. Instead, developers can define API interfaces with attributes, making the SDK more concise and expressive. This will improve the readability and maintainability of the codebase.

Example of using Refit:

[Headers("User-Agent: MyApp")]
public interface IApiClient
{
    [Get("/posts/{id}")]
    Task<Post> GetPostById(int id);
}

b) System.Text for JSON Serialization:
.NET 6 includes significant improvements in System.Text.Json for JSON serialization and deserialization. By adopting System.Text.Json as the default JSON serializer for the SDK, we can benefit from its superior performance and reduced memory allocation compared to third-party libraries. This will lead to faster data processing and a more efficient SDK.

c) HttpClientFactory Integration:
The HttpClientFactory is designed to manage HttpClient instances efficiently, minimizing the overhead of creating new connections for each API request. By integrating HttpClientFactory, we can improve the SDK's performance and mitigate potential issues related to HttpClient misuse, such as socket exhaustion and connection leaks.

Example Implementation details

Get Account

image

using Refit;

namespace Appwrite.Core.Apis;

internal interface IAccount
{
    [Get("/account")]
    Task<User> Get(CancellationToken cancellationToken = default);
}

namespace Appwrite.Core.Services;

public class Account : HttpClientProvider
{
    private readonly IAccount _accountApi;

    public Account(Client client)
    {
        _accountApi = base.GetRestService<IAccount>(client);
    }

    /// <summary>
    /// Get Account
    /// </summary>
    /// <para>Get currently logged in user data as JSON object.</para>
    /// <param name="cancellationToken">Cancellation Token</param>
    /// <returns>User</returns>
    public async Task<User> Get(CancellationToken cancellationToken = default)
    {
        return await _accountApi.Get(cancellationToken);
    }
}

The SDK will automatically handle the HTTP request and response, making the integration process intuitive and efficient.

Example Client invocation:

using Appwrite.Core;
using Appwrite.Core.Services;

var endpoint = String.Empty;
var project = String.Empty;
var apikey = String.Empty;

var client = new Client()
    .SetEndpoint(endpoint)
    .SetProject(project)
    .SetKey(apikey);
try
{
    var account = new Account(client);

    // optional
    CancellationTokenSource newSource = new CancellationTokenSource();
    newSource.Cancel();

    var newTeam = await account.Get(newSource.Token);

    Console.WriteLine("Done !");
}
catch (TaskCanceledException ex)
{
    Console.WriteLine($"TaskCanceledException - {ex.Message}");
}
catch (AppwriteException ex)
{
    Console.WriteLine($"AppwriteException - {ex.Message}");
}
catch (Exception ex)
{
    Console.WriteLine($"Exception - {ex.Message}");
}

🚧 For more implementation details checkout - https://github.com/initinll-forks/sdk-for-dotnet/tree/dotnet-6

👀 Have you spent some time to check if this issue has been raised before?

  • I checked and didn't find similar issue

🏢 Have you read the Code of Conduct?

@joeyouss joeyouss added the enhancement New feature or request label Jul 26, 2023
@adityaoberai
Copy link
Member

adityaoberai commented Jul 26, 2023

Thanks for raising this discussion @initinll

I do have my reservations here for a few reasons:

  1. The addition of Refit increases the number of additional dependencies the SDK would need, which is not something we prefer to do across Appwrite on the whole. Moreover, since we already maintain strong typing by generating models for any kind of response from the Appwrite APIs, I would further question the benefits of this approach.

  2. The way we use HttpClient in the SDK is by substantial limiting its usage to the Client class. This way, we prevent the creation of multiple instances of HttpClient in the first place (thereby, preventing the sockets exhaustion problem). Additionally since we only really maintain a single instance of HttpClient in the Client class, HttpClientFactory may not be necessary here.

  3. Changing the pattern of how the SDK is structured here would deviate us from our policy of maintaining a consistent developer experience across Appwrite SDKs. We can have some more discussion over this, but I'd like to refer you take a look at our sdk-generator repo once as well to understand any further pitfalls this could create (since the SDKs are not manually written).

Additionally, the primary comment on the top refers to making the SDK compatible for modern .NET versions and beyond. Projects targeting .NET Standard 2.0 anyway are compatible across .NET Framework, .NET Core, and modern .NET projects.

@adityaoberai
Copy link
Member

I will agree that there are benefits of using System.Text.Json for serialisation and deserialisation over Newtonsoft.Json.

@abnegate I would love to double check if there are any specific reasons why we prefer Newtonsoft.Json (aside from simplicity)?

@abnegate
Copy link
Member

I will agree that there are benefits of using System.Text.Json for serialisation and deserialisation over Newtonsoft.Json.

@abnegate I would love to double check if there are any specific reasons why we prefer Newtonsoft.Json (aside from simplicity)?

I agree with @adityaoberai on all points. No reason not to use System.Text.Json instead at this point

@adityaoberai
Copy link
Member

@initinll while we explore options to improve performance and developer experience, if you would like to create and maintain your own version of the SDK, please feel free to do so :D

We do appreciate community-maintained libraries and SDKs and if you would like to develop, that's absolutely alright too!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants