.NET

Vitamina tu API en .Net Core con OData

Siempre has querido definir tu API para que realice consultas de una forma poderosa (como las disponibles en Azure Search)  y lo sabes. En este post veremos qué es OData y cómo integrarlo en nuestra API realizada en .NET Core para vitaminizarlas de una manera muy sencilla.

NOTA: La implementación actual de OData sólo puede admitir hasta ASP.NET Core 2.2. Para ASP.NET Core 3.0 está previsto que se libere en el segundo trimestre de 2020.

¿Qué es OData?

OData (Open Data Protocol) es un estándar que define un conjunto de mejores prácticas para la construcción y consumo de RESTful APIs, permitiendo a los desarrolladores la capacidad de desarrollar Queryable APIs. Este protocolo utiliza otras tecnologías ya reconocidas como HTTP, AtomPub o JSON y permite a cualquier cliente obtenga información de cualquier fuente basándose en:

  • La estandarización de una forma uniforme de representación de datos estructurados a través de Atom o JSON.
  • La utilización de convenciones URL uniformes, tanto para la navegación, filtrado, orden y paginación de datos (entre otros).
  • La creación de operaciones uniformes mediante métodos HTTP (GET, POST, PUT y DELETE).

Para más información podéis visitar https://www.odata.org/

La potencia de OData nos da la posibilidad, entre otras, de:

  • Aplicar filtros en los datos a obtener.
  • Habilitar paginación.
  • Ordenar los datos.
  • Reestructurar los datos de respuesta.
  • Envío de solicitudes de forma asíncrona o en modo batch.

Al lío que es lo que nos mola

Lo primero que debemos hacer es descargarnos el siguiente paquete Nuget: Microsoft.AspNetCore.OData

Una vez instalado vamos a configurar OData en la inicialización de nuestra API. En nuestra clase Startup.cs debemos agregar el servicio de OData de la siguiente forma:


public void ConfigureServices(IServiceCollection services)
{
   services.AddOData();
   services.AddODataQueryFilter();

   services.AddDbContext<AdventureWorks2016Context>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

   services.AddMvc(options =>
   {
      options.EnableEndpointRouting = false;
   }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

Hay que tener en cuenta que la versión 2.2 de .Net Core tiene habilitado por defecto el “endpoint routing”. Tenemos que deshabilitarlo para no recibir un bonito mensaje como este:

System.InvalidOperationException: ‘Cannot use ‘Microsoft.AspNet.OData.Routing.ODataRoute’ with Endpoint Routing.’

Luego configuramos el routing de la siguiente forma:


public static void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
   if (env.IsDevelopment())
   {
      app.UseDeveloperExceptionPage();
   }
   else
   {
      // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
      app.UseHsts();
   }

   app.UseHttpsRedirection();
   app.UseMvc(routeBuilder =>;
   {
      routeBuilder.EnableDependencyInjection();
      routeBuilder.Select().Filter().OrderBy().Expand().Count().MaxTop(10);

      routeBuilder.MapODataServiceRoute("api", "api", GetEdmModel(app.ApplicationServices));
   });
}

private static IEdmModel GetEdmModel(IServiceProvider serviceProvider)
{
   ODataModelBuilder builder = new ODataConventionModelBuilder(serviceProvider);

   builder.EntitySet<Person>("Person")
           .EntityType
           .Filter()
           .Count()
           .Expand()
           .OrderBy()
           .Page()
           .Select();
   .. .. ..
   return builder.GetEdmModel();
}

Líneas de código

Comentemos algo de estas lineas de código.

  • routeBuilder.EnableDependencyInjection:  Esto habilita la inyección de dependencias para inyectar los servicios de OData en nuestros controladores.
  • routeBuilder.Select().Filter().OrderBy().Expand().Count().MaxTop(10): Esta línea de código establece qué funcionalidad de OData queremos habilitar en nuestra API.
  • routeBuilder.MapODataServiceRoute(«api», «api», GetEdmModel(app.ApplicationServices)): Esta línea habilita el mapeo de la ruta OData con los atributos de ruta de OData que veremos más adelante en los controladores.

Si os fijáis en la última línea, se configura EDM (Entity Data Model) para definir el mapeo de forma correcta entre nuestras entidades de datos en entidades que usa OData para realizar las operaciones de filtro, selección, ordenación, etc.

Con esto ya tendríamos configurado OData en nuestra API. ¿Sencillo no?

Controladores

Echemos un ojo a los controladores.


using AspNetCoreOData.Database;
using Microsoft.AspNet.OData;
using Microsoft.AspNet.OData.Query;
using Microsoft.AspNet.OData.Routing;
using Microsoft.AspNetCore.Mvc;
using System.Linq;

namespace AspNetCoreOData.Controllers
{
   [ODataRoutePrefix("Person")]
   public class PersonController : ODataController
   {
      private AdventureWorks2016Context db;

      public PersonController(AdventureWorks2016Context adventureWorks2016Context)
      {
         db = adventureWorks2016Context;
      }

      [ODataRoute]
      [EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]
      [HttpGet]
      public IActionResult Get()
      {
         return Ok(db.Person.AsQueryable());
      }

      [ODataRoute("({key})")]
      [EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]
      [HttpGet]
      public IActionResult Get([FromODataUri] int key)
      {
         return Ok(db.Person.Find(key));
      }
   }
}

Lo primero que debemos tener en cuenta es que el controlador heredará la clase ODataController. Después, al tener habilitado el routing de OData, estableceremos a nivel de controlador el atributo ODataRoutePrefix, indicando el prefijo (como ya habíamos avanzado).


[ODataRoutePrefix("Person")]

Decoraremos con el atributo ODataRoute y habilitaremos las consultas OData con EnableQuery nuestras acciones del controlador.


[ODataRoute("({key})")]
[EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]

Preparados, listos… ¡YA!

 Ejecutamos nuestra API y vemos algunos tipos de consultas que podemos hacer (para más información de la sintaxis OData Query, puedes visitar: https://www.odata.org/documentation/odata-version-2-0/uri-conventions/).

En el código se adjuntará una colección Postman para que podáis trastear. Algunas consultas que podemos hacer son las siguientes:

  • Seleccionar todas las personas:

https://localhost:5001/api/Person

  • Seleccionar todas las personas que se llaman Helen:

 https://localhost:5001/api/Person?$filter=FirstName eq ‘Helen’

  • Seleccionar la persona con identificador igual a 3:

https://localhost:5001/api/Person(3)

  • Seleccionar todas las personas que se llaman Helen pero mostrar sólo nombres y apellidos:

https://localhost:5001/api/Person?$filter=FirstName eq ‘Helen’ &$select=FirstName,LastName

  • Seleccionar todas las personas que se llaman Helen ordenadas por apellidos de forma descendente:

https://localhost:5001/api/Person?$filter=FirstName eq ‘Helen’&$orderby=LastName desc

Conclusiones

La conclusión que sacamos de OData es que mola y mucho 🙂 Nos da potencia para realizar consultas bestial y encima la configuración en nuestra API en .NET Core es muy sencilla.

El código de ejemplo junto con una colección de Postman y una base de datos de prueba lo podéis descargar desde GitHub

Happy coding!!

Compartir
Publicado por
Sergio Parra Guerra

Este sitio web utiliza cookies para que tengas la mejor experiencia de usuario. Si continuas navegando, estás dando tu consentimiento para aceptar las cookies y también nuestra política de cookies (esperemos que no te empaches con tanta cookie 😊)