KGSoft.TinyHttpClient 3.0.2

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

KGSoft.TinyHttpClient

A lightweight .NET HTTP utility for consuming REST APIs with either a simple static helper API or a fluent request builder.

KGSoft.TinyHttpClient wraps common HttpClient tasks such as sending requests, applying headers, reading response content, deserializing JSON, handling typed responses, logging, and running authentication callbacks.

Targets .NET 10.

Installation

Install from NuGet:

dotnet add package KGSoft.TinyHttpClient

NuGet package:

https://www.nuget.org/packages/KGSoft.TinyHttpClient/

Features

  • Static helper API for quick requests
  • Fluent request builder for readable request composition
  • Typed responses via Response<T>
  • Automatic JSON deserialization
  • Raw response body access as both string and byte[]
  • Query string support with URL encoding
  • JSON request body support
  • Form-encoded request support
  • Custom HttpContent support
  • Global and per-request header configuration
  • Per-request Polly retry support
  • Configurable per-request JSON serialization settings
  • Reused HttpClient with configurable pooled connection lifetime, idle timeout, and request timeout
  • Logging support
  • Pre-request sync/async hooks for token acquisition or refresh
  • 401 sync/async callbacks for authentication expiry flows

Basic Usage

Static Helper API

Use the Helper class when you want concise one-line HTTP calls.

var response = await Helper.GetAsync("https://example.com/api/users/1");

if (response.IsSuccess)
{
    Console.WriteLine(response.Message);
}

Typed GET Request

var response = await Helper.GetAsync<User>("https://example.com/api/users/1");

if (response.IsSuccess)
{
    User user = response.Result;
}

POST Request

var body = JsonConvert.SerializeObject(new
{
    first_name = "Jane",
    last_name = "Doe"
});

var response = await Helper.PostAsync("https://example.com/api/users", body);

Typed POST Request

var body = JsonConvert.SerializeObject(new
{
    first_name = "Jane",
    last_name = "Doe"
});

var response = await Helper.PostAsync<User>("https://example.com/api/users", body);

if (response.IsSuccess)
{
    User user = response.Result;
}

Fluent API

Use HttpRequestBuilder when you want requests to read naturally and compose options per request.

GET

var response = await new HttpRequestBuilder()
    .Get("https://example.com/api/users/1")
    .MakeRequestAsync<User>();

You can also provide the URI to the builder constructor and call the HTTP verb without a URI:

var response = await new HttpRequestBuilder("https://example.com/api/users/1")
    .Get()
    .MakeRequestAsync<User>();

Or set the URI fluently:

var response = await new HttpRequestBuilder()
    .WithUri("https://example.com/api/users/1")
    .Get()
    .MakeRequestAsync<User>();

Query Parameters

var response = await new HttpRequestBuilder()
    .Get("https://example.com/api/users")
    .AddQueryParam("page", "1")
    .AddQueryParam("search", "jane doe")
    .MakeRequestAsync<UserSearchResult>();

POST JSON Body

var response = await new HttpRequestBuilder()
    .Post("https://example.com/api/users")
    .WithBody(new
    {
        first_name = "Jane",
        last_name = "Doe"
    })
    .MakeRequestAsync<User>();

PATCH JSON Body

var response = await new HttpRequestBuilder("https://example.com/api/users/1")
    .Patch()
    .WithBody(new
    {
        first_name = "Jane"
    })
    .MakeRequestAsync<User>();

HEAD and OPTIONS

var headResponse = await new HttpRequestBuilder("https://example.com/api/users/1")
    .Head()
    .MakeRequestAsync();

var optionsResponse = await new HttpRequestBuilder()
    .Options("https://example.com/api/users")
    .MakeRequestAsync();

Form-Encoded Request

var response = await new HttpRequestBuilder()
    .Post("https://example.com/oauth/token")
    .AddFormParam("grant_type", "client_credentials")
    .AddFormParam("client_id", "my-client-id")
    .AddFormParam("client_secret", "my-client-secret")
    .MakeRequestAsync<TokenResponse>();

Custom Headers

var response = await new HttpRequestBuilder()
    .Get("https://example.com/api/users/1")
    .WithHeader("X-Correlation-ID", correlationId)
    .WithBearerToken(accessToken)
    .MakeRequestAsync<User>();

Calling WithHeader for the same header name replaces the previous value.

Cancellation Token

using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));

var response = await new HttpRequestBuilder()
    .Get("https://example.com/api/users/1")
    .WithCancellationToken(cts.Token)
    .MakeRequestAsync<User>();

Custom Content

var response = await new HttpRequestBuilder("https://example.com/upload")
    .Post()
    .WithContent(() => new ByteArrayContent(fileBytes))
    .MakeRequestAsync();

Prefer the Func<HttpContent> overload when using retry policies, because it creates fresh content for each retry attempt.

Per-Request HttpClient

var response = await new HttpRequestBuilder("https://example.com/api/users/1")
    .Get()
    .WithHttpClient(httpClient)
    .MakeRequestAsync<User>();

When WithHttpClient is not used, requests use the shared pooled client managed by HttpConfig.

JSON Serialization Settings

var response = await new HttpRequestBuilder("https://example.com/api/users")
    .Post()
    .WithBody(user)
    .WithJsonSerializerSettings(new JsonSerializerSettings
    {
        NullValueHandling = NullValueHandling.Ignore
    })
    .MakeRequestAsync<User>();

Retry With Polly

var retryPolicy = new ResiliencePipelineBuilder<Response>()
    .AddRetry(new RetryStrategyOptions<Response>
    {
        ShouldHandle = new PredicateBuilder<Response>()
            .HandleResult(response => !response.IsSuccess),
        MaxRetryAttempts = 3,
        Delay = TimeSpan.FromSeconds(1)
    })
    .Build();

var response = await new HttpRequestBuilder()
    .Get("https://example.com/api/users/1")
    .WithRetry(retryPolicy)
    .MakeRequestAsync<User>();

Builders are intended to compose and send one request. Create a new HttpRequestBuilder for each request so headers, body, content, and retry policy state do not carry over unexpectedly.

Per-Request Logging

var response = await new HttpRequestBuilder("https://example.com/api/users/1")
    .Get()
    .WithLogger(logger)
    .MakeRequestAsync<User>();

WithLogger accepts either KGSoft.TinyHttpClient.Logging.ILogger or Microsoft.Extensions.Logging.ILogger, including ILogger<T>.

WithLogger logs all request activity by default. Use WithLogScope to limit that request to failed responses:

var response = await new HttpRequestBuilder("https://example.com/api/users/1")
    .Get()
    .WithLogger(logger)
    .WithLogScope(Enums.LogScope.OnlyFailedRequests)
    .MakeRequestAsync<User>();

Responses

Requests return either Response or Response<T>.

public class Response
{
    public HttpStatusCode StatusCode { get; set; }
    public bool IsSuccess { get; set; }
    public string Message { get; set; }
    public byte[] Content { get; set; }
}

public class Response<T> : Response
{
    public T Result { get; set; }
}

Message contains the response body as a string.

Content contains the response body as bytes.

Result contains the deserialized response body when using Response<T>.

Global Configuration

HttpConfig can be used to configure defaults shared by requests.

HttpConfig.MediaTypeHeader = Constants.ApplicationJson;
HttpConfig.RequestTimeoutSeconds = 100;
HttpConfig.HttpClientPoolLifetimeMinutes = 5;
HttpConfig.HttpClientPoolIdleMinutes = 2;

Default Authorization Header

HttpConfig.DefaultAuthHeader =
    new AuthenticationHeaderValue("Bearer", accessToken);

Global Custom Headers

HttpConfig.CustomHeaders["X-App-Version"] = "1.0.0";

Per-Request Header Configuration

var config = new HeaderConfig
{
    AuthHeader = new AuthenticationHeaderValue("Bearer", accessToken),
    CustomHeaders = new Dictionary<string, string>
    {
        { "X-Correlation-ID", correlationId }
    }
};

var response = await Helper.GetAsync<User>(
    "https://example.com/api/users/1",
    config: config);

Authentication Hooks

You can run logic before each request. This is useful for acquiring or refreshing tokens.

HttpConfig.PreRequestAuthAsyncFunc = async () =>
{
    var accessToken = await tokenProvider.GetAccessTokenAsync();

    HttpConfig.DefaultAuthHeader =
        new AuthenticationHeaderValue("Bearer", accessToken);
};

The hook runs before request headers are applied, so changes made inside the hook affect the current request.

401 Callbacks

You can register callbacks that run when a response returns 401 Unauthorized.

HttpConfig.UnauthorizedResultAction = () =>
{
    Console.WriteLine("Unauthorized response received.");
};

Or use an async callback:

HttpConfig.UnauthorizedResultAsyncFunc = async () =>
{
    await authService.RefreshSignInAsync();
};

Logging

Implement ILogger and assign it to HttpConfig.Logger.

public class ConsoleLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine(message);
    }
}

HttpConfig.Logger = new ConsoleLogger();
HttpConfig.LogScope = Enums.LogScope.AllRequests;

Supported log scopes:

Enums.LogScope.OnlyFailedRequests
Enums.LogScope.AllRequests

Notes

KGSoft.TinyHttpClient intentionally keeps the API small. It is useful when you want a lightweight wrapper around HttpClient without adopting a larger REST client framework.

For more examples, see the test project in this repository.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  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
3.0.2 109 6/1/2026
3.0.1 1,254 6/1/2026
3.0.0 101 6/1/2026
2.5.0 2,503 5/7/2026
2.4.0 1,016 12/11/2024
2.3.0 369 11/1/2023
2.2.0 723 7/27/2022
2.1.0 606 7/27/2022
2.0.1 630 6/15/2022
2.0.0 595 6/14/2022
2.0.0-rc1 349 6/3/2022
1.5.0 633 5/23/2022
1.4.1 1,472 8/21/2019
1.4.0 840 4/5/2019
1.3.1 825 4/4/2019
1.3.0 915 12/5/2018
1.2.0 906 11/27/2018
1.1.0 910 11/26/2018
1.0.0 935 11/22/2018

Target .NET 8