Skip to content
NLNuvyntra Labs

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

FeatureHow
HTTP methods[Get], [Post], [Put], [Delete], [Patch], [Head]
Path parameters/users/{id} matches int id or [AliasAs("id")]
Query parametersRemaining parameters, or [Query] / [Query("q")]
JSON body[Body]
Headers[Headers("Accept: application/json")], [Header("X-Request-Id")]
Multipart[Multipart] with StreamPart, ByteArrayPart, FileInfoPart
CancellationCancellationToken
Rich responseTask<IApiResponse<T>> (no throw on 4xx/5xx)
ErrorsApiException (HTTP response), ApiRequestException (transport)
JSONSystem.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.

MissingDirection
Query objects, collection formats, camel/snake/kebabNext contract increment
[Timeout], [Url], [PathPrefix], optional route segmentsNext contract increment
[QueryName] valueless flags, [FormObject]Next contract increment
SSE / IAsyncEnumerable / JSON LinesLater — streaming
Request-body compressionLater — transport convenience
Authorization header value getterLater, or keep composing SecureSession / ApiResilience
Newtonsoft.Json / XML packagesOptional packages only if hosts need them
Reflection fallbackNot planned — stay generated-only
First-party stub testing packageLater — 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.

Plugin.Maui.HttpForge on NuGet

Source on GitHub