Refit no dia a dia: Mais produtividade e menos código em integrações REST

Refit no dia a dia: Mais produtividade e menos código em integrações REST

Veja como reduzir drasticamente o código repetitivo ao consumir APIs REST no .NET e como o Refit pode acelerar seu desenvolvimento sem perder controle.

O que é o Refit?

O Refit é uma biblioteca para .NET que transforma as suas chamadas HTTP em interfaces fortemente tipadas, utilizando atributos para mapear endpoints REST. Ele basicamente elimina a necessidade de escrever e reescrever código manual com HttpClient, substituindo por uma abordagem declarativa.

A ideia central é bem simples:

Você define uma interface → o Refit gera a implementação automaticamente → você consome como se fosse um serviço local qualquer.

Ele segue basicamente o mesmo conceito de ferramentas como Retrofit (Java/Kotlin), trazendo esse padrão bem estruturado para o nosso maravilhoso ecossistema .NET.

Quais são os problemas que o Refit resolve

Quem trabalha com integração HTTP no .NET já passou por isso e sabe do que eu to falando:

  • Código extremamente repetitivo com HttpClient
  • Serialização manual
  • Controle de headers espalhado
  • Tratamento de erros inconsistente e descentralizados
  • Difícil manutenção conforme a medida que a API cresce

Exemplo clássico de uma requisição sem o uso de Refit:

var client = new HttpClient();
var response = await client.GetAsync("https://api.exemplo.com/users/1");

if (!response.IsSuccessStatusCode)
    throw new Exception("Erro");

var json = await response.Content.ReadAsStringAsync();
var user = JsonSerializer.Deserialize<User>(json);

Isso se repete em toda a aplicação e vira dívida técnica rápido.

O Refit resolve isso abstraindo completamente esse boilerplate.

Instalação

O processo de instalação geralmente é ben simples, pode ser feito utilizando os comandos .Net abaixo ou via instalador de pacotes.

dotnet add package Refit
dotnet add package Refit.HttpClientFactory

Se quiser usar Newtonsoft(Recomendo):

dotnet add package Refit.Newtonsoft.Json

Como o Refit funciona internamente

O Refit usa:

  • Reflection + geração dinâmica de proxy
  • HttpClient por baixo dos panos
  • Serialização (System.Text.Json ou Newtonsoft)

Quando você define:

public interface IUserApi
{
    [Get("/users/{id}")]
    Task<User> GetUser(int id);
}

O Refit:

  1. Interpreta o atributo [Get]
  2. Monta a URL
  3. Executa a chamada HTTP
  4. Desserializa o retorno
  5. Retorna o objeto tipado

Tudo isso sem você escrever nenhuma lógica HTTP, maneiro né não?

Principais vantagens

1. Redução massiva de boilerplate

Você elimina código repetitivo de:

  • Criação de request
  • Leitura de response
  • Serialização/desserialização de objetos

2. Código mais legível e expressivo

Interfaces ficam autoexplicativas:

Task<List<Order>> GetOrdersByCustomer(int customerId);

Muito mais claro do que navegar por múltiplos métodos HTTP.

3. Fortemente tipado

  • Menos erros em runtime
  • Melhor IntelliSense
  • Facilita refactor

4. Integração nativa com DI

Funciona perfeitamente com HttpClientFactory:

services.AddRefitClient<IUserApi>()
        .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://api.exemplo.com"));

5. Suporte a autenticação e headers

Você pode definir headers direto na interface:

[Headers("Authorization: Bearer")]

Ou dinamicamente via DelegatingHandler.

6. Testabilidade

Como você depende de interface, fica trivial mockar:

var mock = new Mock<IUserApi>();

Melhores cerários para uso do refit

1. Integração com APIs externas

  • ERPs
  • Gateways de pagamento
  • APIs de terceiros

2. Microservices

Comunicação entre serviços internos:

  • Padronização
  • Redução de código repetido
  • Melhor organização

3. Aplicações com muitas integrações HTTP

Se seu projeto consome várias APIs, o ganho é enorme.

4. Sistemas com foco em produtividade

Equipes que precisam evoluir rápido se beneficiam muito.

Comparação com abordagens tradicionais

Refit vs HttpClient puro

Critério	   HttpClient	Refit
Verbosidade	   Alta	        Baixa
Tipagem	       Manual	    Forte
Manutenção	   Difícil	    Fácil
Reuso	       Limitado	    Alto
Testabilidade  Média	    Alta

Refit vs RestSharp

Critério	   RestSharp	Refit
Estilo	       Imperativo	Declarativo
Tipagem	       Média	    Alta
Integração DI  Limitada	    Nativa
Legibilidade   Média	    Alta

Refit vs HttpClient + Typed Clients

Typed Clients já melhoram bastante:

public class UserClient
{
    private readonly HttpClient _http;

    public UserClient(HttpClient http)
    {
        _http = http;
    }

    public async Task<User> GetUser(int id)
    {
        var response = await _http.GetAsync($"/users/{id}");
        ...
    }
}

Mas ainda exige código manual e o Refit elimina isso completamente.

Umas dicas de quando NÃO usar Refit

1. APIs muito dinâmicas

Se:

  • Endpoints mudam em runtime
  • Rotas são montadas dinamicamente

Refit não se adapta bem, encontra certa dificuldade em interpretação.

2. Controle avançado de HTTP

Se você precisa:

  • Manipular request/response em baixo nível
  • Trabalhar com streaming complexo
  • Controlar pipeline HTTP manualmente

Melhor usar HttpClient direto.

3. Performance extrema (edge cases)

O Refit adiciona uma pequena camada de abstração.

Em sistemas ultra críticos (ex: alta frequência), pode ser melhor ir direto no HttpClient.

4. APIs não RESTful

Se a API não segue padrão REST, o ganho diminui.

Erros comuns de quem usa Refit

1. Ignorar tratamento de erro

Refit lança exceções como:

ApiException

Muita gente não trata corretamente a exceções geradas:

try
{
    await api.GetUser(1);
}
catch (ApiException ex)
{
    // tratar status code
}

2. Não configurar HttpClientFactory

Usar:

RestService.For<IUserApi>("url");

em produção é erro.

A forma ideal de se usar é:

AddRefitClient

Porque:

  • Assim voce reaproveita conexões
  • Evita socket exhaustion

3. Misturar responsabilidades

Colocar lógica de negócio na interface:

errado:

Task<User> GetUserWithBusinessRule(int id);

Refit deve ser utilizado apenas para o transporte HTTP.

4. Não versionar contratos

Mudanças na API quebram facilmente o cliente.

Uma boa prática:

  • Versionar interfaces (IUserApiV1, IUserApiV2)

5. Ignorar logging

Refit sozinho não loga nada.

Você deve usar:

  • DelegatingHandler
  • Serilog / middleware

Exemplo prático completo

Vamos montar um cenário real: Com consumo de API de pedidos.

Antes de iniciarmos, certifique-se de ter instalado os pacotes descritos no inicio desse artigo:

  • Refit
  • Refit.HttpClientFactory

1. Criar o projeto

dotnet new web -n RefitMinimalApiDemo
cd RefitMinimalApiDemo

Esse template já vem com Minimal API pronto.

2. Instalar dependências

dotnet add package Refit
dotnet add package Refit.HttpClientFactory

(opcional, se quiser custom serializer)

dotnet add package Refit.Newtonsoft.Json
dotnet add package Refit.Newtonsoft.Json

3. Criar a estrutura básica

Crie essas pastas para se obter uma organização simples e limpa:

/Models
/Apis
/Services

4. Criar o Model

public class Order
{
    public int Id { get; set; }
    public string Customer { get; set; }
    public decimal Total { get; set; }
}

5. Criar a Interface Refit

using Refit;

public interface IOrderApi
{
    [Get("/orders")]
    Task<List<Order>> GetOrders();

    [Get("/orders/{id}")]
    Task<Order> GetOrderById(int id);

    [Post("/orders")]
    Task<Order> CreateOrder([Body] Order order);
}

6. Configurar o Refit no Program.cs

using Refit;

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddRefitClient<IOrderApi>()
    .ConfigureHttpClient(c =>
    {
        c.BaseAddress = new Uri("https://localhost:5001"); // vamos simular API local
    });

var app = builder.Build();

7. Criar uma API fake para simulação local

Como você precisa testar, vamos criar endpoints no próprio projeto simulando uma API externa.

Adicione isso antes do app.Run():

var orders = new List<Order>
{
    new Order { Id = 1, Customer = "Cliente A", Total = 100 },
    new Order { Id = 2, Customer = "Cliente B", Total = 200 }
};

app.MapGet("/orders", () => orders);

app.MapGet("/orders/{id}", (int id) =>
{
    var order = orders.FirstOrDefault(o => o.Id == id);
    return order is not null ? Results.Ok(order) : Results.NotFound();
});

app.MapPost("/orders", (Order order) =>
{
    order.Id = orders.Count + 1;
    orders.Add(order);
    return Results.Ok(order);
});

8. Criar um Service

/Services/OrderService.cs

public class OrderService
{
    private readonly IOrderApi _api;

    public OrderService(IOrderApi api)
    {
        _api = api;
    }

    public Task<List<Order>> GetAll()
        => _api.GetOrders();

    public Task<Order> Create(Order order)
        => _api.CreateOrder(order);
}

Registre o serviço no DI:

builder.Services.AddScoped<OrderService>();

9. Expor endpoints usando Refit para consumir a própria API

Agora o mais interessante: você vai consumir sua própria API via Refit.

Adicione:

app.MapGet("/client/orders", async (IOrderApi api) =>
{
    return await api.GetOrders();
});

app.MapGet("/client/orders/{id}", async (IOrderApi api, int id) =>
{
    return await api.GetOrderById(id);
});

app.MapPost("/client/orders", async (IOrderApi api, Order order) =>
{
    return await api.CreateOrder(order);
});

10. Rodar o projeto

dotnet run

11. Testar na prática

Endpoints "API real"

  • GET /orders
  • GET /orders/1
  • POST /orders

Endpoints via Refit (cliente)

  • GET /client/orders
  • GET /client/orders/1
  • POST /client/orders

Resultado final

/Orders
/Orders/1

Se você chegou até aqui e seguiu todos os passos, agora você vai ter:

  • Uma API simulada (/orders)
  • Um cliente Refit consumindo ela (/client/orders)
  • Tudo no mesmo projeto (ambiente controlado)

Conclusão técnica

Refit é uma ferramenta extremamente poderosa quando usada no contexto certo:

  • Ele não substitui o HttpClient → ele abstrai
  • Ele não resolve tudo → mas resolve 80% dos cenários REST com elegância

O maior ganho não é só reduzir código, é:

padronizar comunicação HTTP na aplicação

Se você trabalha com múltiplas integrações (ERP, gateways, microservices), o Refit praticamente se paga sozinho em manutenção.

Mas como toda abstração:

  • Use com critério
  • Não force em cenários onde não encaixa
  • Combine com boas práticas (DI, logging, retry, versionamento)

Código-fonte do projeto

Para facilitar o entendimento, disponibilizei o projeto completo com o exemplo de Refity, já organizado com separação de responsabilidades e boas práticas:

👉 Baixar o projeto no GitHub neste link:

Quer ver mais conteúdos como este?

Se você trabalha com .NET, C# e backend, este blog seguirá trazendo conteúdos práticos e objetivos sobre o ecossistema Microsoft, com foco em código, boas práticas e decisões técnicas aplicadas ao mundo real.

Acompanhe para continuar aprofundando seu domínio sobre a plataforma .NET.

Confira mais:

Fique por dentro das novidades

Assine nossa newsletter e receba as últimas atualizações e artigos diretamente em seu email.

Assinar gratuitamente