RastaClient 1.1.1

dotnet add package RastaClient --version 1.1.1
                    
NuGet\Install-Package RastaClient -Version 1.1.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RastaClient" Version="1.1.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RastaClient" Version="1.1.1" />
                    
Directory.Packages.props
<PackageReference Include="RastaClient" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RastaClient --version 1.1.1
                    
#r "nuget: RastaClient, 1.1.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RastaClient@1.1.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RastaClient&version=1.1.1
                    
Install as a Cake Addin
#tool nuget:?package=RastaClient&version=1.1.1
                    
Install as a Cake Tool

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

  1. Base URL Configuration: Ensure the base URL is properly configured and accessible
  2. Client Name Mismatch: Verify the client name used in CreateClient() matches the registered name
  3. Serialization Issues: Check that your models have proper JSON serialization attributes
  4. Network Timeouts: Configure appropriate timeouts for your HttpClient
  5. Authentication: Ensure proper authentication headers are included

Debug Tips

  1. Enable detailed logging to see request/response details
  2. Use network monitoring tools to inspect HTTP traffic
  3. Verify API endpoints are accessible and return expected responses
  4. Ensure models match the API response structure
  5. 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.1 199 7/6/2025
1.1.0 133 7/5/2025
1.0.0 136 7/5/2025