Faactory.RestClient
0.3.0-preview-1
See the version list below for details.
dotnet add package Faactory.RestClient --version 0.3.0-preview-1
NuGet\Install-Package Faactory.RestClient -Version 0.3.0-preview-1
<PackageReference Include="Faactory.RestClient" Version="0.3.0-preview-1" />
paket add Faactory.RestClient --version 0.3.0-preview-1
#r "nuget: Faactory.RestClient, 0.3.0-preview-1"
// Install Faactory.RestClient as a Cake Addin
#addin nuget:?package=Faactory.RestClient&version=0.3.0-preview-1&prerelease
// Install Faactory.RestClient as a Cake Tool
#tool nuget:?package=Faactory.RestClient&version=0.3.0-preview-1&prerelease
REST Client for .NET
This projects contains the implementation for a REST Client for .NET. It's built on top of the original HttpClient
and fully supports IHttpClientFactory
for dependency injection.
Getting started
Install the package.
$ dotnet add package Faactory.RestClient
To create a client instance using dependency injection
IServiceCollection services = new ServiceCollection()
...
.AddRestClient( "jsonplaceholder", "https://jsonplaceholder.typicode.com" )
...
This will give you access to an IRestClientFactory
interface. Then, wherever you need a client
public class MyClass
{
private readonly IRestClient client;
public MyClass( IRestClientFactory clientFactory )
{
client = clientFactory.CreateClient( "jsonplaceholder" );
}
...
}
If creating the client manually, an HttpClient
instance needs to be passed through
var httpClient = ...
var restClient = new RestClient( httpClient, "https://jsonplaceholder.typicode.com" );
Using
All request operations respond with a RestResponse
or RestObjectResponse
, containing the status code of the operation and the content, if any.
var response = await restClient.GetAsync( "todos/1" );
if ( response.IsOk() )
{
// do something with the content only if response is a 200 OK
}
Configuring and Scoping
It is possible to customize a request's configuration, such as headers or query parameters. We do that by invoking Configure
and a configuration method, which returns a new instance.
IRestClient configured = restClient.Configure( options =>
{
options.QueryParameters.Add( "address.city", "Bartholomebury" );
} );
var response = configured.GetAsync( "users" );
// or directly with a fluent syntax
var response = await restClient.Configure( options =>
{
options.QueryParameters.Add( "address.city", "Bartholomebury" );
})
.GetAsync( "users" );
It is also possible to scope the request with the path to the resource while configuring a request. To do that, we invoke the Configure
with the path and the configuration method. This will return an IRestRequest
instead of an IRestClient
.
IRestRequest scoped = restClient.Configure( "users", options =>
{
options.QueryParameters.Add( "address.city", "Bartholomebury" );
} );
var response = scoped.GetAsync();
// or directly with a fluent syntax
var response = await restClient.Configure( "users", options =>
{
options.QueryParameters.Add( "address.city", "Bartholomebury" );
})
.GetAsync();
You will notice that
IRestRequest
operation methods don't take a path, since it was already defined with the configuration method.
It's worth noting that both IRestClient
and scoped IRestRequest
instances are reusable and multiple operations can be performed with the same instance. Here's an example on reusing a non-scoped request.
var request = restClient.Configure( options =>
{
options.Headers.Add( "X-Custom-Header", "custom header value" );
} );
var ids = new int[] { 1, 2, 3 };
var getTasks = ids.Select( id => request.GetAsync( $"users/{id}" ) )
.ToArray();
var responses = await Task.WhenAll( getTasks );
Working with JSON
The client includes extensions to serialize and deserialize JSON content. This can be done by manually deserializing a RestResponse
instance
var response = await restClient.GetAsync( "todos/1" );
var todo = response.Deserialize<Todo>();
Or requesting directly with the JSON extension, which returns a RestObjectResponse
instead
var response = await restClient.GetJsonAsync<Todo>( "todos/1" );
var todo = response.Content;
In both scenarios you will have access to the response status code and headers.
When doing a GET
request with a JSON extension, if you're not interested in the response status or headers, you can bypass it and get the content only. If the response status code is not a 200 (OK), the content returned will be default<T>
.
var todo = await restClient.GetJsonAsync<Todo>( "todos/1" ).GetContentAsync();
Polymorphic JSON Serialization
By default, the client uses Microsoft's JSON serializer, therefore, there is limited support for polymorphic serialization and deserialization is not supported at all. You can find more information in this article where you will also find a few workarounds, including writing a custom converter.
If you rather use Newtonsoft's Json.NET (or any other), you can easilly write a custom serializer. Here's an example for Newtonsoft's
public class NewtonsoftJsonSerializer : ISerializer
{
public byte[] SerializeObject<T>( T value )
{
var json = JsonConvert.SerializeObject( value );
return Encoding.UTF8.GetBytes( json );
}
public T DeserializeObject<T>( byte[] content )
{
var json = Encoding.UTF8.GetString( content );
return JsonConvert.DeserializeObject<T>( json );
}
}
If you are using dependency injection, you can add the serializer by injecting it into the container services.
IServiceCollection services = new ServiceCollection()
...
services.AddRestClient( "jsonplaceholder", "https://jsonplaceholder.typicode.com" )
// add our custom serializer
services.AddSingleton<IJsonSerializer, NewtonsoftJsonSerializer>();
If you are not using dependency injection, just pass it into the constructor.
var httpClient = ...
var restClient = new RestClient(
httpClient,
"https://jsonplaceholder.typicode.com",
new NewtonsoftJsonSerializer() );
You can also pass a custom serializer if deserializing from a RestResponse
instance
var customSerializer = new NewtonsoftJsonSerializer();
var response = await restClient.GetAsync( "todos/1" );
var todo = response.Deserialize<Todo>( customSerializer );
Authorization header
Since version 0.1.4
you can use extensions to configure the Authorization
header. Currently, the supported schemes are
- Basic authentication
- Bearer token
This can be applied to the entire client, when configuring the underlying HttpClient
instance with dependency injection
IServiceCollection services = new ServiceCollection()
...
.AddRestClient( "jsonplaceholder", "https://jsonplaceholder.typicode.com", httpClient =>
{
httpClient.AddBasicAuthentication( "username", "password" );
} )
...
when manually creating the client instance, by accessing the underlying client extensions
var httpClient = ...
httpClient.AddBasicAuthentication( "username", "password" );
var restClient = new RestClient( httpClient, "https://jsonplaceholder.typicode.com" );
// accessing the underlying client instance works the same
// restClient.HttpClient.AddBasicAuthentication( "username", "password" );
or when customizing/scoping a request
var response = await restClient.Configure( "users", options =>
{
options.AddBasicAuthentication( "username", "password" );
})
.GetAsync();
Note: These extensions require adding the namespace
Faactory.RestClient
EXPERIMENTAL: REST-Schema Extensions
If you are working with an API that is compatible with REST-Schema, there are a few extensions that you can use. These are experimental features, so they might change in the future, disappear or not function properly.
We can send a map schema spec through the headers by customizing a request with the available extensions.
var response = await restClient.Configure( "users", options =>
{
options.SchemaMap( new {
spec = new {
_ = new string[] { "id", "name", "email", "address" },
address = new string[] { "street", "city", "zipcode" }
}
} );
})
.GetAsync();
Similarly we can send an include schema spec.
var response = await restClient.Configure( "users", options =>
{
options.SchemaInclude( new {
spec = new {
_ = new string[] { "address" }
}
} );
})
.GetAsync();
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net6.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 6.0.0)
- Microsoft.Extensions.Http (>= 6.0.0)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Faactory.RestClient:
Package | Downloads |
---|---|
Fonix.Extensions.ApiClient
Fonix APIs RestClient Extensions |
|
Faactory.DbContext.RestSql
DbContext RestSql provider |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
0.4.0-preview-1 | 107 | 7/26/2023 |
0.3.2 | 243 | 7/10/2023 |
0.3.1 | 155 | 5/4/2023 |
0.3.0 | 602 | 8/9/2022 |
0.3.0-preview-6 | 116 | 8/9/2022 |
0.3.0-preview-5 | 147 | 8/9/2022 |
0.3.0-preview-4 | 112 | 8/8/2022 |
0.3.0-preview-2 | 114 | 8/5/2022 |
0.3.0-preview-1 | 115 | 8/5/2022 |
0.2.1 | 653 | 3/28/2022 |
0.1.8 | 605 | 11/3/2021 |
0.1.7 | 270 | 10/7/2021 |
0.1.6 | 303 | 8/12/2021 |
0.1.5 | 271 | 8/12/2021 |
0.1.4 | 320 | 8/3/2021 |
0.1.3 | 352 | 7/29/2021 |
0.1.2 | 374 | 7/27/2021 |
0.1.1 | 277 | 7/21/2021 |
0.1.0 | 285 | 7/21/2021 |