AutoHttpClient.Generator 1.5.0

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

AutoHttpClient.Generator

NuGet NuGet Downloads CI License: MIT .NET 10 Ready

AutoHttpClient.Generator is an AOT-safe, compile-time typed HTTP client for .NET. Annotate an interface with [HttpClient], decorate methods with [Get], [Post], [Put], [Delete], or [Patch], and the generator emits a strongly-typed implementation plus DI registration at build time.

Why AutoHttpClient.Generator?

  • Compile-time generated clients — no dynamic proxy generation, no reflection-heavy dispatch layer
  • AOT-safe request dispatch — generated C# calls HttpClient directly with no reflection-based proxy, and passing an explicit JsonSerializerOptions (ideally backed by a JsonSerializerContext) to the constructor or AddAutoHttpClients(jsonOptions) produces zero trim/AOT warnings, measured against Refit in samples/AotBenchmark/BENCHMARK.md
  • Minimal ceremony — plain interfaces plus attributes, no hand-written wrappers
  • DI-ready — AddAutoHttpClients() registers every generated client for IServiceCollection
  • Strongly typed — route values, query parameters, headers, and JSON bodies all come from your method signature

Why not Refit or RestSharp?

  • Refit (v16+) has also moved to a Roslyn source generator and ships an official Native AOT path (RestService.ForGenerated<T> + a JsonSerializerContext), so it's no longer purely runtime-proxy based. Both libraries can now produce warning-free trimmed/AOT builds when given explicit JSON type info. The real differences today are ergonomics: AutoHttpClient.Generator's generated client can be constructed directly (new) or resolved from DI with zero extra AOT-specific API surface, has build-time diagnostics for common mistakes (see Diagnostics), and ships an OpenAPI scaffolding tool. See samples/AotBenchmark/BENCHMARK.md for a measured, head-to-head trim/AOT comparison.
  • RestSharp is a runtime HTTP abstraction with reflection-oriented configuration rather than compile-time emitted clients
  • AutoHttpClient.Generator keeps everything as generated source in your build output: explicit, trim-friendly, and (for the request-building path) zero-reflection

Installation

dotnet add package AutoHttpClient.Generator

Then register the generated clients:

builder.Services.AddAutoHttpClients();

Quick start

using AutoHttpClient;

[HttpClient]
public interface IOrdersApi
{
    [Get("/api/orders/{id}")]
    Task<Order?> GetOrderAsync(int id, CancellationToken ct = default);

    [Get("/api/orders")]
    Task<List<Order>> GetOrdersAsync([Query("status")] string? status = null, CancellationToken ct = default);

    [Post("/api/orders")]
    Task<Order> CreateOrderAsync([Body] CreateOrderRequest request, CancellationToken ct = default);

    [Put("/api/orders/{id}")]
    Task<Order> UpdateOrderAsync(int id, [Body] UpdateOrderRequest request, CancellationToken ct = default);

    [Delete("/api/orders/{id}")]
    Task DeleteOrderAsync(int id, CancellationToken ct = default);

    [Get("/api/orders/{id}/status")]
    Task<HttpResponseMessage> GetOrderStatusRawAsync(int id, CancellationToken ct = default);
}

Register the generated implementation:

builder.Services.AddAutoHttpClients();

This emits an internal sealed client implementation and a DI registration similar to:

services.AddHttpClient("global::IOrdersApi").AddTypedClient<IOrdersApi>(httpClient => new OrdersApiClient(httpClient, jsonOptions));

AddAutoHttpClients() (parameterless) is a convenience overload that falls back to JsonSerializerOptions.Web; it's annotated [RequiresUnreferencedCode]/ [RequiresDynamicCode] so it only warns if you actually use it. For a fully warning-free trimmed/Native AOT build, pass your own options instead — ideally backed by a source-generated JsonSerializerContext:

builder.Services.AddAutoHttpClients(new JsonSerializerOptions(MyJsonContext.Default.Options)
{
    TypeInfoResolver = MyJsonContext.Default,
});

See samples/AotBenchmark/BENCHMARK.md for a measured, zero-warning comparison against Refit using this pattern.

Parameter attributes

AutoHttpClient.Generator classifies parameters using these rules:

Parameter style Behavior
[Body] Serialized as JSON request content
[Query("name")] Added to the query string using the provided name
[Query] or unattributed non-route parameter Added to the query string using the parameter name
Array/IEnumerable<T> query parameter (not string) Expanded into one repeated name=value entry per element
[Header("X-Name")] Added as an HTTP header
[HeaderCollection] Expands an IDictionary<string, string?> (or any IEnumerable<KeyValuePair<string, string?>>) parameter into one header per entry
[QueryMap] Expands an IDictionary<string, string?> (or any IEnumerable<KeyValuePair<string, string?>>) parameter into one query string entry per pair
Route parameter Any parameter whose name appears in the route template, e.g. {id}
CancellationToken Passed through to HttpClient and JSON helpers

Examples

[Get("/api/orders")]
Task<List<Order>> GetOrdersAsync([Query("status")] string? status = null, int page = 1, CancellationToken ct = default);

[Post("/api/orders")]
Task<Order> CreateOrderAsync([Body] CreateOrderRequest request, [Header("X-Tenant")] string tenant, CancellationToken ct = default);

[Get("/api/orders/{id}")]
Task<Order?> GetOrderAsync(int id, CancellationToken ct = default);

[Get("/api/orders")]
Task<List<Order>> SearchOrdersAsync([QueryMap] IDictionary<string, string?> filters, CancellationToken ct = default);

[Get("/api/orders")]
Task<List<Order>> GetOrdersForTenantAsync([HeaderCollection] IDictionary<string, string?> headers, CancellationToken ct = default);

Static headers

Apply constant headers to every request generated for an interface or a specific method with [Headers("Name: Value")], similar to Refit:

using AutoHttpClient;

[HttpClient(BaseAddress = "https://api.example.com")]
[Headers("X-Api-Version: 1.0")]
public interface IOrdersApi
{
    [Get("/api/orders")]
    [Headers("Accept: application/json")]
    Task<List<Order>> GetOrdersAsync(CancellationToken ct = default);
}

Method-level [Headers] take priority over interface-level ones when the same header name is declared in both places. [Headers] can be applied multiple times on the same target.

Multipart form uploads

Mark a method [Multipart] and decorate its parameters with [Part] to send a multipart/form-data request — useful for file uploads:

using AutoHttpClient;

[HttpClient(BaseAddress = "https://api.example.com")]
public interface IUploadsApi
{
    [Post("/api/uploads")]
    [Multipart]
    Task<UploadResult> UploadAsync(
        [Part("file", "photo.png")] Stream file,
        [Part("description")] string description,
        [Part] UploadMetadata metadata,
        CancellationToken ct = default);
}

Part parameter types are handled automatically:

Parameter type Generated content
string StringContent
byte[] ByteArrayContent
Stream (or subclass) StreamContent
Anything else JSON-serialized via JsonContent.Create

[Part(name, fileName)] controls the form field name and, optionally, the file name sent to the server; both default to the parameter name / no file name. A [Multipart] method cannot also declare a [Body] parameter (AH004).

Return types

Return type Generated behavior
Task Sends the request and throws ApiException on a non-success status code
Task<T> Sends the request, checks for success, and deserializes JSON with ReadFromJsonAsync<T>()
Task<T?> Same as Task<T> but preserves nullable result types
Task<HttpResponseMessage> Returns the raw response without any success check
IObservable<T> Wraps the same request/response/deserialize logic in an IObservable<T> — see Observable return types below
IAsyncEnumerable<T> Streams a JSON array response lazily — see Streaming with IAsyncEnumerable below

Observable return types

Methods can also return IObservable<T> instead of Task<T> for interop with Rx-style code (a single HTTP call surfaced as an observable sequence, matching Refit's IObservable<T> support):

using AutoHttpClient;

[HttpClient]
public interface IOrdersApi
{
    [Get("/api/orders/{id}")]
    IObservable<Order> GetOrderAsync(int id);
}

// usage
ordersApi.GetOrderAsync(42).Subscribe(
    order => Console.WriteLine(order.Id),
    ex => Console.WriteLine($"Failed: {ex.Message}"));
  • The call doesn't start until Subscribe is called; disposing the returned subscription cancels the in-flight request.
  • On success, the observer receives exactly one OnNext followed by OnCompleted. On failure (including a non-success status code, which throws ApiException), the observer receives OnError instead.
  • No dependency on System.Reactive is required — it's a minimal IObservable<T>/IObserver<T> bridge using only BCL types.
  • A CancellationToken parameter isn't meaningful on an IObservable<T>-returning method (cancellation is via the subscription's IDisposable.Dispose() instead), so don't declare one there.

Streaming with IAsyncEnumerable

Methods can return IAsyncEnumerable<T> to lazily stream a large JSON array response one element at a time instead of buffering the whole array in memory — something Refit doesn't support:

using AutoHttpClient;
using System.Collections.Generic;
using System.Threading;

[HttpClient]
public interface IOrdersApi
{
    [Get("/api/orders")]
    IAsyncEnumerable<Order> StreamOrdersAsync(CancellationToken ct = default);
}

// usage
await foreach (var order in ordersApi.StreamOrdersAsync(ct))
{
    Console.WriteLine(order.Id);
}
  • The response and its underlying stream are disposed automatically when enumeration completes or the await foreach is exited early (via break, an exception, or cancellation).
  • Deserialization uses System.Text.Json.JsonSerializer.DeserializeAsyncEnumerable<T>, so elements are yielded as they're parsed instead of waiting for the entire response body.
  • A non-success status code throws ApiException before any elements are yielded.
  • Declare an explicit CancellationToken parameter (as shown above) to cancel enumeration — [EnumeratorCancellation]/.WithCancellation() support is intentionally not implemented to keep the generated code simple.
  • [Retry] (below) can't be combined with IAsyncEnumerable<T> methods (diagnostic AH007) because C# iterator methods can't wrap yield return in a try/catch.

Resilience presets with [Resilience]

For a one-attribute resilience policy, use [Resilience] on a method. It applies timeout + retry defaults together:

  • Conservative → 2 attempts, 500ms base delay, 15s timeout
  • Standard (default) → 3 attempts, 200ms base delay, 30s timeout
  • Aggressive → 5 attempts, 100ms base delay, 60s timeout
using AutoHttpClient;

[HttpClient]
public interface IOrdersApi
{
    [Get("/api/orders/{id}")]
    [Resilience(ResiliencePreset.Aggressive)]
    Task<Order> GetOrderAsync(int id, CancellationToken ct = default);
}

[Resilience] is method-level, so different endpoints can use different policies. If both [Resilience] and [Retry] are applied, explicit [Retry] values win for retry attempts/delay, while timeout still comes from the selected resilience preset.

Automatic retry with [Retry]

Decorate a method with [Retry(maxAttempts, delayMilliseconds)] to automatically retry on transient failures — no dependency on Polly required:

using AutoHttpClient;

[HttpClient]
public interface IOrdersApi
{
    [Get("/api/orders/{id}")]
    [Retry(maxAttempts: 5, delayMilliseconds: 100)]
    Task<Order> GetOrderAsync(int id, CancellationToken ct = default);
}
  • Defaults are maxAttempts: 3, delayMilliseconds: 200 if omitted.
  • A failure is considered transient (and retried) if it's an ApiException with a 5xx, 408, or 429 status code, or an HttpRequestException (e.g. a connection failure). Genuine cancellations (OperationCanceledException/TaskCanceledException) are never retried.
  • Delay between attempts grows exponentially (attempt 1 waits the base delay, attempt 2 waits 2x, attempt 3 waits 4x, and so on).
  • The entire request (URL/query/header/body construction and the HTTP call) is retried, not just the deserialization step, since a failed HttpClient.SendAsync call may not have reached the server at all.
  • Not supported on IAsyncEnumerable<T>-returning methods — see Streaming with IAsyncEnumerable above.

Per-method JsonSerializerOptions override

By default every generated method uses the single JsonSerializerOptions instance passed to the client's constructor (or registered via AddAutoHttpClients(jsonOptions)). Override it for an individual method with [JsonSerializerOptions(providerType, memberName)], pointing at a public static property or field of type JsonSerializerOptions:

using AutoHttpClient;
using System.Text.Json;

public static class LegacyApiJsonOptions
{
    public static JsonSerializerOptions Options { get; } = new JsonSerializerOptions
    {
        PropertyNamingPolicy = null, // this endpoint still uses PascalCase
    };
}

[HttpClient]
public interface IOrdersApi
{
    [Get("/api/orders/{id}")]
    [JsonSerializerOptions(typeof(LegacyApiJsonOptions), nameof(LegacyApiJsonOptions.Options))]
    Task<Order> GetOrderAsync(int id, CancellationToken ct = default);
}

If the referenced member doesn't exist (or isn't a public static JsonSerializerOptions property/field), diagnostic AH006 is reported and the method falls back to the client-wide options.

Error handling

Non-success responses throw AutoHttpClient.ApiException (instead of a bare EnsureSuccessStatusCode() call) so you don't lose the response body:

try
{
    var order = await ordersApi.GetOrderAsync(404, ct);
}
catch (AutoHttpClient.ApiException ex)
{
    // ex.StatusCode, ex.ReasonPhrase, ex.Content (raw response body, best-effort)
}

If you need the raw HttpResponseMessage instead (no exception thrown), use a Task<HttpResponseMessage> return type.

BaseAddress configuration

You can configure a base address directly on the interface attribute:

using AutoHttpClient;

[HttpClient(BaseAddress = "https://api.example.com")]
public interface IOrdersApi
{
    [Get("/api/orders")]
    Task<List<Order>> GetOrdersAsync(CancellationToken ct = default);
}

The generated DI registration configures the typed client:

services.AddHttpClient<IOrdersApi, OrdersApiClient>(client =>
{
    client.BaseAddress = new Uri("https://api.example.com");
});

Scaffolding from OpenAPI/Swagger

AutoHttpClient.Generator now includes a small repo-side scaffolding tool for converting an OpenAPI/Swagger JSON document into a partial interface decorated with AutoHttpClient attributes.

Run it with:

dotnet run --project tools/AutoHttpClient.OpenApiScaffold -- --input swagger.json --output IMyApiClient.g.cs --namespace MyApp.Clients --interface-name IMyApiClient

The generated file is a one-time scaffold that you add to your project, then the existing AutoHttpClient.Generator source generator consumes it normally.

What it generates

  • [HttpClient] or [HttpClient(BaseAddress = "...")] when the spec declares a simple server URL
  • [Get], [Post], [Put], [Delete], [Patch] based on each OpenAPI operation
  • Route parameters as normal method parameters
  • Query parameters as [Query("name")]
  • Request bodies as [Body]
  • Task<T> return types using referenced schema names where possible

Current scope / limitations

  • Optimized for common OpenAPI 3 JSON documents
  • Swagger/OpenAPI 2 documents may work for basic paths/operations, but v3 is the primary target
  • Best support is for JSON request/response bodies with named schemas, simple path/query/header parameters, and standard HTTP verbs
  • Inline/anonymous schemas fall back to JsonElement (or collections/dictionaries of known types where possible)
  • Advanced OpenAPI features such as oneOf, anyOf, callbacks, multipart form uploads, and full DTO generation are not scaffolded yet
  • Named schemas are used as C# type names in the generated interface; you still need matching DTO types in your project

Comparison

Feature AutoHttpClient.Generator Refit (v16+) RestSharp
Compile-time generated client ✅ ✅ (also generator-based) ❌
AOT-safe out of the box (no reflection-based JSON) ✅ 0 trim/AOT warnings, measured — see BENCHMARK.md ✅ with JsonSerializerContext ❌
Zero reflection dispatch ✅ ✅ ❌
Native HttpClient typed client DI ✅ ✅ ⚠️ manual
Interface-first API ✅ ✅ ❌
OpenAPI/Swagger scaffolding tool ✅ (repo tool) ✅ ⚠️ varies
Build-time diagnostics ✅ Limited ❌
Typed exception with response body on failure ✅ (ApiException) ✅ (ApiException) ⚠️ manual
Collection query parameter expansion ✅ ✅ ⚠️ manual
Multipart/form-data uploads ✅ ✅ ⚠️ manual
IObservable<T> return types ✅ ✅ ❌
Per-method JSON serializer override ✅ ([JsonSerializerOptions]) ⚠️ per-RefitSettings instance, not per-method ❌
IAsyncEnumerable<T> streaming responses ✅ ❌ ❌
Per-endpoint resilience presets ✅ ([Resilience(Conservative/Standard/Aggressive)]) ❌ ❌
Built-in retry with exponential backoff ✅ ([Retry], no Polly needed) ❌ (requires Polly + HttpClientFactory handlers) ❌

Diagnostics

Code Severity Message
AH001 Warning Method on a [HttpClient] interface has no HTTP method attribute and will not be generated.
AH002 Warning Route template parameter has no matching method parameter.
AH003 Error Method has multiple [Body] parameters; only one is allowed.
AH004 Error Method is marked [Multipart] but also has a [Body] parameter.
AH005 Warning Parameter is marked [Part] but its method is not marked [Multipart].
AH006 Warning [JsonSerializerOptions] provider member wasn't found (or isn't a public static JsonSerializerOptions property/field) — the client-wide options are used instead.
AH007 Warning [Retry] is combined with an IAsyncEnumerable<T>-returning method and is ignored, since iterator methods can't wrap yield return in a try/catch.

Generated attributes

The package emits these attributes at post-initialization time:

  • HttpClientAttribute
  • GetAttribute
  • PostAttribute
  • PutAttribute
  • DeleteAttribute
  • PatchAttribute
  • BodyAttribute
  • QueryAttribute
  • HeaderAttribute
  • HeadersAttribute
  • HeaderCollectionAttribute
  • QueryMapAttribute
  • MultipartAttribute
  • PartAttribute
  • ApiException

Migrating from Refit

AutoHttpClient.Generator uses the same interface-first approach as Refit. Migration is mostly a find-and-replace of attributes.

1. Install and remove Refit

dotnet add package AutoHttpClient.Generator
dotnet remove package Refit
dotnet remove package Refit.HttpClientFactory

2. Replace Refit attributes with AutoHttpClient attributes

// Before (Refit)
using Refit;

public interface IOrdersApi
{
    [Get("/api/orders/{id}")]
    Task<Order?> GetOrderAsync(int id, CancellationToken ct = default);

    [Post("/api/orders")]
    Task<Order> CreateOrderAsync([Body] CreateOrderRequest request, CancellationToken ct = default);

    [Get("/api/orders")]
    Task<List<Order>> GetOrdersAsync([AliasAs("status")] string? status = null);
}

// After (AutoHttpClient.Generator)
using AutoHttpClient;

[HttpClient]
public interface IOrdersApi
{
    [Get("/api/orders/{id}")]
    Task<Order?> GetOrderAsync(int id, CancellationToken ct = default);

    [Post("/api/orders")]
    Task<Order> CreateOrderAsync([Body] CreateOrderRequest request, CancellationToken ct = default);

    [Get("/api/orders")]
    Task<List<Order>> GetOrdersAsync([Query("status")] string? status = null);
}

3. Update DI registration

// Before (Refit)
builder.Services.AddRefitClient<IOrdersApi>()
    .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://api.example.com"));

// After (AutoHttpClient.Generator)
[HttpClient(BaseAddress = "https://api.example.com")]
public interface IOrdersApi { ... }

builder.Services.AddAutoHttpClients();

Attribute mapping

Refit AutoHttpClient.Generator
[Get("/path")] [Get("/path")]
[Post("/path")] [Post("/path")]
[Put("/path")] [Put("/path")]
[Delete("/path")] [Delete("/path")]
[Patch("/path")] [Patch("/path")]
[Body] [Body]
[AliasAs("name")] [Query("name")]
[Header("X-Name")] [Header("X-Name")]
[Headers("X: Y")] [Headers("X: Y")]
[HeaderCollection] [HeaderCollection]
[Multipart] / [AttachmentName] [Multipart] / [Part(name, fileName)]
[Authorize] Use [Header("Authorization")]

Feature parity with Refit — and beyond

IObservable<T> return types and per-method JSON serializer overrides ([JsonSerializerOptions]) are both supported — see Observable return types and Per-method JsonSerializerOptions override above. AutoHttpClient.Generator also goes further than Refit with three built-in differentiators Refit doesn't offer at all: IAsyncEnumerable<T> streaming responses, Polly-free automatic retry, and per-endpoint resilience presets.

Also by the same author

🌐 Full suite overview: swevo.github.io

Package Description
AutoLog.Generator Compile-time high-performance logging — [Log(Level, Message)] on a partial method generates LoggerMessage.Define. AOT-safe.
AutoDispatch.Generator Compile-time CQRS dispatcher — [Handler] generates a strongly-typed IDispatcher. No MediatR, no reflection.
AutoWire Compile-time DI auto-registration — [Scoped]/[Singleton]/[Transient] generates IServiceCollection registration code.
AutoMap.Generator Compile-time object mapping with generated extension methods. AOT-safe AutoMapper alternative.
AutoValidate.Generator Compile-time FluentValidation wiring — discovers validators and generates AddValidators().
AutoResult.Generator Compile-time Result<T> — [TryWrap] generates Try*() wrappers for every public method.
AutoQuery.Generator Compile-time LINQ query specs — [QuerySpec] generates a strongly-typed Apply(IQueryable<T>).
Package Downloads Description
AutoWire Downloads Compile-time dependency injection auto-registration for
AutoMap.Generator Downloads Compile-time object mapping for
AutoQuery.Generator Downloads Compile-time query composition for IQueryable using Roslyn incremental source generators
AutoArchitecture Downloads Compile-time architecture/dependency-rule enforcement for
AutoDispatch.Generator Downloads Compile-time CQRS dispatcher for
AutoLog.Generator Downloads Compile-time high-performance logging for
AutoValidate.Generator Downloads Compile-time FluentValidation wiring for

License

MIT

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

  • .NETStandard 2.0

    • No dependencies.

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.5.0 0 9/29/2026
1.4.0 0 9/29/2026
1.1.0 138 7/10/2026
1.0.1 124 6/30/2026
1.0.0 127 6/30/2026

1.5.0: Add built-in [Resilience(ResiliencePreset)] per-method policy presets (Conservative/Standard/Aggressive) that combine timeout + retry defaults without external Polly wiring; explicit [Retry] continues to override preset retry values while keeping preset timeout. 1.4.0: Add IAsyncEnumerable<T> streaming return type support (lazily deserializes a JSON array response element-by-element via JsonSerializer.DeserializeAsyncEnumerable, disposing the response/stream when enumeration ends) and a Polly-free [Retry(maxAttempts, delayMilliseconds)] attribute with exponential backoff for transient failures (ApiException 5xx/408/429 or HttpRequestException); AH007 diagnostic when [Retry] is combined with IAsyncEnumerable<T> (unsupported, ignored). Both go beyond Refit parity. 1.3.0: Add IObservable<T> return type support (closes the Refit parity gap) and a per-method [JsonSerializerOptions(providerType, memberName)] override with AH006 diagnostic for an invalid/missing provider member. 1.2.0: Static headers ([Headers]), [HeaderCollection], [QueryMap], collection query parameter expansion, multipart form uploads ([Multipart]/[Part]), ApiException with EnsureSuccessAsync error handling, and AH004/AH005 diagnostics. Zero-warning Native AOT/trim publishing: generated code now resolves JsonTypeInfo of T from JsonSerializerOptions instead of using generic reflection-capable overloads, and DI registration (AddAutoHttpClients(jsonOptions)) no longer requires trim-unsafe constructors. 1.1.0: Add OpenAPI/Swagger scaffolding tool in the repo for generating AutoHttpClient interfaces from spec documents. 1.0.1: Fix package icon (was showing an incorrect/placeholder image). 1.0.0: [HttpClient] on interface; [Get]/[Post]/[Put]/[Delete]/[Patch] methods; [Body]/[Query]/[Header] parameters; route template interpolation; AddAutoHttpClients() DI registration; AH001/AH002/AH003 diagnostics.