Fuzn.FluentHttp 0.6.7-beta

This is a prerelease version of Fuzn.FluentHttp.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package Fuzn.FluentHttp --version 0.6.7-beta
                    
NuGet\Install-Package Fuzn.FluentHttp -Version 0.6.7-beta
                    
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="Fuzn.FluentHttp" Version="0.6.7-beta" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Fuzn.FluentHttp" Version="0.6.7-beta" />
                    
Directory.Packages.props
<PackageReference Include="Fuzn.FluentHttp" />
                    
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 Fuzn.FluentHttp --version 0.6.7-beta
                    
#r "nuget: Fuzn.FluentHttp, 0.6.7-beta"
                    
#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 Fuzn.FluentHttp@0.6.7-beta
                    
#: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=Fuzn.FluentHttp&version=0.6.7-beta&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Fuzn.FluentHttp&version=0.6.7-beta&prerelease
                    
Install as a Cake Tool

Fuzn.FluentHttp

A lightweight fluent API for building and sending HTTP requests with HttpClient. Provides a clean, chainable interface for configuring URLs, headers, content types, authentication, and serialization.

Installation

To get started, add the Fuzn.FluentHttp package to your project using the following command:

dotnet add package Fuzn.FluentHttp

Quick Start

The following example demonstrates how to register an HttpClient with dependency injection and use it to make a simple GET request:

using Fuzn.FluentHttp;

// Register HttpClient with DI
services.AddHttpClient<UserHttpClient>(client =>
{
    client.BaseAddress = new Uri("https://api.example.com");
});

// Use in your service
public class UserHttpClient(HttpClient httpClient)
{
    public async Task<User?> GetUserAsync(int id)
    {
        var response = await httpClient
            .Url($"/users/{id}")
            .Get<User>();

        return response.IsSuccessful ? response.Data : null;
    }
}

Alternative syntax using Request().WithUrl():

var response = await httpClient.Request().WithUrl("/users/1").Get<User>();

Note: When HttpClient has no BaseAddress, you must use absolute URLs.

HTTP Methods

All standard HTTP methods are supported with both generic and non-generic versions. Generic methods automatically deserialize the response body:

// Non-generic returns FluentHttpResponse
await httpClient.Url("/resource").Get();
await httpClient.Url("/resource").Post();
await httpClient.Url("/resource").Put();
await httpClient.Url("/resource").Patch();
await httpClient.Url("/resource").Delete();
await httpClient.Url("/resource").Head();
await httpClient.Url("/resource").Options();

// Generic returns FluentHttpResponse<T> with deserialized Data property
await httpClient.Url("/resource").Get<T>();
await httpClient.Url("/resource").Post<T>();

// Custom HTTP methods (e.g., WebDAV)
await httpClient.Url("/resource").Send(new HttpMethod("PROPFIND"));
await httpClient.Url("/resource").Send<T>(new HttpMethod("MKCOL"));

Request Configuration

Content

Objects are automatically serialized to JSON:

await httpClient
    .Url("/users")
    .WithContent(new { Name = "John", Email = "john@example.com" })
    .Post<User>();

Query Parameters

Add query parameters to the request URL:

// Individual parameters (values must be strings)
.WithQueryParam("q", "dotnet")
.WithQueryParam("page", "1")

// Multiple values for same key (e.g., ?tags=c%23&tags=dotnet)
.WithQueryParam("tags", "c#")
.WithQueryParam("tags", "dotnet")

// For non-string values, convert to string yourself
.WithQueryParam("date", DateTime.UtcNow.ToString("O"))
.WithQueryParam("active", true.ToString().ToLower())

Headers

.WithHeader("X-Custom", "value")
.WithHeaders(new Dictionary<string, string> { ["X-Another"] = "value" })

Authentication

Built-in support for common authentication schemes:

.WithAuthBearer("jwt-token")
.WithAuthBasic("username", "password")
.WithAuthApiKey("api-key")                    // Uses X-API-Key header
.WithAuthApiKey("api-key", "Authorization")   // Custom header name

Content & Accept Types

Control request and response content types:

.WithContentType(ContentTypes.Json)
.WithContentType("application/graphql")
.WithAccept(AcceptTypes.Json)
.WithAccept("application/pdf")

File Uploads

Upload files with automatic multipart/form-data handling:

await httpClient
    .Url("/upload")
    .WithFile("file", "doc.pdf", fileStream, "application/pdf")
    .WithFormField("description", "My document")
    .Post<UploadResult>();

Other Options

.WithTimeout(TimeSpan.FromSeconds(30))
.WithUserAgent("MyApp/1.0")
.WithCookie("session", "abc123")
.WithVersion(HttpVersion.Version20)
.WithVersionPolicy(HttpVersionPolicy.RequestVersionExact)
.WithCancellationToken(cancellationToken)

Working with Responses

FluentHttpResponse / FluentHttpResponse<T>

Responses provide easy access to status, content, headers, and cookies. The response body is only deserialized when you access the Data property, not automatically upon receiving the response:

var response = await httpClient.Url("/users/1").Get<User>();

// Check status
if (response.IsSuccessful)
{
    User user = response.Data!;  // Deserialization happens here
}

// Or throw HttpRequestException on failure
response.EnsureSuccessful();

// Access response properties
HttpStatusCode status = response.StatusCode;
string? reason = response.ReasonPhrase;
string content = response.Content;
string? contentType = response.ContentType;
long? contentLength = response.ContentLength;
Version version = response.Version;

// Access headers and cookies
var headers = response.Headers;
var contentHeaders = response.ContentHeaders;
var cookies = response.Cookies;

// Access underlying messages
HttpResponseMessage inner = response.InnerResponse;
HttpRequestMessage request = response.RequestMessage;

// Deserialize to different type (useful for error responses)
var error = response.ContentAs<ProblemDetails>();

// Try deserialize without throwing
if (response.TryContentAs<User>(out var user))
{
    // Use user
}

Streaming Responses

For large files, use streaming to avoid loading the entire response into memory. The FluentHttpStreamResponse must be disposed after use:

await using var response = await httpClient.Url("/files/large.zip").GetStream();

if (response.IsSuccessful)
{
    // Access metadata
    long? size = response.ContentLength;
    string? type = response.ContentType;
    string? fileName = response.FileName;  // From Content-Disposition header

    // Read as stream or bytes
    var stream = await response.GetStream();
    // Or: var bytes = await response.GetBytes();
}

Custom Serialization

By default, FluentHttp uses System.Text.Json with JsonSerializerDefaults.Web (camelCase, case-insensitive).

Per-Request Options

Customize serialization on a per-request basis:

.WithJsonOptions(new JsonSerializerOptions { PropertyNamingPolicy = null })
.WithSerializer(new MyCustomSerializer())

Global Defaults

Configure defaults for all requests:

FluentHttpDefaults.JsonOptions = new JsonSerializerOptions { PropertyNamingPolicy = null };
FluentHttpDefaults.Serializer = new NewtonsoftSerializerProvider();

Custom Serializer

Implement ISerializerProvider for custom serialization:

public class NewtonsoftSerializerProvider : ISerializerProvider
{
    public string Serialize<T>(T obj) => JsonConvert.SerializeObject(obj);
    public T? Deserialize<T>(string json) => JsonConvert.DeserializeObject<T>(json);
}

Resilience & Retry

FluentHttp works seamlessly with HttpClient's DelegatingHandler pipeline. Use libraries like Polly for retry policies, circuit breakers, and other resilience patterns:

services.AddHttpClient("MyApi")
    .AddStandardResilienceHandler();  // Microsoft.Extensions.Http.Resilience
    // Or: .AddTransientHttpErrorPolicy(...) // Microsoft.Extensions.Http.Polly

Debugging

Both requests and responses override ToString() for easy inspection:

// Inspect request configuration
var builder = httpClient.Url("/users").WithAuthBearer("token");
Console.WriteLine(builder);  // Prints formatted request details (auth is redacted)

// Inspect response
Console.WriteLine(response);  // Prints status, headers, and content

// Get HttpRequestMessage without sending
var request = builder.BuildRequest(HttpMethod.Post);

License

MIT License - see LICENSE for details.

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.
  • net10.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Fuzn.FluentHttp:

Package Downloads
Fuzn.TestFuzn.Plugins.Http

Http plugin for TestFuzn

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.6.8-beta 385 2/13/2026
0.6.7-beta 51 2/12/2026
0.6.6-beta 55 2/9/2026
0.6.5-beta 49 2/9/2026
0.6.4-beta 52 2/8/2026
0.6.3-beta 48 2/4/2026
0.6.2-beta 47 2/4/2026
0.6.1-beta 46 2/3/2026
0.6.0-beta 50 2/1/2026
0.0.11-beta 49 1/30/2026
0.0.10-beta 45 1/30/2026
0.0.9-beta 85 1/30/2026
0.0.8-beta 50 1/30/2026
0.0.7-beta 50 1/29/2026
0.0.6-beta 49 1/29/2026
0.0.5-beta 56 1/26/2026
0.0.4-beta 55 1/26/2026
0.0.3-beta 53 1/25/2026