Minimal API .NET: o que é isso?

Minimal API .NET: o que é isso?

Imagine conseguir escrever o mínimo necessário para ter uma Web API inteira, com recursos de acesso a dados e documentada com Swagger. Será que isso é possível? Neste artigo falaremos das Minimal APIs, um novo recurso apresentado oficialmente à comunidade de desenvolvedores junto ao .NET 6.0 e que nos permite esse tipo de simplificação.

Quando estamos criando um serviço web usando a plataforma .NET, muito provavelmente usaremos os recursos das Web APIs dentre as opções disponíveis, porque elas já estruturam um backend para desenvolvermos usando C#. Apesar da estrutura de um projeto deste tipo ter evoluído com o passar do tempo, ainda ficamos dependentes de muitos recursos e configurações.

E aí vamos conferir como as Minimal APIs realmente funcionam ? 😉

O que é uma Minimal API?

Com a chegada do .NET 6, a Microsoft disponibilizou o recurso das Minimal APIs, que foram pensadas para permitir a criação de APIs HTTP que utilizem menos recursos, sendo uma ótima solução para implementação de microsserviços e aplicativos que consumam o mínimo de dependências do ASP .NET Core, por exemplo.

Então, que tal criar uma API de cadastro de pessoas escrevendo o mínimo de linhas de código o possível? Para isso teremos uma lista em memória e como pré-requisitos, usaremos o NET 6 e o Visual Studio Community 2022, mas fique a vontade para usar outra IDE que seja de sua escolha como o VS Code por exemplo.

Na imagem vemos a tela do Visual Studio Installer, destacando a opção ASP.NET and web development.

Com o Visual Studio Community 2022 aberto, crie um novo projeto ASP.NET Core vazio, como na imagem abaixo:

Na imagem vemos a tela do Visual Studio 2022 destacando a opção de
projeto  ASP.NET  Core Vazio.

Ah, vamos definir também um nome para nosso projeto, que será “Alura.MinimalAPI”.

Na imagem vemos a tela do Visual Studio 2022, com a opção do nome do projeto destacada.

E sem esquecer de selecionar a versão 6.0 do .NET Core.

Na imagem vemos a tela do Visual Studio 2022, com  a opção do framework .NET 6.0 destacada.

Repare na estrutura do projeto criado:

Na imagem vemos a tela do Visual Studio 2022, com a opção do gerenciador de soluções destacado.

Dessa forma, já temos uma API funcional. Agora execute o projeto clicando no botão ”Run” no menu superior do Visual Studio Community. No navegador padrão será exibida a página principal encontrada em “localhost:7274” e será exibida a mensagem “Hello World”.

Bem bacana! 😉 Mas queremos desenvolver mais do que um “Hello world”, certo? Vamos criar uma solução que funcione em memória, uma lista de pessoas, e realizar as operações de inserção, atualização, remoção e listagem.

Em nosso projeto de exemplo adicionamos um diretório Model e vamos criar as classes Pessoa e RepositorioDePessoas.

O código de Pessoa será o seguinte:

namespace Alura.MinimalAPI.Alura.MinimalAPI.Model
{
    public class Pessoa
    {
        public Pessoa()
        {
               Identificador = Guid.NewGuid();
        }
        public Guid Identificador { get; set; }
        public string Nome { get; set; } = string.Empty;
        public string CPF { get; set; } = string.Empty;
        public string Email { get; set; } = string.Empty;
    }
}

Com base nesta classe, criamos uma outra com algumas funcionalidades para manipular uma lista de pessoas em memória, a RepositorioDePessoa. Vamos usar este recurso para simular uma base de dados. O código dela será:

namespace Alura.MinimalAPI.Alura.MinimalAPI.Model
{
    public class RepositorioDePessoas
    {   
        public RepositorioDePessoas(bool dados)
        {
            if (dados)
            {
                CriarDadosEmMemoria();
            }
            else
            {
                ListaPessoas = new List<Pessoa>();
            }
        }

        private void CriarDadosEmMemoria()
        {

            this.ListaPessoas = new List<Pessoa>()
            {
                new Pessoa()
                {
                    Nome = "André Silva",
                    CPF = "123456789-12",
                    Email ="[email protected]"
                },
                new Pessoa()
                {
                    Nome = "Pedro Malazartes",
                    CPF = "182993692-12",                    
                    Email ="[email protected]"
                },
                new Pessoa()
                {
                    Nome = "Maria Joaquina",
                    CPF = "987351984-12",                    
                    Email ="[email protected]"
                }
            };
        }

        public List<Pessoa> ListaPessoas { get; set; }

        public Pessoa AdicionarPessoas(Pessoa p)
        {
            ListaPessoas.Add(p);
            return p;
        }

        public bool RemoverPessoas(string  cpf)
        {
            var pessoaTemp = (from pessoa in this.ListaPessoas
                              where pessoa.CPF == cpf
                               select pessoa).SingleOrDefault();
            if (pessoaTemp == null)
            {
                return false;
            }
            var removido = ListaPessoas.Remove(pessoaTemp);            
            return removido;
        }

        public List<Pessoa> SelecionarPessoas()
        {
            return this.ListaPessoas;
        }

        public Pessoa SelecionarPessoa(string cpf)
        {
             var pessoaTemp = (from pessoa in ListaPessoas
                    where pessoa.CPF == cpf
                    select pessoa).SingleOrDefault();
            if (pessoaTemp==null)
            {
                return new Pessoa();
            }
            return pessoaTemp;
        }

        public bool AtualizarPessoas(Pessoa p)
        {
            var pessoaTemp = (from pessoa in this.ListaPessoas
                              where pessoa.CPF == p.CPF
                              select pessoa).SingleOrDefault();
            if (pessoaTemp == null)
            {
                return false;
            }

            pessoaTemp.Identificador = p.Identificador;
            pessoaTemp.Nome = p.Nome;

            return true;
        }

    }
}

Repare que nesses códigos de classes não temos aqueles using, responsáveis pela importação de bibliotecas padrão. Para onde eles foram? Onde estão as bibliotecas?

Global usings

A plataforma .NET permite agora a configuração dos nossos projetos com as global usings. Com elas temos um trecho específico no código onde ficarão definidas as importações das bibliotecas básicas que usarmos. Na criação do projeto, a opção das global usings já estará habilitada no arquivo “.csproject”.

Na imagem é mostrado o conteúdo do arquivo .csproject e exibida a configuração que habilita a utilização de global usings.

Portanto, as seguintes bibliotecas serão configuradas de maneira implícita no projeto:

System.Net.Http.Json
Microsoft.AspNetCore.Builder
Microsoft.AspNetCore.Hosting
Microsoft.AspNetCore.Http
Microsoft.AspNetCore.Routing
Microsoft.Extensions.Configuration
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.Hosting
Microsoft.Extensions.Logging

e as bibliotecas básicas:

System.Collections.Generic
System.IO
System.Linq
System.Net.Http
System.Threading
System.Threading.Task

Classe Program.CS

De volta ao projeto da minimal API, vamos configurá-lo para trabalhar com o Swagger. Como criamos um projeto vazio, adicione o pacote via NuGet, acessando pelo menu superior > “Ferramentas”> “Gerenciador de pacotes do Nuget” > “Gerenciador de pacotes do NuGet para essa solução…”, como na imagem abaixo:

Na imagem é mostrada a tela do NuGet  para adição no projeto da biblioteca `Swashbuckle.AspNetCore` do Swagger.

Agora vamos à definição de todo o código da nossa classe Program.CS:

using Alura.MinimalAPI.Alura.MinimalAPI.Model;

var builder = WebApplication.CreateBuilder(args);

//Habilitando o swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

//instanciando o repositório em memória.
var repositorio = new RepositorioDePessoas(true);

app.UseSwagger();// Ativando o Swagger

// Endpoints da solução
app.MapGet("/", () => "Hello World!");

// Listar todas as pessoas.
app.MapGet("/ListaPessoas", () => {
    return repositorio.SelecionarPessoas();        
    });

//Buscar pessoa pelo CPF.
app.MapGet("/ListaPessoas/{cpf}", (string cpf) => {
    return repositorio.SelecionarPessoa(cpf);
});

//Adicionar pessoa.
app.MapPost("/ListaPessoas/adicionar", (Pessoa pessoa) => {
    return repositorio.AdicionarPessoas(pessoa);
});

//Atualizar pessoa.
app.MapPut("/ListaPessoas/atualizar", (Pessoa pessoa) => {
    return repositorio.AtualizarPessoas(pessoa);
});

//Remover pessoa.
app.MapDelete("/ListaPessoas/remover", (string cpf) => {
    return repositorio.RemoverPessoas(cpf);
});

app.UseSwaggerUI();// Ativando a interface Swagger

app.Run();

Repare como nossa classe está bem mais enxuta agora que criamos um serviço web com 50 linhas e endpoints documentados usando Swagger. A escrita de um endpoint também está mais simples devido ao uso de uma expressão lambda. Por exemplo:

app.MapPost("/ListaPessoas/adicionar", (Pessoa pessoa) => {
    return repositorio.AdicionarPessoas(pessoa);
});

O resultado obtido pode ser observado executando o projeto no Visual Studio Community 2022 e acessando a url https://localhost:7274/swagger/index.html.

Minimalismo na programação

A ideia de simplificar a escrita de códigos tem se tornado mais presente na rotina de desenvolvimento, se fazendo notar em outras linguagens mais modernas, como Python. Existe uma tendência ao minimalismo, ou seja, a abrir mão do que não for essencial para o funcionamento de nossos softwares, inclusive no universo .NET.

Mas que objetivos a Microsoft tenta atingir com uma solução de API mínima? Vamos elencar alguns deles a seguir:

  • Para os iniciantes em programação, diminuir a complexidade do código;
  • Reduzir a necessidade de utilizar alguns recursos que podem não ser essenciais para uma solução ASP.NET como controllers, roteamento, filtros, etc;
  • Adotar o minimalismo a nível de API, buscando maior facilidade de entendimento do código que está sendo gerado.;
  • Pensar em aplicações que sejam ao mesmo tempo simples e escaláveis, ou seja, tenham um código legível, além da capacidade de expandir o armazenamento de dados ou atendimento de usuários.

Conclusão

A plataforma .NET tem evoluído a passos largos nos últimos anos e incorporou diversos recursos para tornar a plataforma de desenvolvimento mais dinâmica e simples, beneficiando pessoas novas na área sem deixar de agradar as mais experientes.

Nesse sentido, simplificar o desenvolvimento de uma API ajuda bastante e reflete a intenção da Microsoft de ouvir as demandas da comunidade, oferecendo soluções cada vez mais atraentes para todos os públicos.

Ficamos então com o lema minimalista “Menos é mais”. Até a próxima! 😉

Para conhecer mais sobre programação com .NET e mergulhar mais fundo em tecnologia, veja:

Você pode baixar o zip ou acessar o link do repositório no GitHub!

André Bessa
André Bessa

Dev C# com foco em backend e instrutor na Alura, buscando sempre novos conhecimentos.

Veja outros artigos sobre Programação