.NET 6 — Minimal API

Roger Resende
#LocalizaLabs
Published in
5 min readJul 4, 2022

Quando trabalhamos com aplicações web necessitamos de recursos que na plataforma .NET estão associados às Web APIs que provêem a estrutura necessária para criação e utilização das mesmas. É comum utilizarmos essas estruturas para construções de microserviços e pequenas APIs com endpoints simplificados.

Seguindo outras linguagens de programação que vem ganhando força como Python e Node.js, com poucas linhas de código é possível ter uma aplicação recebendo e retornando informações. Visando também uma maior facilidade de entendimento do código, a Microsoft anunciou no dia 8 de novembro de 2021 o .NET 6 que combinado com novos recursos do C# como global using, instruções de nível superior e o novo recurso das Minimal APIs, permitem otimizar a experiência de inicialização do aplicativo e deixar o código melhor, mais rápido, mais simples e com várias melhorias de desempenho.

O que são Minimal APIs

São APIs minimalistas que reduzem a complexidade e ao mesmo tempo escaláveis, sendo permitido a inclusão de controllers, injeção de dependência, acesso a dados, entre outros quando necessário, que utilizam o mínimo de recursos possível para criação de aplicações web, ideal para microserviços e aplicações que necessitem do mínimo de dependências do ASP .NET Core e que com poucas linhas de código já é possível receber e retornar dados através de serviços HTTP.

Comparando um projeto Web API com Web Minimal API

Notem que no projeto minimal-api há apenas a classe program.cs ao contrário do projeto web-api que possui controllers, startup.cs e program.cs.

Criando um projeto

Este recurso só está disponível a partir do .NET 6 — preview 4, para utilizar o Visual Studio 2019 é recomendado a versão 16.11, você também pode utilizar o Visual Studio Code.

Para criar o projeto utilize os comandos a seguir em um terminal do VS Code:

dotnet new sln –n MinimalApidotnet new web -o minimal-apidotnet sln add minimal-api.csproj

Ou pelo Visual Studio crie um novo projeto ASP NET Core Empty, conforme imagem abaixo:

Depois de criado o projeto podemos observar a classe program.cs, bastando apenas 4 linhas de código para que tenhamos toda a configuração necessária para recebermos requisições.

var builder = WebApplication.CreateBuilder(args);var app = builder.Build();app.MapGet("/", () => "Hello World!");app.Run();

Instruções de nível superior

A partir do C# 9, mas totalmente consolidado no C# 10, não é mais necessário informar um método Main para um projeto do tipo Console Application e Minimal APIs, você pode fazer uso do recurso instruções de nível superior reduzindo a quantidade de código a ser escrito.

O próprio compilador gera uma entrada de classe e um método Main para o aplicativo, sendo permitido apenas um arquivo com essas instruções.

Global Usings

Outra novidade é uso de global usings, como podemos ver não há importação de using e também namespaces na classe program.cs, não há necessidade de se especificar explicitamente, bastando estar declarado em um dos arquivos da aplicação para que esteja disponível para todos os arquivos da mesma, reduzindo a redundância de usings e namespaces em todos os arquivos e deixando o código mais limpo.

Nós podemos adicionar ao projeto outros usings de forma global através do arquivo.csproj:

<Using Include="System.Teste" />

Diretiva implícita de using

Para aplicações Console application e Minimal APIs, o próprio compilador adiciona automaticamente as seguintes diretivas:

  • using System;
  • using System.IO;
  • using System.Collections.Generic;
  • using System.Linq;
  • using System.Net.Http;
  • using System.Threading;
  • using System.Threading.Tasks;

Você pode desabilitar essa função através da opção Implicit usings no seu arquivo.csproj

<ImplicitUsings>disable</ImplicitUsings>

Você também pode remover um using específico, nesse caso a opção Implicit usings está habilitada e um using específico é removido.

<ImplicitUsings>enable</ImplicitUsings>
<ItemGroup>
<Using Remove="System.Collections" />
</ItemGroup>

Trabalhando com dados utilizando EntityFrameworkCore

Primeiro devemos adicionar os pacotes EntityFrameworkCore e EntityFrameworkCore.InMemory, nesse caso irei utilizar o armazenamento de dados em memória.

dotnet add package Microsoft.EntityFrameworkCoredotnet add package Microsoft.EntityFrameworkCore.InMemory

Para podermos manipular os dados vamos criar uma classe representando a entidade cidade:

public class Cidade
{
public int Id { get; set; }
public string Nome { get; set; }
}

Com a entidade criada podemos criar a nossa classe de contexto que deriva de DbContext e que representará uma sessão do nosso banco de dados:

public class Contexto : DbContext
{
public Contexto(DbContextOptions options) : base(options)
{ }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Cidade>().HasKey(cidade => cidade.Id);
}
public DbSet<Cidade> Cidades { get; set; }
}

Agora basta adicionar nosso contexto ao serviço. Aqui podemos ver outro recurso que pode ser implementado em minimal APIs, à injeção de dependência:

//Injetando a dependência de dbcontext e sinalizando que vou utilizar InMemoryDabasebuilder.Services.AddDbContext<Contexto>(options => options.UseInMemoryDatabase("Cidades"));

Criando os serviços que farão a manipulação dos dados da nossa API através das rotas Post/Put/Get/Delete.

app.MapGet("/cidades", async (Contexto dbContext) => await dbContext.Cidades.ToListAsync());app.MapGet("/cidades/{id}", async (int id, Contexto dbContext) => await dbContext.Cidades.FirstOrDefaultAsync(cidade => cidade.Id == id));app.MapPost("/cidades", async (Cidade cidade, Contexto dbContext) =>{
if (cidade != null)
{
dbContext.Cidades.Add(cidade);
await dbContext.SaveChangesAsync();
}
return cidade;
});
app.MapPut("/cidades/{id}", async (int id, Cidade cidade, Contexto dbContext) =>
{
var cidadeAtual = await dbContext.Cidades.FirstOrDefaultAsync(c => c.Id == id);
if (cidadeAtual != null && cidadeAtual.Id == cidade.Id)
{
dbContext.Entry(cidade).State = EntityState.Modified;
await dbContext.SaveChangesAsync();
return cidade;
}
return null;
});
app.MapDelete("/cidades/{id}", async (int id, Contexto dbContext) =>{
var cidade = await dbContext.Cidades.FirstOrDefaultAsync(c => c.Id == id);
if (cidade != null)
{
dbContext.Cidades.Remove(cidade);
await dbContext.SaveChangesAsync();
}
return;
});

Pronto! Já temos nossa API funcionando com poucas linhas de código de uma forma muito simples.

Documentando nossa API com Swagger

Primeiro passo é adicionar o pacote Swashbuckle ao nosso projeto:

dotnet add package Swashbuckle.AspNetCore

Feito isso o próximo passo é configurar e ativar o uso do swagger na aplicação:

//Adicionando Swagger para documentação da API
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();if(app.Environment.IsDevelopment())
{
//Ativando o swagger
app.UseSwagger();
app.UseSwaggerUI();
}

Executando o projeto novamente já podemos ver a nossa API documentada.

Conclusão

Assim como em qualquer novidade, este recurso deve ser usado observando sempre a real necessidade da aplicação. O fato é que com poucas linhas de código foi possível termos uma API funcional com acesso a dados e documentada. Podendo, ainda, ser evoluída de acordo com a necessidade do projeto, seja adicionando controllers, mensageria, dentre outros.

Disponibilizei um repositório no GitHub com o projeto utilizado neste artigo, então fiquem à vontade para consultá-lo e vê-lo em ação.

Referências:

--

--