What it is
HttpForge is the contract layer. You declare HTTP REST as a C# interface. A source generator emits the HttpClient implementation at compile time — there is no runtime reflection request builder.
public interface IUserApi
{
[Get("/users/{id}")]
Task<User> GetUser(int id, CancellationToken cancellationToken = default);
[Post("/users")]
Task<User> CreateUser([Body] CreateUserRequest request);
}
var user = await api.GetUser(42);Registration
UseHttpForge() is the MAUI host hook. AddHttpForgeClient<T>() registers the generated client with IHttpClientFactory and returns IHttpClientBuilder.
using Plugin.Maui.HttpForge;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseHttpForge();
builder.Services.AddHttpForgeClient<IUserApi>(client =>
{
client.BaseAddress = new Uri("https://api.example.com");
});
return builder.Build();
}
}Resolve IUserApi from DI. Without the host:
var api = RestService.For<IUserApi>("https://api.example.com");Contract surface
| Feature | How |
|---|---|
| HTTP methods | [Get], [Post], [Put], [Delete], [Patch], [Head] |
| Path parameters | /users/{id} matches int id or [AliasAs("id")] |
| Query parameters | Remaining parameters, or [Query] / [Query("q")] |
| JSON body | [Body] |
| Headers | [Headers("Accept: application/json")], [Header("X-Request-Id")] |
| Multipart | [Multipart] with StreamPart, ByteArrayPart, FileInfoPart |
| Cancellation | CancellationToken |
| Rich response | Task<IApiResponse<T>> (no throw on 4xx/5xx) |
| Errors | ApiException (HTTP response), ApiRequestException (transport) |
| JSON | System.Text.Json (optional JsonSerializerContext for AOT) |
Unsupported shapes fail at compile time (HFG001–HFG006). HttpForge is generated-only — there is no reflection fallback package.
Multipart
[Multipart]
[Post("/users/{id}/photo")]
Task UploadPhoto(int id, [AliasAs("file")] StreamPart file);
await api.UploadPhoto(7, new StreamPart(stream, "photo.jpg", "image/jpeg"));Errors and rich responses
A Task<T> method throws ApiException when the server returns 4xx/5xx, and ApiRequestException when the transport fails (timeout, DNS, TLS). Task<IApiResponse<T>> does not throw on HTTP error status — inspect the response instead.
- ApiException — an HTTP response arrived and was not success.
- ApiRequestException — the request never completed as an HTTP response.
- IApiResponse<T> — status, headers, and deserialized body without throwing on 4xx/5xx.
JSON and AOT
The default serializer is System.Text.Json. Hosts that trim or publish AOT can supply a JsonSerializerContext. Hosts can also swap IHttpContentSerializer. Newtonsoft.Json and XML are not in the core package.
Not in v1
HttpForge 1.0.x is a focused subset. These Refit surfaces are not in v1 — they are roadmap items, not bugs.
| Missing | Direction |
|---|---|
| Query objects, collection formats, camel/snake/kebab | Next contract increment |
| [Timeout], [Url], [PathPrefix], optional route segments | Next contract increment |
| [QueryName] valueless flags, [FormObject] | Next contract increment |
| SSE / IAsyncEnumerable / JSON Lines | Later — streaming |
| Request-body compression | Later — transport convenience |
| Authorization header value getter | Later, or keep composing SecureSession / ApiResilience |
| Newtonsoft.Json / XML packages | Optional packages only if hosts need them |
| Reflection fallback | Not planned — stay generated-only |
| First-party stub testing package | Later — HttpForge.Testing |
Platforms and version
Version 1.0.1. Target frameworks: net10.0, net10.0-android (API 21+), net10.0-ios (iOS 15+), net10.0-maccatalyst (15+), and net10.0-windows10.0.19041.0 (Windows 10.0.17763+). CI packs the Windows TFM on windows-latest and merges it into the nupkg published from macOS.