https://d226lax1qjow5r.cloudfront.net/blog/blogposts/how-to-send-an-sms-with-net-6-minimal-api/sms_net-6.png

Cómo enviar un SMS con .Net 6 Minimal API

Publicado el November 6, 2021

Tiempo de lectura: 5 minutos

Llevo un tiempo echando un vistazo a las versiones preliminares de .Net 6, y una de las características más interesantes de las que habla mucha gente son las API mínimas. Aunque parece que la opinión está muy dividida, creo que son una adición bienvenida. Elimina gran parte del peso de utilizar ASP.NET MVC y ciertamente baja el listón de entrada con una sensación similar a ExpressJS en NodeJS.

Hace poco más de un año publicamos una entrada en nuestro blog titulada "Cómo enviar un SMS con ASP.NET Core MVC". Así que con el lanzamiento de .Net 6 sobre nosotros, pensé que sería una buena idea tomar inspiración y ver cómo sería utilizar la nueva sintaxis de la API mínima para emular la misma funcionalidad.

Dame el código

Puede ir directamente al código en GitHub.

Requisitos previos

  • .Net 6 RC 2 SDK o superior

  • Visual Studio 2022 Preview o Visual Studio Code

Vonage API Account

To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.

Creación del proyecto

La forma más sencilla que he encontrado para crear un nuevo proyecto Minimal API es utilizando el siguiente comando

dotnet new web -o SmsDotnetMinimalApi

Microsoft también tiene un gran tutorial sobre la creación de un nuevo proyecto de API mínima con Visual Studio.

Ahora deberíamos tener una API con un endpoint "Hello World". A esto añadiremos dos paquetes NuGet, el primero es SDK .Net de Vonage versión 5.9.2 en el momento de escribir esto. Como esto va a ser una API no vamos a tener una interfaz de usuario por lo que el segundo es Swashbuckle / Swagger que nos permitirá probar cualquier punto final que creamos fácilmente.

dotnet add package Vonage
dotnet add package Swashbuckle.AspNetCore

Lo pequeño es hermoso

Junto con el habitual appsettings.jsonsu proyecto recién creado será un solo archivo, Program.cs. Esto es realmente mínimo, para un proyecto ASP.Net al menos.

Solution Explorer.Net 6 Project

Abramos Program.csy debería verse así.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

Esto es todo lo que necesitas para tener una API .NET completa en un único archivo. Esto proporcionará un punto de partida mucho más ligero para construir una pequeña API o microservicio. Y para ser honesto, todavía me sorprende cuando pienso en la cantidad de código que WebAPI necesitaría para producir el mismo resultado.

Configuración

Empecemos añadiendo algunos ajustes. Dentro de appsettings.json debemos agregar nuestra clave y secreto de Vonage, que se utilizan para autenticar tu aplicación con los servicios de Vonage y se encuentran en la parte superior del Panel.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "Vonage_key": "ab12c3de",
  "Vonage_secret": "ZKSQ1vlzNvyZnQCI"
}

Actualmente, no tenemos configurada la Inyección de Dependencias, así que agreguemos la clase VonageClient a la colección de servicios. Esto permitirá que sea inyectada en cualquier clase o método que utilizaremos más adelante.

Importe los espacios de nombres necesarios en la parte superior del archivo.

using Vonage;
using Vonage.Messaging;
using Vonage.Request;

Registra el VonageClient en la colección de servicios.

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);
});

Yendo línea por línea podemos ver que obtenemos una instancia de IConfiguration, esto nos permite acceder a la configuración de la aplicación que necesitamos. La clave y el secreto son entonces recuperados de la configuración para que podamos crear las credenciales que son requeridas por el constructor VonageClient.

Enviar un SMS

Ahora que tenemos nuestra clase VonageClient configurada y lista para ser inyectada vamos a crear un nuevo endpoint al que podamos enviar peticiones. Necesitaremos pasar un modelo de datos al endpoint así que creamos una clase en un nuevo archivo llamado `SmsModel`. Luego, dentro de la clase, queremos añadir las siguientes propiedades.

public class SmsModel
{
    public string To { get;set; }

    public string From { get;set; }

    public string Text { get;set; }
}

Con nuestro modelo creado podemos seguir adelante y añadir un nuevo método POST con el VonageClient y nuestra clase 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
    });
});

En este bloque de código ocurren un par de cosas. En primer lugar, estamos utilizando el método MapPost para crear un endpoint en http://localhost:5000/sms. En segundo lugar, estamos declarando los parámetros para el método; VonageClient se inyectará utilizando la inyección de dependencia que establecimos anteriormente, SmsModel se creará utilizando el cuerpo de la solicitud utilizando model binding.

El cuerpo principal del método se encarga de enviar el SMS. Creamos una instancia de SendSmsRequest con los datos del modelo que le hemos pasado y, a continuación, pasamos la clase de solicitud al método SendAnSmsAsync del SmsClient. En el espíritu del "mínimo", ¡esto es sólo una línea!

Pruébelo

El proyecto debería ahora construirse, ejecutarse y recibir peticiones. Como se mencionó anteriormente, sin embargo, no tenemos ninguna interfaz de usuario para probar esto fácilmente por lo que vamos a añadir unas pocas líneas más de código para implementar la interfaz de usuario Swagger en nuestro proyecto.

Directamente después de var builder = WebApplication.CreateBuilder(args) necesitamos añadir dos líneas de código. Éstas añadirán los servicios necesarios para inyectar dependencias.

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

Una vez añadidos, registramos el middleware Swagger antes de la línea app.Run() línea

app.UseSwagger();
app.UseSwaggerUI();
app.Run();

Con todo nuestro código ya escrito, podemos ejecutar el proyecto, pulsa F5 si estás usando Visual Studio o ejecuta el siguiente comando dentro de la carpeta del proyecto

dotnet run

Ahora vaya a https://localhost:5001/swagger y deberías poder utilizar el botón "Pruébalo" en el extremo SMS. A partir de ahí verás un código de respuesta 200 y recibirás un mensaje de texto.

Validación

La validación de entrada es una parte vital de cualquier API, tal y como están las cosas no hay validación incorporada en Minimal APIs como se encontraría con ASP.NET MVC. Damian Edwards ha creado una pequeña biblioteca llamada MinimalValidation que utiliza atributos de validación similares a los de MVC.

Personalmente, prefiero Validación fluida ya que utiliza código para definir reglas en lugar de atributos. Un ejemplo de esto está por debajo, para el código completo incluyendo la validación echa un vistazo a la repositorio en GitHub.

Registro de servicios y cambios en los puntos finales

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");
        }
    }
}

Ampliación de la validación

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()
               );
}

Reflexiones finales

Mientras que MVC es un marco de trabajo con todas las funciones que incorpora la vinculación y validación de modelos, canalizaciones extensibles a través de filtros, comportamientos basados en convenciones y declaraciones y mucho más. Algunos pueden no necesitar características específicas o tener limitaciones de rendimiento que hacen que el uso de MVC no sea deseable. Con más y más características emergiendo como middleware ASP.NET Core (autorización, autenticación, enrutamiento, etc), ASP.NET 6 y Minimal APIs traen estas características en juego con menos pompa y es un ajuste perfecto para la creación de microservicios ligeros en el momento oportuno de una manera mantenible.

Recursos

Compartir:

https://a.storyblok.com/f/270183/400x339/e206caec3f/matt-hunt.png
Matt HuntAntiguo miembro del equipo de Vonage