Recentemente, tive a honra de contribuir com o projeto open-source Microsoft/FeatureManagement-Dotnet, uma biblioteca consolidada que facilita o uso de feature flags no ecossistema .NET. Minha implementação adicionou suporte nativo para Minimal APIs no ASP.NET Core, oferecendo uma maneira prática de integrar controle dinâmico de funcionalidades. Neste artigo, vou explorar essa nova funcionalidade que desenvolvi, abordando desde os conceitos básicos até cenários avançados, com exemplos práticos e sugestões de como aplicá-la em projetos reais.
O Papel das Feature Flags no desenvolvimento moderno
Feature flags, ou bandeiras de funcionalidade, são um recurso fundamental no desenvolvimento de software atual. Elas permitem ativar ou desativar funcionalidades em tempo de execução, sem necessidade de alterar o código ou realizar um novo deploy. Isso é especialmente útil em casos como:
- Lançamentos Progressivos (Rollouts): Implementar novidades gradualmente para subgrupos de usuários, reduzindo riscos.
- Testes A/B: Comparar diferentes versões de uma funcionalidade para otimizar resultados.
- Controle de Acesso: Restringir funcionalidades a usuários ou grupos específicos com base em regras dinâmicas.
- Gerenciamento de Experimentos: Testar novas ideias sem impactar a estabilidade do sistema.
O Microsoft.FeatureManagement já oferecia suporte robusto para feature flags em controladores tradicionais do ASP.NET Core. Com a introdução das Minimal APIs no .NET 6 — um modelo leve e eficiente para construção de APIs —, surgiu a necessidade de adaptar essa capacidade. Minha contribuição resolve essa demanda, integrando feature flags diretamente ao pipeline de roteamento das Minimal APIs.
Introduzindo o WithFeatureGate
A base da minha implementação é a extensão WithFeatureGate, um método projetado para ser simples e intuitivo, condicionando a execução de endpoints ao estado de feature flags. Se as condições não forem atendidas, o endpoint retorna um status HTTP 404 (Not Found) automaticamente, sem executar o código associado.
Um exemplo básico
Veja como funciona na prática:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddFeatureManagement();
var app = builder.Build();
app.MapGet("/test", () => "Funcionalidade Habilitada")
.WithFeatureGate("TestFeature");
app.Run();
Nesse caso, o endpoint /test só é acessível se a feature flag TestFeature estiver ativada. A configuração pode ser definida no appsettings.json, como:
{
"FeatureManagement": {
"TestFeature": true
}
}
Se TestFeature estiver como false, uma requisição GET para /test retorna 404, sem processamento adicional. Essa integração reflete a simplicidade das Minimal APIs, ao mesmo tempo que oferece flexibilidade significativa.
Recursos avançados da implementação
O WithFeatureGate vai além de cenários básicos. Ele foi projetado para suportar casos de uso mais complexos, proporcionando controle detalhado sobre o comportamento dos endpoints. A seguir, apresento algumas das principais possibilidades:
1. Controle com múltiplas features
Para exigir que várias feature flags estejam ativas simultaneamente, basta listar os nomes:
app.MapGet("/test-multiple", () => "Múltiplas Funcionalidades Habilitadas")
.WithFeatureGate("Feature1", "Feature2");
O endpoint /test-multiple só retorna 200 OK se tanto Feature1 quanto Feature2 estiverem ativadas. Caso uma delas esteja desativada, o resultado é 404. Isso é útil para funcionalidades que dependem de múltiplos componentes.
2. Requisito "Any": Flexibilidade com opções
Quando o objetivo é liberar o endpoint com pelo menos uma feature ativa, usa-se o RequirementType.Any:
app.MapGet("/test-any", () => "Qualquer Funcionalidade Habilitada")
.WithFeatureGate(RequirementType.Any, "Feature1", "Feature2");
Aqui, o endpoint responde com sucesso se Feature1 ou Feature2 (ou ambas) estiverem ativas. Essa opção é ideal para cenários com caminhos alternativos de ativação.
3. Negação: Lógica invertida
É possível configurar o endpoint para ser acessível apenas quando uma feature está desativada:
app.MapGet("/test-negated", () => "Funcionalidade Negada")
.WithFeatureGate(true, "TestFeature");
Nesse exemplo, /test-negated só funciona se TestFeature for false. Essa funcionalidade permite criar lógicas invertidas ou experiências alternativas.
4. Grupos de Endpoints com MapGroup
Para aplicar uma feature flag a um conjunto de endpoints, o método MapGroup é uma solução prática:
var group = app.MapGroup("/api")
.WithFeatureGate("GroupFeature");
group.MapGet("/endpoint1", () => "Endpoint 1");
group.MapGet("/endpoint2", () => "Endpoint 2");
Se GroupFeature estiver desativada, todos os endpoints sob /api — como /api/endpoint1 e /api/endpoint2 — retornam 404. Essa abordagem facilita o gerenciamento de seções completas de uma API.
5. Targeting: Controle por audiência
O Microsoft.FeatureManagement oferece suporte ao TargetingFilter, um recurso que permite direcionar funcionalidades a usuários ou grupos específicos com base em configurações detalhadas. Isso é especialmente útil para cenários de personalização ou lançamentos segmentados. Veja como implementei um exemplo prático:
Primeiro, é necessário registrar o filtro e configurar um ITargetingContextAccessor no contêiner de serviços. Aqui está uma implementação que identifica o usuário e os grupos a partir do contexto HTTP:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddFeatureManagement()
.AddFeatureFilter<TargetingFilter>();
builder.Services.AddSingleton<ITargetingContextAccessor, CustomTargetingContextAccessor>();
var app = builder.Build();
app.MapGet("/premium-feature", () => "Bem-vindo à funcionalidade Premium!")
.WithFeatureGate("PremiumFeature");
app.Run();
// Implementação do ITargetingContextAccessor
public class CustomTargetingContextAccessor : ITargetingContextAccessor
{
private readonly IHttpContextAccessor _httpContextAccessor;
public CustomTargetingContextAccessor(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public ValueTask<TargetingContext> GetContextAsync()
{
var context = _httpContextAccessor.HttpContext;
var userId = context?.User?.Identity?.Name ?? "anonymous";
var groups = context?.User?.Claims
.Where(c => c.Type == "group")
.Select(c => c.Value)
.ToArray() ?? Array.Empty<string>();
return new ValueTask<TargetingContext>(new TargetingContext
{
UserId = userId,
Groups = groups
});
}
}
Nesse exemplo, o CustomTargetingContextAccessor usa o IHttpContextAccessor para extrair o nome do usuário autenticado (via Identity.Name) e os grupos associados (via claims personalizados do tipo "group"). Isso assume que a autenticação está configurada, como com JWT ou cookies, e que os grupos são incluídos como claims no token.
A configuração no appsettings.json define quem tem acesso à funcionalidade:
{
"FeatureManagement": {
"PremiumFeature": {
"EnabledFor": [
{
"Name": "Targeting",
"Parameters": {
"Audience": {
"Users": ["thaise.medeiros"],
"Groups": [
{
"Name": "PremiumUsers",
"RolloutPercentage": 100
}
]
}
}
}
]
}
}
}
Aqui, o endpoint /premium-feature só estará disponível para a usuária "thaise.medeiros" ou para membros do grupo "PremiumUsers". O campo RolloutPercentage define que 100% dos membros do grupo têm acesso, mas esse valor pode ser ajustado para lançamentos graduais — por exemplo, 50% para atingir metade do grupo.
O ITargetingContextAccessor é a chave para conectar a configuração às requisições reais. Ele fornece o contexto do usuário atual, permitindo que o TargetingFilter avalie se o acesso deve ser concedido. Combinado com autenticação (como JWT), isso cria uma forma robusta e flexível de personalizar funcionalidades para audiências específicas.
Por que Feature Flags fazem sentido em Minimal APIs
As Minimal APIs foram criadas para simplicidade e desempenho, eliminando a complexidade de controladores e metadados desnecessários. Integrar feature flags ao roteamento mantém essa abordagem enxuta, adicionando controle dinâmico essencial para aplicações modernas. Isso se destaca em:
- Microsserviços: Gerenciar funcionalidades distribuídas fica mais simples.
- Entrega Contínua: Permite implantar código com segurança e ativar recursos sob demanda.
- Experiência do Usuário: Facilita personalizar a API para diferentes perfis ou testes.
A combinação de Minimal APIs com WithFeatureGate oferece um modelo direto de desenvolvimento aliado a uma ferramenta robusta para evolução de software.
Como a funcionalidade foi implementada
Desenvolver o suporte a feature flags para Minimal APIs foi um processo que exigiu alinhar a flexibilidade do FeatureManagement com a simplicidade das Minimal APIs. A solução que se encaixasse naturalmente no pipeline de roteamento, aproveitando os filtros de endpoint do ASP.NET Core para avaliar as feature flags em tempo de execução.
A implementação gira em torno de um filtro que verifica o estado das flags antes de liberar ou bloquear o acesso aos endpoints. Esse filtro é integrado ao sistema de construção de endpoints das Minimal APIs por meio de extensões que tornam seu uso fluido e intuitivo. Um dos desafios foi garantir que ele suportasse diferentes configurações — como múltiplas flags, lógica de "todas ativas" ou "pelo menos uma ativa", e até negação
Outro ponto importante foi integrar o filtro com recursos avançados, como o targeting, que depende de um mecanismo para identificar o contexto do usuário atual. Isso foi resolvido usando a infraestrutura existente do FeatureManagement, garantindo compatibilidade com filtros como o TargetingFilter.
O resultado é uma solução que estende as capacidades do FeatureManagement às Minimal APIs, equilibrando potência e simplicidade de forma que os desenvolvedores possam adotá-la facilmente em seus projetos.
Conclusão
Adicionar suporte a feature flags em Minimal APIs com o Microsoft.FeatureManagement foi uma contribuição significativa para a comunidade .NET. Com o WithFeatureGate, é possível implementar desde controles básicos até configurações avançadas como targeting e agrupamento, tudo de forma prática e eficiente. Seja para lançar uma nova funcionalidade, conduzir testes ou personalizar experiências, essa implementação entrega as ferramentas necessárias de maneira elegante.
A funcionalidade já está disponível no repositório Microsoft/FeatureManagement-Dotnet, embora ainda não tenha sido incluída em uma release oficial. Você pode explorá-la agora mesmo em seus projetos e conferir como feature flags podem aprimorar o desenvolvimento e a entrega de software — mas em breve ela será lançada!
Top comments (0)