Saltar a contenido

.Net core 3.1

Overview

En este documento, hablaremos de como utilizar Asp.net core en nuestro proyecto para realizar API Rest, además detallaremos la configuración y las herramientas que nos da la librería Andreani.ARQ.WebHost

Librería WebHost

Esta librería surge con la necesidad de poder estandarizar la configuración inicial de los proyectos de tipo Web API. La Librería cuenta con:

  1. Configuración de archivos de settings.
  2. Configuración de Logging con Serilog.
  3. Configuración de Asp net controllers.
  4. Configuración estándar para run de web host.
  5. Configuración de Autodocumentación con Swagger.
  6. Configuración de Healthcheck.
  7. Configuración de Opentracing.

Otro enfoque que se tomó en la implementación del nuevo Template de arquitectura, es respetar la configuración estándar de Net core para poder permitir a los equipos configurar las dependencias que necesiten bajo un entorno estandarizado en la documentación de el framework.

El cambio de Carter por Asp net es debido a varios motivos:

  1. Carter no es un componente nativo del framework.
  2. Carter limita la implementación de librerías externas.
  3. Carter posee una documentación limitada.
  4. Estandarización, la mayoría de los desarrolladores que aprenden el framework aprenden con Asp Net. La comunidad utiliza Asp net.
  5. Mantenibilidad, asp net al ser nativo del framework es mantenido y evolucionado por Microsoft.

Implementación

Para utilizar la librería Andreani.ARQ.WebHost debemos realizar los siguientes pasos:

  1. Configuración de Web Host en archivo Program.cs

    public class Program
        {
            public static void Main(string[] args)
            {
                CreateHostBuilder(args).Build().Run();
            }
    
            public static IHostBuilder CreateHostBuilder(string[] args) =>
                Host.CreateDefaultBuilder(args)
                .ConfigureAndreaniWebHost<Startup>(args);
        }
    
    La función ConfigureAndreaniWebHost realiza la configuración.

  2. En el archivo Startup.cs debemos agregar la configuración del services.

            public void ConfigureServices(IServiceCollection services)
            {
                services.ConfigureAndreaniServices(Configuration);
    
                //...
            }
    

  3. En el archivo Startup.cs debemos agregar la configuración de application.

            public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider)
            {
                app.ConfigureAndreani(env, provider);
    
                // ...
            }
    

Con esas 3 líneas de código tenemos la configuración inicial con las herramientas detalladas previamente.

Result

Web Host dispone de una extensión de Controller que maneja las respuestas de los handler del mediator, por lo que no debemos preocuparnos por manipular el HTTP Response. La extensión Result siempre devuelve json.

Ejemplo

    this.Result(await _mediator.Send(body)

ASP.NET

Overview

ASP.NET es un marco web gratuito para crear excelentes sitios web y aplicaciones web utilizando HTML, CSS y JavaScript. También puede crear API web y utilizar tecnologías en tiempo real como Web Sockets.

Para más info consultar aqui

Cómo una hacer Web API

En este apartado vamos a mostrar diferentes técnicas para realizar API o endpoints.

Controller

Los Endpoint se encuentran albergados en los objetos denominados Controllers

    [ApiController]
    [ApiVersion("1.0")]
    [Route("api/v{version:apiVersion}/[controller]")]
    public class PersonController : ControllerBase
    {
        private readonly IMediator _mediator;
        public PersonController(IMediator mediator)
        {
            _mediator = mediator;
        }
    }
Detalle

Campo Detalle
ApiController Es el atributo que identifica un controlador
ApiVersion Identifica la versión de las APIs, esta versión se incluirá en la URL
Route Identifica la ruta base que tendrán las API de este controller. El detalle v{version:apiVersion} se reemplaza en tiempo de run por el valor cargado en ApiVersion
IMediator Interface de MadiatR.

Simple CRUD

  1. Get List: Devuelve una lista de un recurso
        [HttpGet]
        public async Task<IActionResult> GetList()
        {
            //...
        }
        // Crea el endpoint
        // GET api/v1/person
    
  2. Get by Id: Devuelve el recurso que contenga el identificador
        [HttpGet("{id}")]
        public async Task<IActionResult> GetById(string id)
        {
            //...
        }
        // Crea el endpoint
        // GET api/v1/person/{id}
        // uso GET api/v1/person/5
    
  3. Create: Crea un recurso
        [HttpPost]
        public async Task<IActionResult> Create(ObjectRequest request)
        {
            //...
        }
        // Crea el endpoint
        // POST api/v1/person
    
  4. Update: Actualizamos la información de un recurso
        [HttpPut("{id}")]
        public async Task<IActionResult> Create(string id, ObjectRequest request)
        {
            //...
        }
        // Crea el endpoint
        // PUT api/v1/person/{id}
    
  5. Delete: Borramos un recurso
        [HttpDelete("{id}")]
        public async Task<IActionResult> Create(string id)
        {
            //...
        }
        // Crea el endpoint
        // DELETE api/v1/person/{id}
    

Filtros - Parámetros

  1. Parametros por url
        [HttpGet("{id}/message/{messageId}")]
        public async Task<IActionResult> GetRecord(string id, string messageId)
        {
            //...
        }
        // Crea el endpoint
        // GET api/v1/person/{id}/message/{messageId}
    
  2. Query param
        [HttpGet]
        public async Task<IActionResult> GetList(string sort, string field, string filter)
        {
            //...
        }
        // Crea el endpoint
        // GET api/v1/person?sort=any&field=any&filter=any
    
        [HttpGet("{id}/message")]
        public async Task<IActionResult> GetList(string id, [FromQuery]string field, [FromQuery] string filter)
        {
            //...
        }
        // Crea el endpoint
        // GET api/v1/person/{id}/message?field=any&filter=any
    
  3. parametro por Body
        [HttpPatch("{id}")]
        public async Task<IActionResult> GetList(string id, ObjectRequest body)
        {
            //...
        }
        // Crea el endpoint
        // Patch api/v1/person/{id}
    
        [HttpPatch("{id}")]
        public async Task<IActionResult> GetList(string id, [FromBody] ObjectRequest body)
        {
            //...
        }
        // Crea el endpoint
        // Patch api/v1/person/{id}
    
  4. parámetros por header
        [HttpGet]
        public async Task<IActionResult> GetList([FromHeader] string page)
        {
            //...
        }
        // Crea el endpoint
        // GET api/v1/person -h page=any
    

Swagger

Se implementó la autodocumentación para asegurarnos de que todos los desarrollos cuenten con su documentación actualizada sin disponer de tiempo y esfuerzo por parte de los desarrolladores.

Si bien los detalles básicos de la documentación están cubiertos sugerimos agregar algunos atributos en el código para tener un alto nivel de calidad en la documentación.

  1. Podemos agregar las posibles respuestas que tiene una API, asegurándonos de documentar la respuesta correcta como una respuesta incorrecta por parte del sistema.

        [HttpGet]
        [ProducesResponseType(typeof(List<PersonDto>), StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(List<Notify>), StatusCodes.Status400BadRequest)]
        public async Task<IActionResult> Get() => this.Result(await _mediator.Send(new ListPerson()));
El atributo ProducesResponseType permite realizar esta documentación. Debemos especificar cual es la estructura que vamos a devolver y el status code.

  1. Podemos agregar algunas etiquetas para explicar las acciones que realizan nuestras API. Lo podemos realizar con la documentación de xml nativa de .Net

        /// <summary>
        /// Listado de persona de la base de datos
        /// </summary>
        /// <remarks>en los remarks podemos documentar información más detallada</remarks>
        /// <param name="body"></param>
        /// <returns></returns>
        [HttpGet]
        [ProducesResponseType(typeof(List<PersonDto>), StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(List<Notify>), StatusCodes.Status400BadRequest)]
        public async Task<IActionResult> Get() => this.Result(await _mediator.Send(new ListPerson()));
la etiqueta <summary></summary> permite documentar en primer nivel, mientras que el <remarks></remarks> se detalla dentro de la sección de la api en el Swagger, pueden ver el ejemplo en la sección de OpenApi de esta documentación

  1. Por ultimo podemos incluir ejemplos en nuestra documentación para disponibilizar un escenario verdadero con posibles valores verdaderos de la consulta. Esto da una gran perspectiva al cliente para saber que mandar en los campos solicitados.

    public class CreatePersonResponse
    {
        /// <summary>
        ///
        /// </summary>
        /// <example>5</example>
        public int PersonId { get; set; }
        /// <summary>
        ///
        /// </summary>
        /// <example>Is success</example>
        public string Message { get; set; }
    }
La etiqueta <example></example>, en el objeto que documentamos como respuesta de nuestra API, documentará el ejemplo y mostrará ese valor en la documentación.