Criando uma API .NET com Minimal Api (atualizado em 2025)
Em 2019, escrevi um artigo (Criando a primeira API com .NET Core. | by Marcio Nizzola | Medium) que teve em torno de 10.000 visualizações, mas que ficou obsoleto com o lançamento de novas features do C Sharp.
Na época, focamos em controllers tradicionais para construir APIs no .NET Core. Mas o ecossistema evoluiu rapidamente! Hoje, com o .NET 9 (e o quase-lançado .NET 10), a recomendação é usar Minimal APIs (saiba mais aqui O que são Minimal API´s no .NET 6? | by Marcio Nizzola | Medium) para projetos simples e leves. Elas reduzem o boilerplate, eliminam a necessidade de controllers e tornam o código mais conciso, sem sacrificar a funcionalidade.
Se você é novo no mundo das APIs (Application Programming Interface), lembre-se: uma API é uma ponte segura entre sistemas. Ela permite que apps desktop, web, mobile ou IoT interajam com sua aplicação sem expor diretamente o banco de dados, respeitando limitações de SO ou tecnologias.
Vamos criar nossa primeira API moderna usando .NET 9 ou 10 (preview). Usaremos o Visual Studio 2022 (ou o VS Code com CLI), Entity Framework Core para o banco de dados e faremos os para testes. No final, teremos uma API CRUD básica para gerenciar clientes.
Passo 1: Criando o Projeto
Abra o Visual Studio e clique em “Create a new project”. No menu esquerdo, selecione “.NET” e escolha “ASP.NET Core Web API”. Dê um nome ao projeto, como “FirstApiMinimal”, selecione a pasta de salvamento e clique em “Next”.
Na tela de configuração:
- Escolha “.NET 9.0 (Long Term Support)” como framework, caso queira se aventurar no Preview pode escolher .NET 10 preview também (até a publicação ainda não tinha sido lançado o .NET 10).
- Desmarque “Use controllers” (isso é chave para Minimal APIs!).
- Deixe “Enable OpenAPI support” por enquanto, caso ainda queira adicionar Swagger ele foi removido e terá que ser adicionado à parte como pacote Nuget.
- Você pode até desmarcar “Configure for HTTPS” para simplicidade local.
Clique em “Create”. O Visual Studio gerará o projeto com um Program.cs minimalista — o coração da nossa API.
Estrutura inicial:
- Program.cs: Onde configuramos serviços e endpoints.
- appsettings.json: Para configurações, como a string de conexão do banco.
Passo 2: Adicionando o Modelo e o Contexto de Dados
Crie pastas para organização: clique com o botão direito no projeto > Add > New Folder. Crie “Models” e “Data”.
Na pasta Models, adicione uma nova classe (Add > Class) chamada Customer.cs (será o nosso cliente) :
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace FirstMinimalApi.Models;
[Table("Customers")] // Anotação para nome da tabela (vamos usar isso depois)
public class Customer
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(50, ErrorMessage = "O nome deve ter no máximo 100 caracteres.")]
public string Name { get; set; } = string.Empty;
[Required]
[MaxLength(18, ErrorMessage = "O CPF deve ter no máximo 14 caracteres.")]
public string DocumentNumber { get; set; } = string.Empty;
[Required]
[EmailAddress(ErrorMessage = "O email fornecido não é válido.")]
public string Email { get; set; } = string.Empty;
[Required]
[DataType(DataType.Date)]
public DateTime BirthDate { get; set; }
public DateTime CreateDate { get; set; } = DateTime.Now;
}Aqui, usamos Data Annotations do .NET para validar campos:
- [Key]: Define o Id como chave primária.
- [Required] e [MaxLength]: Validações básicas.
- [Table(“Customers”)]: Garante que a tabela no banco se chame “Clientes” (padrão seria “Cliente”).
Passo 2: Limpar o program.cs
O template do .NET traz um exemplo de uma api mínima com uma simulação de previsão do tempo, limpe todo o program.cs deixando-o assim:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.UseHttpsRedirection();
app.Run();Na pasta Data, adicione uma classe AppDbContext.cs:
using Microsoft.EntityFrameworkCore;
using PrimeiraApiMinimal.Models;
namespace PrimeiraApiMinimal.Data;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<Cliente> Clientes { get; set; }
}Passo 3: Agora é que a mágica acontece
Vá até a janela “Solution Explorer” e com o botão direito clique sobre o nome do projeto, fazendo com que o menu flutuante apareça, escolha as opções: Add > New Scaffolded Item
Na janela que abre, podemos criar automaticamente, baseados numa classe através do processo de “Scaffolding” tudo que é necessário para fazer endpoints “Crud” automaticamente.
- Model Class : é a classe do modelo, no nosso caso “Customer”.
- Endpoint Class : é a classe que deverá ser criada para os endpoints, aperte o botão “+” para criar uma nova e especifique o nome.
- DbContext class: é a classe do contexto, é onde o Entity Framework irá configurar as entidades do banco de dados, e será utilizada para manipulá-lo.
- Database Provider: é o tipo de banco de dados que você irá utilizar.
Pronto, aperte o botão “Add” e veja a mágica acontecer ! Serão criados dois novos arquivos “AppDbContext.cs” que é a nossa classe do contexto, e “CustomerEndpoints.cs” que contém os endpoints criados, utilizando o conceito de “Minimal Api”.
Vamos ver então o que tem dentro da classe “CustomerEndpoints.cs”, nela estão os endpoints com os métodos Get, Post, Put e Delete, utilizando Entity Framework para persistir as informações no banco de dados !
Se você nunca ouviu falar de Minimal API, neste post entro em detalhe de cada implementação: https://marcionizzola.medium.com/o-que-s%C3%A3o-minimal-api-s-no-net-6-45e3d292acc9
using Microsoft.EntityFrameworkCore;
using FirstMinimalApi.Models;
using Microsoft.AspNetCore.Http.HttpResults;
namespace FirstMinimalApi;
public static class CustomerEndpoints
{
public static void MapCustomerEndpoints (this IEndpointRouteBuilder routes)
{
var group = routes.MapGroup("/api/Customer").WithTags(nameof(Customer));
group.MapGet("/", async (AppDbContext db) =>
{
return await db.Customer.ToListAsync();
})
.WithName("GetAllCustomers");
group.MapGet("/{id}", async Task<Results<Ok<Customer>, NotFound>> (int id, AppDbContext db) =>
{
return await db.Customer.AsNoTracking()
.FirstOrDefaultAsync(model => model.Id == id)
is Customer model
? TypedResults.Ok(model)
: TypedResults.NotFound();
})
.WithName("GetCustomerById");
group.MapPut("/{id}", async Task<Results<Ok, NotFound>> (int id, Customer customer, AppDbContext db) =>
{
var affected = await db.Customer
.Where(model => model.Id == id)
.ExecuteUpdateAsync(setters => setters
.SetProperty(m => m.Id, customer.Id)
.SetProperty(m => m.Name, customer.Name)
.SetProperty(m => m.DocumentNumber, customer.DocumentNumber)
.SetProperty(m => m.Email, customer.Email)
.SetProperty(m => m.BirthDate, customer.BirthDate)
.SetProperty(m => m.CreateDate, customer.CreateDate)
);
return affected == 1 ? TypedResults.Ok() : TypedResults.NotFound();
})
.WithName("UpdateCustomer");
group.MapPost("/", async (Customer customer, AppDbContext db) =>
{
db.Customer.Add(customer);
await db.SaveChangesAsync();
return TypedResults.Created($"/api/Customer/{customer.Id}",customer);
})
.WithName("CreateCustomer");
group.MapDelete("/{id}", async Task<Results<Ok, NotFound>> (int id, AppDbContext db) =>
{
var affected = await db.Customer
.Where(model => model.Id == id)
.ExecuteDeleteAsync();
return affected == 1 ? TypedResults.Ok() : TypedResults.NotFound();
})
.WithName("DeleteCustomer");
}
}Vamos agora ver o arquivo “AppDbContext.cs”, nele está montado o contexto do banco de dados:
using Microsoft.EntityFrameworkCore;
public class AppDbContext : DbContext
{
public AppDbContext (DbContextOptions<AppDbContext> options)
: base(options)
{
}
public DbSet<FirstMinimalApi.Models.Customer> Customer { get; set; } = default!;
}Esse é o DbContext do Entity Framework Core (EF Core). Ele mapeia nossa entidade Customer(Cliente) para o banco de dados.
Passo 3: Configurando o Banco de Dados com Code-First e Migrations
Instale o pacote do EF Core via NuGet:
- Clique com o botão direito no projeto > Manage NuGet Packages.
- Busque e instale: Microsoft.EntityFrameworkCore.Tools (para migrations).
Abra o appsettings.json e veja que foi adicionada já a string de conexão:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"AppDbContext": "Server=(localdb)\\mssqllocaldb;Database=AppDbContext-4c24acbd-b158-41f2-a324-133fb40f8d2b;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}Quando o Scaffolding foi feito, ele automaticamente incluiu novos comandos no “Program.cs”, ficando desta forma agora:
using Microsoft.EntityFrameworkCore;
using FirstMinimalApi;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("AppDbContext") ??
throw new InvalidOperationException("Connection string 'AppDbContext' not found.")));
// Add services to the container.
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.UseHttpsRedirection();
app.MapCustomerEndpoints();
app.Run();Agora, crie as migrations via Package Manager Console (Tools > NuGet Package Manager > Package Manager Console):
- execute o comando para criar a migração inicial: Add-Migration InitialCreate
- Script-Migration — Gera o SQL para revisão. Se quiser alterar o nome da tabela para “Clientes”, edite o arquivo na pasta Migrations (altere modelBuilder.Entity<Cliente>().ToTable(“Clientes”); se necessário).
- Update-Database — Aplica a migration e cria o banco.
Pronto! O banco PrimeiraApiDb foi criado no LocalDB.
Passo 4: Nem tudo é perfeito
Tem um detalhe no Scaffolding que foi feito, há um bug que eu vi, onde caso nós executemos o método “Put” que faz a alteração, ele considera atualizar o Id, mas o campo Id é chave primária, portanto não pode ser alterado, e vai dar um erro, sendo assim, remova ou comente a linha para funcionar corretamente como eu fiz abaixo.
Passo 5: Testando a API
Agora vamos testar? Para o teste vamos utilizar o arquivo “FirstMinimalApi.http” que já veio no nosso template, mas substitua-o pelo novo que foi adaptado aos novos endpoint:
@FirstMinimalApi_HostAddress = http://localhost:5226
### Get all customers
GET {{FirstMinimalApi_HostAddress}}/api/Customer
Accept: application/json
### Get customer by ID
GET {{FirstMinimalApi_HostAddress}}/api/Customer/1
Accept: application/json
### Create new customer
POST {{FirstMinimalApi_HostAddress}}/api/Customer
Content-Type: application/json
{
"name": "John Doe",
"documentNumber": "123.456.789-00",
"email": "john.doe@example.com",
"birthDate": "1990-01-01"
}
### Update customer
PUT {{FirstMinimalApi_HostAddress}}/api/Customer/1
Content-Type: application/json
{
"id": 1,
"name": "John Doe Updated",
"documentNumber": "123.456.789-00",
"email": "john.updated@example.com",
"birthDate": "1990-01-01",
"createDate": "2025-10-07T10:00:00"
}
### Delete customer
DELETE {{FirstMinimalApi_HostAddress}}/api/Customer/1Se nunca viu estes tipos de teste, veja meu post antigo: Esqueça o Postman, use o VSCode para testar API´S ! | by Marcio Nizzola | Medium neste o Visual Studio agora também suporta arquivos .http, proporcionando uma nova forma de testar api´s.
Com este código http, podemos agora testar, o Visual Studio permite que executemos as chamadas utilizando o arquivo .http, veja o exemplo abaixo
Podemos ver no lado esquerdo da imagem que há um comando “Send Request” abaixo de cada separador “###”, que se executado, irá chamar a api e exibir no lado direito o resultado. Neste exemplo foi clicado no método Get que resultou num código 200, indicando o sucesso !
Novidade: O .NET 10 tem validação nativa em Minimal ?
Sim, uma das melhorias implementadas na versão 10 é a validação de requisições, onde caso um campo obrigatório não for fornecido, ou um campo tiver um tamanho diferente da especificação, será feita uma validação pelo próprio endpoint.
Basta acrescentar a linha em destaque no program.cs:
Veja o exemplo abaixo onde retirei o campo “name” que é obrigatório, gerando um erro de validação:
Pronto, com esse exemplo você pode começar a criar suas api´s utilizando os conceitos de Minimal Api.
Há muito mais coisas que você pode fazer para melhorá-las, seguem alguns dos meus post´s !
Gostou do artigo? clique no ícone👏, compartilhe com os amigos e me siga para ver as próximas publicações !! Quer ver mais conteúdos, acesse minhas redes através do Linktree: https://linktree.com/nizzola
