RestMiddleware 1.0.0

dotnet add package RestMiddleware --version 1.0.0
                    
NuGet\Install-Package RestMiddleware -Version 1.0.0
                    
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="RestMiddleware" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RestMiddleware" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="RestMiddleware" />
                    
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 RestMiddleware --version 1.0.0
                    
#r "nuget: RestMiddleware, 1.0.0"
                    
#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 RestMiddleware@1.0.0
                    
#: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=RestMiddleware&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=RestMiddleware&version=1.0.0
                    
Install as a Cake Tool

RestMiddleware

A lightweight, generic HTTP client wrapper for building .NET repository layers.

RestMiddleware is a simple but powerful helper library that eliminates repetitive HttpClient boilerplate. It provides a RestClient helper class that uses IHttpClientFactory to perform consistent, strongly-typed HTTP network calls with minimal code.

Compatible with: .NET Standard 2.0 (.NET Framework 4.6.1+, .NET Core 2.0+, .NET 5/6/7/8/9+)


โœจ Features

  • ๐Ÿš€ Async Generic Helpers: Strongly typed responses ((data, response))
  • ๐Ÿท๏ธ Named Instances: Use multiple API configurations in one project
  • ๐Ÿงญ Nested Layouts: Navigate deep JSON responses using > (e.g., data>payload>items)
  • ๐ŸฅŠ Simple Response: Direct body parsing for standard REST APIs
  • ๐Ÿ›ก๏ธ Auto-Refresh: Automatic JWT token refresh handling
  • ๐Ÿงฑ Efficient: Uses IHttpClientFactory for connection pooling
  • ๐ŸŒ Global & Per-Request Headers: Easy custom header management

๐Ÿ“š Installation

Install the NuGet package:

dotnet add package RestMiddleware

๐Ÿš€ Initialization

Basic Setup (.NET Core / .NET 5+)

In Program.cs or Startup.cs:

using RestMiddleware.Extensions;

services.AddRestMiddleware(options => 
{
    options.MethodToGetBaseUrl = () => "https://api.myapp.com";
    options.MethodToGetToken = () => GetUserToken(); // Delegate to get token
    options.FetchRefreshTokenIfUnauthorised = true;
});

Named Instances (Multiple APIs)

If you need to connect to multiple different APIs:

// Default Client
services.AddRestMiddleware(options => {
    options.MethodToGetBaseUrl = () => "https://api.one.com";
});

// Second API Client
services.AddRestMiddleware("InventoryService", options => {
    options.MethodToGetBaseUrl = () => "https://inventory.api.com";
    options.UseSimpleResponse(); // Parse direct body
});

Usage with Named Instances

public class MyService 
{
    private readonly RestClient _inventoryClient;

    public MyService(IRestClientFactory factory)
    {
        _inventoryClient = factory.CreateClient("InventoryService");
    }
}

๐Ÿงฉ Response Parsing Strategies

There are two main ways to tell the library how to extract data and errors from your API responses:

Option A: Schema-Based (Standard Envelopes)

Best when your API wraps results in a standard structure (e.g., { "status": "ok", "result": { ... }, "errors": [] }).

You provide a sample JSON file and the keys to navigate.

  • Support for nested keys: Use > to go deep (e.g., data>items).
  • Automatic Deduction: The library analyzes the sample file to learn how to parse error lists.
options.UseResponseLayout(
    sampleJsonPath: "api_sample.json", 
    dataKey: "result>payload", 
    errorKey: "errors"
);
Option B: Function-Based (Custom Logic)

Best for maximum flexibility or when you want to handle parsing manually without a schema file.

options.ParseSuccess = (json, type) => {
    // Custom logic to extract and deserialize data (e.g. using JObject)
    return myCustomDeserializer(json, type);
};

options.ParseErrors = (json) => {
    // Custom logic to extract error messages as string[]
    return new string[] { "Something failed" };
};
Quick Start: Simple Response

If your API returns the object/array directly (no wrapper), use:

options.UseSimpleResponse();

๐Ÿงช Configuration Options

HttpRequestOptions

Option Type Description
MethodToGetBaseUrl Func<string> Returns the Base URL for the client (sync).
MethodToGetBaseUrlAsync Func<Task<string>> Preferred. Async version to retrieve Base URL.
MethodToGetToken Func<string> Returns the Bearer token for authorization (sync).
MethodToGetTokenAsync Func<Task<string>> Preferred. Async version to retrieve Bearer token.
FetchRefreshTokenIfUnauthorised bool If true, attempts to refresh token on 401.
MethodToGetRefreshTokenEndpoint Func<string> Endpoint to call for refreshing tokens.
MethodToGetRefreshToken Func<string> Optional. Returns the refresh token (if distinctive).
AccessTokenParameterName string JSON key for access token (default: "jwt_token").
RefreshTokenParameterName string JSON key for refresh token (default: "refresh_token").
CreateCustomRefreshRequestBody Func<object> Advanced. Return any object to fully customize the refresh body.
MethodToSetTokenLocally Action<object> Callback to save the new token (sync).
MethodToSetTokenLocallyAsync Func<object, Task> Preferred. Async callback to save new token.
ParseSuccess Func<string, Type, object> The function responsible for parsing success JSON.
ParseErrors Func<string, string[]> The function responsible for parsing error JSON.

๐Ÿ›  Usage

Standard Calls

The library returns a tuple: (T data, HttpResponseDto response).

// POST request with body and CancellationToken
var (user, response) = await _client.PostAndGetObject<UserDto>(new HttpRequestDto()
{
    endpoint = "/users",
    data = new { name = "John" },
    CancellationToken = myCancellationToken
});

Async Token Retrieval Example

options.MethodToGetTokenAsync = async () => {
    var token = await _secureStorage.GetAsync("token");
    return token;
};

๐Ÿ” Automated Auth Workflow

One of the most powerful features of RestMiddleware is the automated token refresh. When a request fails with a 401 Unauthorized, the library can automatically refresh the token and retry the original request.

Example Implementation

Here is a mock implementation showing how to configure a fully automated auth loop:

services.AddRestMiddleware(options => 
{
    options.MethodToGetBaseUrl = () => "https://api.myapp.com";

    // 1. Tell the library how to fetch the CURRENT token asynchronously
    options.MethodToGetTokenAsync = async () => {
        return await MySecureStorage.GetTokenAsync();
    };

    // 2. Enable auto-refresh on 401
    options.FetchRefreshTokenIfUnauthorised = true;
    options.MethodToGetRefreshTokenEndpoint = () => "/api/auth/refresh";
    
    // Optional: Customize payload keys (Defaults: "jwt_token", "refresh_token")
    options.AccessTokenParameterName = "expiredToken"; 
    options.RefreshTokenParameterName = "refreshToken";
    
    // Optional: Provide the separate refresh token just for this call
    options.MethodToGetRefreshToken = () => MySecureStorage.GetRefreshToken();

    // 3. Tell the library how to SAVE the new token after refresh
    options.MethodToSetTokenLocallyAsync = async (tokenResponse) => {
        // 'tokenResponse' is the object returned by your refresh endpoint
        var newToken = ((dynamic)tokenResponse).access_token;
        await MySecureStorage.SaveTokenAsync(newToken);
    };
});

With this configuration, your repositories don't need to worry about expiration. RestClient will handle the "Expire โ†’ Refresh โ†’ Retry" cycle silently in the background.


Accessing Response Headers

var contentType = response.Headers["Content-Type"].FirstOrDefault();

๐Ÿ“ก Available Methods

All methods return (T data, HttpResponseDto response).

Method Description
GetSingleItem<T>(dto) GET a single object of type T.
GetList<T>(dto) GET a list of T.
GetPrimitiveTypeObject(dto) GET a primitive value (string, int, etc).
Post(dto) POST JSON body (returns HttpResponseDto).
PostAndGetObject<T>(dto) POST data and parse response as T.
PostAndGetList<T>(dto) POST data and parse response as List<T>.
PostMultipartAndGetObject<T>(dto) Form-data / Multipart POST.
DeleteItem(dto) DELETE request.

๐Ÿ“„ License

MIT License. Free for commercial and personal use.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  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.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos 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.0.0 121 1/11/2026