Skip to content

Refit

Run the complete page example.

When your app needs data from a web service, you want the call to be easy to read and use. Refit lets you describe that call on a C# interface. You specify the service's route and the values it needs, then call the interface method to make the request.

Refit generates the implementation during the build. It fills in the URL, headers and body, sends the request through HttpClient, and reads the reply into your C# model.

These examples use .NET 10 and C# 14 as their baseline. All C# 14 features are available. Examples for another target framework say so explicitly.

You keep control of the HTTP client and can share settings for JSON, authorization and error handling. The walkthrough below builds a first call, then the subject pages explain the choices in more detail.

Install the Refit NuGet package in the project that declares your interface.

dotnet add package Refit

Your first request

1. Choose a reply type. This service returns a person's ID and name as JSON. JSON is a text format for objects, lists and values.

internal sealed record Person(int Id, string Name);

2. Describe the request. [Get] selects the HTTP GET method. A GET asks a service to read data. The {id} part is a route placeholder. Refit replaces it with the method's id argument. An interface like this is the contract between your app and the service.

internal interface IPeopleApi
{
    [Get("/people/{id}")]
    Task<Person> GetPersonAsync(int id, CancellationToken cancellationToken);
}

3. Register the JSON types. Refit reads and writes JSON with System.Text.Json, and takes advantage of its source generation. You declare a JSON context: a partial class that derives from JsonSerializerContext and lists your model types. The System.Text.Json source generator fills it in when you build, so nothing inspects your models through reflection at runtime. SampleJsonContext is only the name this example gives its class. Give yours any name. Use the same context when you publish a Native AOT app. Add using System.Text.Json; and using System.Text.Json.Serialization; for the JSON types. Keep the JsonSerializerDefaults.Web line. It makes the context read the camelCase names that most services send. JSON and generated metadata explains what goes wrong without it.

[JsonSourceGenerationOptions(JsonSerializerDefaults.Web)]
[JsonSerializable(typeof(Person))]
[JsonSerializable(typeof(string))]
[JsonSerializable(typeof(Person[]))]
[JsonSerializable(typeof(List<Person>))]
internal sealed partial class SampleJsonContext : JsonSerializerContext;

4. Reuse one HTTP client. Create the HTTP client when your app starts and reuse it for calls. Set its BaseAddress to the root of the API. The examples on these pages call this client httpClient.

HttpClient httpClient = new() { BaseAddress = new Uri("https://people.example") };

The runnable samples supply a local client that answers each request, so they run without a web server.

5. Create the implementation and call it. RestService.ForGenerated<T> uses the implementation that Refit generated during the build. Pass your context's Default instance as the second argument. This call asks for https://people.example/people/1. Add using Refit; to use Refit's types.

IPeopleApi api = RestService.ForGenerated<IPeopleApi>(httpClient, SampleJsonContext.Default);
Person person = await api.GetPersonAsync(1, cancellationToken);
Console.WriteLine(person.Name); // Ada

Pass the caller's CancellationToken so the request stops when a screen closes or the user cancels. Pass CancellationToken.None when nothing can cancel the call.

Pass settings instead of a context

RefitSettings holds the serializer and the other choices for a client, such as headers and error handling. You can build your own JsonSerializerOptions, wrap them in a serializer and pass the settings instead of the context. Pick this form when you have options to share, need full control, or want one options object elsewhere in your app. The short path above needs no options object. This form makes you assign the TypeInfoResolver yourself and keep the options unchanged after first use.

private static readonly JsonSerializerOptions JsonOptions = new(SampleJsonContext.Default.Options) { TypeInfoResolver = SampleJsonContext.Default };
RefitSettings settings = new(new SystemTextJsonContentSerializer(JsonOptions));
IPeopleApi withSettings = RestService.ForGenerated<IPeopleApi>(httpClient, settings);
Person fromSettings = await withSettings.GetPersonAsync(1, cancellationToken); // fromSettings == person

Create a client covers the settings form in detail.

Find a topic

PageWhat you can do
API referenceFind types, overloads, parameters and return values across all topics on one page.
Why use Refit?Compare an interface contract with a raw HTTP implementation.
Client creation and settingsCreate generated clients, configure settings and register clients with dependency injection.
Routes and HTTP methodsChoose a method, fill a route, and inspect a request before sending it.
Return typesChoose Task<T>, ValueTask<T>, IObservable<T> or a response wrapper.
Streaming repliesRead a JSON array, JSON Lines or server-sent events with IAsyncEnumerable<T>.
PaginationRead every item of a paged list, such as an S3, Azure or GitHub listing, with await foreach.
JSON and generated metadataRegister a JSON context, keep your serializer settings, pass metadata to a method and check missing registrations.
AOT and generated clientsGenerate request and JSON code for apps that compile ahead of time.
Testing clientsSupply local replies, inspect requests and check which routes were called.

Refit uses ReactiveUI.Primitives inside its runtime. Your API methods expose C# types such as ValueTask<T> and IObservable<T>. You can await a reply or use LINQ-style operators to shape it.

Run the examples

The documentation examples live in folders named for their topic. Each page links to its folder. They reference the Refit source projects, including the generator that creates the client implementation. Website blocks can show a focused subset of the complete example. Setup and runtime checks stay in the source project when the page does not need them.

From the Refit checkout's src folder, run:

dotnet run --project examples/Documentation/Documentation.csproj -c Release

The program supplies local HTTP replies and checks the documented results. Its Common/SampleHost.cs owns the HTTP client for the whole run. Its Program.cs calls each topic's example and disposes the host when the run ends.