RastaClient 1.1.1
dotnet add package RastaClient --version 1.1.1
NuGet\Install-Package RastaClient -Version 1.1.1
<PackageReference Include="RastaClient" Version="1.1.1" />
<PackageVersion Include="RastaClient" Version="1.1.1" />
<PackageReference Include="RastaClient" />
paket add RastaClient --version 1.1.1
#r "nuget: RastaClient, 1.1.1"
#:package RastaClient@1.1.1
#addin nuget:?package=RastaClient&version=1.1.1
#tool nuget:?package=RastaClient&version=1.1.1
RastaClient
A robust HTTP client library for .NET applications that provides a simplified interface for making REST API calls with built-in retry policies, comprehensive logging, and seamless dependency injection integration.
Features
- Automatic Retry Logic: Configurable retry policies with exponential backoff
- Comprehensive Logging: Detailed request/response logging with configurable levels
- Dependency Injection Ready: Seamless integration with .NET DI container
- Multiple Named Clients: Support for multiple API endpoints through factory pattern
- Generic Type Support: Strongly-typed request and response models
- HttpClient Factory: Leverages IHttpClientFactory for optimal connection management
- Robust Error Handling: Graceful error handling with fallback mechanisms
Installation
dotnet add package RastaClient
Quick Start
1. Register RastaClient
using RastaClient.Infrastructure.Extensions;
// Single client
services.AddRastaClient(options =>
{
options.BaseUrl = "https://api.example.com";
});
// Multiple named clients
services.AddRastaClient("UserApiClient", options =>
{
options.BaseUrl = "https://user-api.example.com";
});
services.AddRastaClient("OrderApiClient", options =>
{
options.BaseUrl = "https://order-api.example.com";
});
2. Use in Your Services
public class UserService
{
private readonly IRestClient _restClient;
public UserService(IRestClientFactory restClientFactory)
{
_restClient = restClientFactory.CreateClient("UserApiClient");
}
public async Task<User?> GetUserAsync(int userId)
{
return await _restClient.GetAsync<User>($"/users/{userId}");
}
public async Task<User?> CreateUserAsync(CreateUserRequest request)
{
return await _restClient.PostAsync<CreateUserRequest, User>("/users", request);
}
}
Configuration
Basic Configuration
services.AddRastaClient("MyApiClient", options =>
{
options.BaseUrl = "https://api.example.com";
});
Custom Retry Policy
services.AddRastaClient("MyApiClient", options =>
{
options.BaseUrl = "https://api.example.com";
// Exponential backoff with 5 retries
options.RetryPolicyFactory = () => Policy
.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.WaitAndRetryAsync(
retryCount: 5,
sleepDurationProvider: retry => TimeSpan.FromSeconds(Math.Pow(2, retry)),
onRetry: (outcome, timespan, retryCount, context) =>
{
Console.WriteLine($"Retry {retryCount} after {timespan}s");
});
});
// No retry policy
services.AddRastaClient("NoRetryClient", options =>
{
options.BaseUrl = "https://api.example.com";
options.RetryPolicyFactory = () => Policy
.HandleResult<HttpResponseMessage>(_ => false)
.RetryAsync(0);
});
API Reference
IRestClient Methods
| Method | Description |
|---|---|
GetAsync<TResponse> |
Send GET request and deserialize response |
PostAsync<TRequest, TResponse> |
Send POST request with body and deserialize response |
PutAsync<TRequest, TResponse> |
Send PUT request with body and deserialize response |
PatchAsync<TRequest, TResponse> |
Send PATCH request with body and deserialize response |
DeleteAsync |
Send DELETE request and return success status |
Method Signatures
// GET Request
Task<TResponse?> GetAsync<TResponse>(
string url,
Dictionary<string, string>? headers = null,
CancellationToken cancellationToken = default);
// POST Request
Task<TResponse?> PostAsync<TRequest, TResponse>(
string url,
TRequest request,
Dictionary<string, string>? headers = null,
CancellationToken cancellationToken = default);
// PUT Request
Task<TResponse?> PutAsync<TRequest, TResponse>(
string url,
TRequest request,
Dictionary<string, string>? headers = null,
CancellationToken cancellationToken = default);
// PATCH Request
Task<TResponse?> PatchAsync<TRequest, TResponse>(
string url,
TRequest request,
Dictionary<string, string>? headers = null,
CancellationToken cancellationToken = default);
// DELETE Request
Task<bool> DeleteAsync(
string url,
Dictionary<string, string>? headers = null,
CancellationToken cancellationToken = default);
Usage Examples
CRUD Operations
public class ProductService
{
private readonly IRestClient _restClient;
public ProductService(IRestClientFactory restClientFactory)
{
_restClient = restClientFactory.CreateClient("ProductApiClient");
}
// GET: Retrieve products
public async Task<Product?> GetProductAsync(int productId)
{
return await _restClient.GetAsync<Product>($"/products/{productId}");
}
public async Task<List<Product>?> GetProductsAsync()
{
return await _restClient.GetAsync<List<Product>>("/products");
}
// POST: Create product
public async Task<Product?> CreateProductAsync(CreateProductRequest request)
{
return await _restClient.PostAsync<CreateProductRequest, Product>("/products", request);
}
// PUT: Update product
public async Task<Product?> UpdateProductAsync(int productId, UpdateProductRequest request)
{
return await _restClient.PutAsync<UpdateProductRequest, Product>($"/products/{productId}", request);
}
// PATCH: Partially update product
public async Task<Product?> PatchProductAsync(int productId, PatchProductRequest request)
{
return await _restClient.PatchAsync<PatchProductRequest, Product>($"/products/{productId}", request);
}
// DELETE: Delete product
public async Task<bool> DeleteProductAsync(int productId)
{
return await _restClient.DeleteAsync($"/products/{productId}");
}
}
Using Custom Headers
public async Task<User?> GetUserWithAuthAsync(int userId, string authToken)
{
var headers = new Dictionary<string, string>
{
["Authorization"] = $"Bearer {authToken}",
["X-Custom-Header"] = "CustomValue"
};
return await _restClient.GetAsync<User>($"/users/{userId}", headers);
}
Error Handling
public async Task<Product?> GetProductSafelyAsync(int productId)
{
try
{
var product = await _restClient.GetAsync<Product>($"/products/{productId}");
if (product == null)
{
_logger.LogWarning("Product with ID {ProductId} not found", productId);
return null;
}
return product;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving product with ID {ProductId}", productId);
return null;
}
}
Retry Policy
RastaClient includes a default retry policy:
- Retry Attempts: 3 attempts
- Retry Delay: 2 seconds between retries
- Retry Conditions: Non-success HTTP status codes
The retry policy can be customized per client as shown in the Configuration section.
Logging
RastaClient provides comprehensive logging at different levels:
Log Levels
- Information: Request/response details, HTTP methods, URLs, status codes
- Debug: Request/response headers
- Warning: Retry attempts, non-success status codes
- Error: Exceptions and error details
Configuration
{
"Logging": {
"LogLevel": {
"RastaClient.Infrastructure.Services.RestClient": "Information"
}
}
}
Best Practices
1. Use Factory Pattern for Multiple Clients
// Registration
services.AddRastaClient("UserApiClient", options =>
options.BaseUrl = "https://user-service.example.com");
services.AddRastaClient("OrderApiClient", options =>
options.BaseUrl = "https://order-service.example.com");
// Usage
public class CommerceService
{
private readonly IRestClient _userClient;
private readonly IRestClient _orderClient;
public CommerceService(IRestClientFactory factory)
{
_userClient = factory.CreateClient("UserApiClient");
_orderClient = factory.CreateClient("OrderApiClient");
}
}
2. Handle Null Responses
Always check for null responses as they indicate non-success status codes:
public async Task<IActionResult> GetUser(int id)
{
var result = await _restClient.GetAsync<User>($"/users/{id}");
if (result == null)
{
return NotFound();
}
return Ok(result);
}
3. Use Cancellation Tokens
public async Task<List<Product>?> GetProductsAsync(CancellationToken cancellationToken)
{
return await _restClient.GetAsync<List<Product>>("/products", cancellationToken: cancellationToken);
}
4. Use Strongly-Typed Models
public class CreateUserRequest
{
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
}
public class User
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; }
}
Troubleshooting
Common Issues
- Base URL Configuration: Ensure the base URL is properly configured and accessible
- Client Name Mismatch: Verify the client name used in
CreateClient()matches the registered name - Serialization Issues: Check that your models have proper JSON serialization attributes
- Network Timeouts: Configure appropriate timeouts for your HttpClient
- Authentication: Ensure proper authentication headers are included
Debug Tips
- Enable detailed logging to see request/response details
- Use network monitoring tools to inspect HTTP traffic
- Verify API endpoints are accessible and return expected responses
- Ensure models match the API response structure
- Check that client names are consistent between registration and usage
Dependencies
- Microsoft.Extensions.DependencyInjection
- Microsoft.Extensions.Logging
- Microsoft.Extensions.Http
- Microsoft.Extensions.Options
- Polly (for retry policies)
- System.Net.Http.Json
License
This project is licensed under the MIT License.
Contributing
Contributions are welcome! Please submit a Pull Request.
Support
For issues or questions, please open an issue on the GitHub repository.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. 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. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.Extensions.Http (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.3)
- Polly (>= 8.6.1)
- System.Net.Http.Json (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.