Library: Refit

Simplify Your API Calls

Published on Sunday, July 23, 2023

Microsoft has made many improvements in WebAPI regarding boiler code for REST APIs. The minimal API is a great way to speed up and remove the tedious process of creating controllers, and in combination with MediatR great way to make most of them into one-liners.

However, we still have a problem connecting to APIs from C#. Even if we use the library RestSharp, it is far from the elegance of MinimalAPI/MediatR. Refit library tries to minimize boiler code by automating much of the process of creating a REST client.

What is Refit?

Refit is a popular library that serves as a type-safe HTTP client for .NET. It's built on top of HttpClient and provides a more straightforward and organized way to interact with RESTful APIs. With Refit, you can define your API endpoints as C# interface methods and automatically handle the HTTP communication under the hood.

Getting Started with Refit

To begin using Refit in your C# project, add a single package:

dotnet add package Refit

Defining the API Interface

Once you've installed the Refit package, you must define the API interface. Basically, you need to map REST API to single (or more) interfaces, where you would define API RESTful Verbs and Url - [Get("/people/{id}")] and input and output (for deserialization) parameters with method Task<Person> UpdatePerson(Guid id, [Body] Person person);.

Basic CRUD operations with Refit.

[Headers("Content-Type: application/json")]
public interface IPeopleApi
{
    [Get("/people/{id}")]
    Task<Person> GetPerson(Guid id);

    [Get("/people")]
    Task<List<Person>> GetAllPeople();

    [Post("/people")]
    Task<Person> CreatePerson([Body] Person person);

    [Put("/people/{id}")]
    Task<Person> UpdatePerson(Guid id, [Body] Person person);

    [Delete("/people/{id}")]
    Task DeletePerson(Guid id);
}

Minimal API with MediatR for the server side:

var builder = WebApplication.CreateBuilder(args);

// Add MediatR
builder.Services.AddMediatR(typeof(Program).Assembly);

var app = builder.Build();

app.MapGet("/people/{id}", async (IRequestHandler<GetPersonQuery, Person> handler, Guid id) =>
    await handler.Handle(new GetPersonQuery(id), default));

app.MapGet("/people", async (IRequestHandler<GetAllPeopleQuery, IEnumerable<Person>> handler) =>
    await handler.Handle(new GetAllPeopleQuery(), default));

app.MapPost("/people/{name}", async (IRequestHandler<CreatePersonCommand, Person> handler, string name) =>
    await handler.Handle(new CreatePersonCommand(name), default));

app.MapPut("/people/{id}/{name}", async (IRequestHandler<UpdatePersonCommand, Person> handler, Guid id, string name) =>
    await handler.Handle(new UpdatePersonCommand(id, name), default));

app.MapDelete("/people/{id}", async (IRequestHandler<DeletePersonCommand> handler, Guid id) =>
{
    await handler.Handle(new DeletePersonCommand(id), default);
    return Results.Ok();
});

app.Run();

Of course, this is the most basic example. Check Refit Documentation for details for request headers, authentication, various body contents, multipart uploads, etc.

Creating the Refit Client

The only thing left to do is to create Refit Client. The most basic way to do it is directly without Dependency Injection.

var httpClient = new HttpClient { BaseAddress = new Uri("https://api.example.com") };
var peopleAPI = RestService.For<IPeopleApi>(httpClient);
var people = await peopleAPI.GetAllPeople();

In the code above, we create an instance of HttpClient with the base URL of the API. Then, we delegate the creation of the peopleAPI instance to RestService.For<IPeopleApi>(httpClient). With that done, we can call await peopleAPI.GetAllPeople().

Handling API Responses

Refit automatically handles the deserialization of the API response into the specified data model (in this case, the List<Person>).

Handling Errors

The Refit also simplifies error handling by automatically throwing exceptions for non-successful HTTP responses. For example, if the API returns a 404 Not Found or 500 Internal Server Error, Refit throws appropriate exceptions you can catch and handle in your code.

Conclusion

Refit is an elegant library for simplifying API calls in C#. Refit can convert your API service interfaces into easy-to-use C# interfaces, making your code cleaner, more organized, and less error-prone. With automatic deserialization and error handling, Refit speeds up development significantly. Even if you cannot handle more complex unsupported use cases or maybe custom implementations (?), you can still use Refit and your custom implementation in parallel.