
Como enviar um SMS com a API mínima do .NET 6
Tempo de leitura: 5 minutos
Já faz algum tempo que venho acompanhando as versões de pré-lançamento do .NET 6, e um dos recursos mais empolgantes sobre os quais muita gente tem falado são as APIs Mínimas. Embora pareça que as opiniões estejam bastante divididas, acho que elas são uma adição bem-vinda. Isso alivia bastante o trabalho de usar o ASP.NET MVC e, sem dúvida, reduz a barreira de entrada, com uma sensação semelhante à do ExpressJS no Node.js.
Há pouco mais de um ano, publicamos um post no blog intitulado “Como enviar um SMS com o ASP.NET Core MVC”. Agora, com o lançamento do .NET 6 se aproximando, achei que seria uma boa ideia me inspirar nesse post e ver como seria usar a nova sintaxe da API Minimal para emular a mesma funcionalidade.
Só me dê o código
Você pode pular direto para o código no GitHub.
Pré-requisitos
SDK do .NET 6 RC 2 ou versão superior
Visual Studio 2022 Preview ou Visual Studio Code
Criação do projeto
A maneira mais fácil que encontrei para criar um novo projeto Minimal API é usando o comando abaixo
dotnet new web -o SmsDotnetMinimalApiA Microsoft também tem um ótimo tutorial sobre como criar um novo projeto com a API Minimal usando o Visual Studio.
Agora já devemos ter uma API com um endpoint “Hello World”. A ela, vamos adicionar dois pacotes NuGet; o primeiro é o SDK .NET da Vonage versão 5.9.2 no momento da redação deste artigo. Como se trata de uma API, não teremos uma interface de usuário; portanto, o segundo é o Swashbuckle / Swagger, que nos permitirá testar facilmente quaisquer endpoints que criarmos.
dotnet add package Vonage
dotnet add package Swashbuckle.AspNetCore Pequeno é bonito
Além do habitual appsettings.json, seu projeto recém-criado será composto por apenas um arquivo, Program.cs. Isso é realmente mínimo, pelo menos para um projeto ASP.Net.
.Net 6 Project
Vamos abrir Program.cs, deve ficar assim.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();Isso é tudo o que você precisa para ter uma API .NET completa em um único arquivo. Isso oferece um ponto de partida bem mais leve para criar uma pequena API ou um microsserviço. E, para ser sincero, ainda fico impressionado quando penso na quantidade de código que a WebAPI precisaria para produzir o mesmo resultado.
Configuração
Vamos começar adicionando algumas configurações. Aqui appsettings.json , precisamos adicionar nossa chave e senha da Vonage; elas são usadas para autenticar seu aplicativo nos serviços da Vonage e podem ser encontradas na parte superior do Painel.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"Vonage_key": "ab12c3de",
"Vonage_secret": "ZKSQ1vlzNvyZnQCI"
}No momento, não temos a injeção de dependências configurada; portanto, vamos adicionar a classe `VonageClient` à coleção de serviços. Isso permitirá que ela seja injetada em qualquer classe ou método que venhamos a utilizar mais adiante.
Importe os namespaces necessários no início do arquivo.
using Vonage;
using Vonage.Messaging;
using Vonage.Request;Registre o VonageClient na coleção de serviços.
builder.Services.AddSingleton<VonageClient>(provider =>
{
var config = provider.GetRequiredService<IConfiguration>();
var key = config.GetValue<string>("Vonage_key");
var secret = config.GetValue<string>("Vonage_Secret");
var credentials = Credentials.FromApiKeyAndSecret(key, secret);
return new VonageClient(credentials);
});Analisando linha por linha, podemos ver que obtemos uma instância de IConfiguration, o que nos permite acessar as configurações do aplicativo de que precisamos. A chave e o segredo são então recuperados da configuração para que possamos criar as credenciais exigidas pelo construtor do VonageClient.
Envio de uma mensagem SMS
Agora que temos nossa classe `VonageClient` configurada e pronta para ser injetada, vamos criar um novo endpoint para o qual possamos enviar solicitações. Precisaremos passar um modelo de dados para o endpoint; portanto, crie uma classe em um novo arquivo chamado `SmsModel`. Em seguida, dentro da classe, vamos adicionar as seguintes propriedades.
public class SmsModel
{
public string To { get;set; }
public string From { get;set; }
public string Text { get;set; }
}Com nosso modelo criado, podemos prosseguir e adicionar um novo método POST com o VonageClient e nossa classe SmsModel como parâmetros.
app.MapPost("/sms", async (VonageClient vonageClient, SmsModel smsModel) =>
{
var smsResponse = await vonageClient.SmsClient.SendAnSmsAsync(new SendSmsRequest
{
To = smsModel.To,
From = smsModel.From,
Text = smsModel.Text
});
});Há algumas coisas acontecendo nesse trecho de código. Primeiro, estamos usando o MapPost método de extensão para criar um endpoint em http://localhost:5000/sms. Em segundo lugar, estamos declarando os parâmetros do método; VonageClient que serão injetados por meio da injeção de dependências que configuramos anteriormente, SmsModel serão criados com base no corpo da solicitação, por meio da ligação de modelo.
O corpo principal do método realiza o trabalho propriamente dito de enviar o SMS. Criamos uma instância do SendSmsRequest usando os dados do modelo que passamos; depois, basta passar a classe de solicitação para o método do SmsClient SendAnSmsAsync . Seguindo o espírito do “minimalismo”, isso dá apenas uma linha!
Experimente
O projeto agora deve ser compilado, executado e receber solicitações. Conforme mencionado anteriormente, porém, não temos uma interface de usuário para testar isso facilmente; por isso, vamos adicionar mais algumas linhas de código para implementar o Swagger UI em nosso projeto.
Logo após a linha `var builder = WebApplication.CreateBuilder(args)`, precisamos adicionar duas linhas de código. Elas irão adicionar os serviços necessários para a injeção de dependências.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();Depois de adicioná-los, registramos o middleware do Swagger antes da app.Run() linha
app.UseSwagger();
app.UseSwaggerUI();
app.Run();Agora que todo o nosso código está escrito, podemos executar o projeto: pressione F5 se estiver usando o Visual Studio ou execute o comando abaixo dentro da pasta do projeto
dotnet runAgora acesse https://localhost:5001/swagger e você poderá usar o botão “Experimente” no endpoint de SMS. A partir daí, você verá um código de resposta 200 e receberá uma mensagem de texto.
Validação
A validação de entradas é uma parte essencial de qualquer API; no momento, não há validação integrada nas APIs Minimal, como seria o caso no ASP.NET MVC. Damian Edwards criou uma pequena biblioteca chamada MinimalValidation , utilizando atributos de validação semelhantes aos da validação do MVC.
Pessoalmente, prefiro o Fluent Validation , pois ele usa código para definir regras, em vez de atributos. Veja um exemplo abaixo; para o código completo, incluindo a validação, confira o repositório no GitHub.
Registro de serviços e alterações nos pontos de extremidade
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// validation
builder.Services.AddValidatorsFromAssemblyContaining<SmsModel>(ServiceLifetime.Scoped);
...
app.MapPost("/sms", async (VonageClient vonageClient, SmsModel smsModel, IValidator<SmsModel> validator) =>
{
ValidationResult validationResult =validator.Validate(smsModel);
if (!validationResult.IsValid)
{
return Results.ValidationProblem(validationResult.ToDictionary());
}
var smsResponse = await vonageClient.SmsClient.SendAnSmsAsync(new SendSmsRequest
{
To = smsModel.To,
From = smsModel.From,
Text = smsModel.Text
});
return Results.Ok();
});Validador de modelos
public class SmsModel
{
public string To { get; set; }
public string From { get; set; }
public string Text { get; set; }
public class Validator : AbstractValidator<SmsModel>
{
public Validator()
{
RuleFor(x => x.To).NotEmpty().WithMessage("To phone number required");
RuleFor(x => x.From).NotEmpty().WithMessage("From phone number required");
}
}
}Extensão de validação
public static class ValidationExtensions
{
public static IDictionary<string, string[]> ToDictionary(this ValidationResult validationResult)
=> validationResult.Errors
.GroupBy(x => x.PropertyName)
.ToDictionary(
g => g.Key,
g => g.Select(x => x.ErrorMessage).ToArray()
);
} Considerações finais
Embora o MVC seja uma estrutura completa, que incorpora vinculação e validação de modelos integradas, pipelines extensíveis por meio de filtros, comportamentos baseados em convenções e em linguagem declarativa e muito mais, alguns usuários podem não precisar de recursos específicos ou ter restrições de desempenho que tornem o uso do MVC indesejável. Com cada vez mais recursos surgindo como middleware do ASP.NET Core (autorização, autenticação, roteamento etc.), o ASP.NET 6 e as APIs Mínimas colocam esses recursos em prática com menos alarde e são a opção perfeita para criar microsserviços leves de maneira ágil e sustentável.
Recursos
Todo o código deste tutorial pode ser encontrado no GitHub
Microsoft Visão geral das APIs mínimas
O essencial de David Fowler Visão geral das APIs mínimas
O que são as pessoas a postar no Twitter sobre APIs mínimas