This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Client Libraries

A collection of client libraries to communicate with REST services.

In this documentation only some client libraries are shown. Evaluate for yourself if and what kind of library you want or need.

Which client library is the best?

This question cannot be answered in general terms. But here are a few notes:

  • If you don’t want any dependency or external library: use only the HttpClient.
  • If you take a very simple json query in a demo or in a tool, then you can use any library shown here.
  • If you want a very powerful library that is very efficient and suitable for both simple and complex scenarios, use Refit.

My personal recommendation in general is: Refit

Make sure that you use a library that is actively being developed. The trick at the end is to integrate the library correctly into your code base.

1 - HttpClient

Creating an HTTP REST client without external dependencies

Using a specific REST library like Refit is the recommended way. Even though I have personally experienced that Refit would not have been allowed for any of my customers, this may well be the case.

.NET provides everything to create a JSON or XML-based REST client without dependencies. The disadvantage here is, of course, that you have to program out everything yourself - even the special cases.

Therefore, you must first create a wrapper that handles the HTTP communication. For simple Get or Post this is relatively simple, but can also become very complex.

Sample

public abstract class MyJsonHttpClient
{
    protected HttpClient HttpClient { get; }
    private string BaseAddress { get; }

    public MyJsonHttpClient(HttpClient httpClient, string baseAddress)
    {
        HttpClient = httpClient;
        BaseAddress = baseAddress;
    }

    protected async Task<T?> InternalGetAsync<T>(string uri)
    {
        using HttpResponseMessage response 
            = await HttpClient.GetAsync(BaseAddress + uri).ConfigureAwait(false);

        return await DeserializeResponse<T>(response).ConfigureAwait(false);
    }

    protected async Task<TResponse?> InternalPostAsync<TBody, TResponse>(string uri, TBody body)
    {
        string jsonContent = JsonSerializer.Serialize(body, s_jsonSerializerOptions);
        using StringContent httpContent = new(jsonContent, Encoding.UTF8, "application/json");

        using HttpResponseMessage response 
            = await HttpClient.PostAsync(BaseAddress + uri, httpContent).ConfigureAwait(false);

        return await DeserializeResponse<TResponse>(response).ConfigureAwait(false);
    }

    protected JsonSerializerOptions s_jsonSerializerOptions 
      = new() { PropertyNameCaseInsensitive = true };
    protected async Task<T?> DeserializeResponse<T>(HttpResponseMessage responseMessage)
    {
        Stream bodyStream
            = await responseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false);
        return await JsonSerializer
                          .DeserializeAsync<T>(bodyStream, s_jsonSerializerOptions)
                          .ConfigureAwait(false);
    }
}

This abstract base class can now be used to build your own API. The abstraction keeps the actual API implementation lean.

public class MyTaskAPI : MyJsonHttpClient
{
    public MyTaskAPI(HttpClient httpClient, string baseAddress)
        : base(httpClient, baseAddress)
    { }

    public Task<TaskApiModel?> GetTask(int id)
        => InternalGetAsync<TaskApiModel>($"/tasks/{id}");

    public Task<TaskApiModel[]?> GetAllTasks()
        => InternalGetAsync<TaskApiModel[]>("/tasks");

    public Task<TaskApiModel?> AddTask(TaskApiCreateModel newTask)
        => InternalPostAsync<TaskApiCreateModel, TaskApiModel>("/tasks", newTask);
}

The implementation can then - as with the other libraries - simply be used to query, create or manipulate the corresponding resources.

HttpClient httpClient = new HttpClient();   // single instance or use HttpClientFactory
MyTaskAPI myApi = new MyTaskAPI(httpClient, "https://my-rest-api.com");

// Get single task
TaskApiModel? task = await myApi.GetTask(123);

// Get all tasks
TaskApiModel[]? tasks = await myApi.GetAllTasks();

// Add new task
TaskApiCreateModel newTask = new TaskApiCreateModel { Title = "Buy flowers" };
TaskApiModel? addedTask = await myApi.AddTask(newTask);
Pros

  • No dependency
  • Full implementation control

Cons

  • Very time-consuming, especially for optimizations
  • Very high test effort (unit tests + integration tests)
  • High risk of error
  • High maintenance effort

Full Sample

See the full sample on GitHub: https://github.com/BenjaminAbt/dotnet.rest-samples

2 - Refit

About Refit: the automatic type-safe REST library for .NET Core, Xamarin and .NET.

GitHub Repo stars is one of the most powerful and performant REST client libraries in the .NET ecosystem.

Unlike other widely used libraries, Refit has been using a concept of automatic source code generation of the REST client at development time (build time) for years. This reduces runtime overhead, increases performance and improves reliability.
For this purpose, Refit used to use so-called stubs, but now Refit uses source code generators).

The documentation of Refit is excellent.

Info Link
License GitHub
Downloads Nuget
Latest Version GitHub release (latest by date)
Issues GitHub issues
Contributors GitHub contributors

Samples

Refit uses interfaces to describe a REST API. It uses the information in the interface at build time to generate the REST client using the source code generators.

public interface IMyTaskAPI
{
    [Get("/tasks")]
    Task<List<TaskApiModel>> GetAllTasks();

    [Get("/tasks/{id}")]
    Task<TaskApiModel?> GetTask(int id);

    [Post("/tasks")]
    Task<TaskApiModel> AddTask(TaskApiCreateModel taskModel);

    [Patch("/tasks/{id}")]
    Task<TaskApiModel?> UpdateTask(int id, TaskApiUpdateModel taskModel);

    [Delete("/tasks/{id}")]
    Task<TaskApiModel?> DeleteTask(int id);

    [Put("/tasks/{id}/status/complete")]
    Task<TaskApiModel?> MarkTaskAsCompleted(int id);

    [Put("/tasks/{id}/status/uncomplete")]
    Task<TaskApiModel?> MarkTaskAsUncompleted(int id);

    // Remarks: you can/should add 'CancellationToken cancellationToken = default' to all parameters to support cancellation
}

The generated client then contains the instance methods to communicate with the API. All REST communication, serialization and deserialization is abstracted by Refit.

IMyTaskAPI taskApi = RestService.For<IMyTaskAPI>("my-rest-api.com");

// Get single task
TaskApiModel? task = await taskApi.GetTask(123);

// Get all tasks
List<TaskApiModel> tasks = await taskApi.GetAllTasks();

// add new task
TaskApiCreateModel newTask = new TaskApiCreateModel { Title = "Buy flowers" };
TaskApiModel? addedTask = await taskApi.AddTask(newTask);

Remarks

Refit has a built-in dependency injection support, required package Refit.HttpClientFactory:

services
    .AddRefitClient<IMyTaskAPI>()
    .ConfigureHttpClient(c => c.BaseAddress = new Uri("my-rest-api.com"));
Pros

  • Extremely simple yet powerful REST Client.
  • Extremely efficient through source code generators.
  • Enormously expandable and thus suitable for both very simple and enormously complex scenarios.

Cons

  • Source code generators are considered to be complex (if you have to debug deeper into Refit).
  • An interface is always needed, thus not much but still more than one line of code is necessary.

Full Sample

See the full sample on GitHub: https://github.com/BenjaminAbt/dotnet.rest-samples

3 - Flurl

About Flurl: a modern, fluent, asynchronous, testable, portable, buzzword-laden URL builder and HTTP client library for .NET

Flurl Repo stars is similar to RestSharp in that it is a very simple REST library, but is based entirely on a Fluent API (like ServiceStack Http Utils).

Flurl provides an initital extension method on any string that should represent a url. Then, the request or query can be created accordingly using a Fluent API with extension methods.

Info Link
License GitHub
Downloads Nuget
Latest Version GitHub release (latest by date)
Issues GitHub issues
Contributors GitHub contributors

Sample

string apiUrl = "my-rest-api.com";

// Get single task
TaskApiModel? task = await $"{apiUrl}/tasks/123".GetJsonAsync<TaskApiModel?>();

// Get all tasks
List<TaskApiModel> tasks = await $"{apiUrl}/tasks".GetJsonAsync<List<TaskApiModel>>();

// Add new task
TaskApiCreateModel newTask = new TaskApiCreateModel { Title = "Buy flowers" };
TaskApiModel addedTask = await $"{apiUrl}/tasks"
    .PostJsonAsync(newTask)
    .ReceiveJson<TaskApiModel>();
Pros

  • Easy to understand.
  • Very intuitive programming style.
  • API call with one single line of code.

Cons

  • Relatively many allocations necessary and therefore more inefficient in comparison.
  • More implementation effort, since a wrapper is always necessary in real applications.
  • If it goes beyond simple scenarios, you have to do a lot of programming yourself.
  • Offering extension methods on any string is not necessarily the best idea: often not wanted and quite considered anti pattern and falls under developer noise.

Full Sample

See the full sample on GitHub: https://github.com/BenjaminAbt/dotnet.rest-samples

4 - RestClient

About RestClient: simple REST and HTTP API Client for .NET

RestSharp Repo stars is one of the most powerful and performant REST client libraries in the .NET ecosystem.

Unlike other widely used libraries, Refit has been using a concept of automatic source code generation of the REST client at development time (build time) for years. This reduces runtime overhead, increases performance and improves reliability.
For this purpose, Refit used to use so-called stubs, but now Refit uses source code generators).

The documentation of Refit is excellent.

Info Link
License GitHub
Downloads Nuget
Latest Version GitHub release (latest by date)
Issues GitHub issues
Contributors GitHub contributors

RestSharp is a very simple and very basic library for REST communication with .NET. The library abstracts based on very simple HTTP calls, which is very similar to native HttpClient programming.
No code is generated automatically, but you work manually with an instance that is enriched with parameters. The call must be done manually, the deserialization is supported in a simple way - again similar to HttpClient.

Client sample

// Create options
RestClientOptions options = new RestClientOptions("my-rest-api.com")
{
    ThrowOnAnyError = true,
    Timeout = 30
};

// Create client
RestClient client = new RestClient(options);

// Get single task
{
    RestRequest request = new RestRequest("tasks/1234");
    TaskApiModel? task = await client.GetAsync<TaskApiModel>(request, cancellationToken);
}

// Get all tasks
{
    RestRequest request = new RestRequest("tasks");
    TaskApiModel[]? tasks = await client.GetAsync<TaskApiModel[]>(request, cancellationToken);
}

// Add new task
{
    TaskApiCreateModel newTask = new TaskApiCreateModel { Title = "Buy flowers" };
    RestRequest request = new RestRequest("tasks").AddJsonBody(newTask);
    TaskApiModel? createdTask = await client.GetAsync<TaskApiModel?>(request, cancellationToken);
}

Wrapper sample

Since RestSharp is really very simple, it is recommended to abstract the entire RestClient. For this purpose a wrapper pattern is useful.

/*** Wrapper Sample ***/

public class MyTaskApiClient
{
    private readonly RestClient _client;

    public MyTaskApiClient(string baseUrl)
    {
        _client = new RestClient(baseUrl);
    }

    public Task<TaskApiModel?> GetTask(int id, CancellationToken cancellationToken = default)
        => _client.GetAsync<TaskApiModel>(new RestRequest($"task/{id}"), cancellationToken);

    public Task<List<TaskApiModel>?> GetAllTasks(CancellationToken cancellationToken = default) =>
        _client.GetAsync<List<TaskApiModel>>(new RestRequest("tasks"), cancellationToken);

    public Task<TaskApiModel?> AddTask(string title, CancellationToken cancellationToken = default)
    {
        TaskApiCreateModel newTask = new TaskApiCreateModel { Title = title };
        RestRequest request = new RestRequest("tasks").AddJsonBody(newTask);
        return _client.GetAsync<TaskApiModel>(request, cancellationToken);
    }
}

Comparison

Pros

  • Very simple client
  • Good serialization.
  • Good for slim szenarios.

Cons

  • Relatively many allocations necessary and therefore more inefficient in comparison.
  • More implementation effort, since a wrapper is always necessary in real applications.
  • If it goes beyond simple scenarios, you have to do a lot of programming yourself.

Full Sample

See the full sample on GitHub: https://github.com/BenjaminAbt/dotnet.rest-samples

5 - ServiceStack

About ServiceStack: Http Client and Http Utils

ServiceStack Repo stars is similar to Flurl in that it is a very simple REST library and also offers on a Fluent API. ServiceStack.HttpClient is part of a huge ServiceStack suite.

ServiceStack offers several implementations: Http Utils (Fluent API based on a string (like Flurl)), or also specific clients, like for Json with the JsonServiceClient (Http Client).

Info Link
License proprietary
Downloads Nuget
Latest Version GitHub release (latest by date)
Issues GitHub issues
Contributors GitHub contributors

Http Client

The Http Client is ServiceStack’s recommended package for HTTP clients, especially for its own products. However, you can use the client for any Json-based REST API.

IServiceClient client = new JsonHttpClient("my-rest-api.com");

// Get single task
TaskApiModel? task = await client.GetAsync<TaskApiModel?>("tasks/123");

// Get all tasks
List<TaskApiModel> tasks = await client.GetAsync<List<TaskApiModel>>("tasks");

// Add new task
TaskApiCreateModel newTask = new TaskApiCreateModel { Title = "Buy flowers" };
TaskApiModel addedTask = await client.PostAsync<TaskApiModel>("tasks", newTask);

The big advantage is that the library is attached to a powerful product and additional built-in features like caching and debug print are provided.

Http Utils

The Http Utils are aimed by ServiceStack primarily at APIs that do not provide a ready-made SDK and behaves similarly to Flurl.

// Get single task
string taskResponse = await "my-rest-api.com/task/123".GetJsonFromUrlAsync();
TaskApiModel? task = taskResponse.FromJson<TaskApiModel?>();

// Get all tasks
string tasksResponse = await "my-rest-api.com/tasks".GetJsonFromUrlAsync();
List<TaskApiModel> tasks = tasksResponse.FromJson<List<TaskApiModel>>();

// Add new task
TaskApiCreateModel newTask = new TaskApiCreateModel { Title = "Buy flowers" };
string addedTaskResponse = await "my-rest-api.com/tasks".PostJsonToUrlAsync(newTask);
TaskApiModel addedTask = addedTaskResponse.FromJson<TaskApiModel>();

The biggest disadvantage of utils is that any serialization must be programmed yourself and you have little to no type safety.

Comparison

Full Sample

See the full sample on GitHub: https://github.com/BenjaminAbt/dotnet.rest-samples