Dev (Back & Front)ARTIGO

Criando uma API OData v4 com ASP.NET Core

No seguinte artigo, o autor apresenta um passo a passo ensinando a criar uma API OData v4 utilizando o ASP.NET Core e explica as vantagens deste processo.

Fala, galera!

Hoje vamos falar um pouco sobre o OData (Open Data Protocol) e sobre como podemos criar APIs Rest utilizando este protocolo. Se você já desenvolveu APIs para diversos clientes, já deve ter tido o problema no qual um determinado campo no seu objeto não é necessário para um cliente, porém extremamente importante para outro cliente, ou até mesmo que sua API precisa de um filtro mais especializado para um determinado cliente, mas não é importante para outro.

Para estes tipos de cenários podemos utilizar o OData (Open Data Protocol), no qual o seu principal objetivo é criar APIs consultáveis, filtráveis e com interoperabilidade.

O que é Open Data Protocol (OData)?

OData ou Open Data Protocol é uma série de padrões para construção e consumo de API. Você pode saber mais sobre o OData Protocol através de sua documentação aqui. Existem inúmeros benefícios em utilizar o padrão OData, desde a facilidade de criar padrões de consultas até a facilidade de leitura do caminho de sua API.

Dentro do OData Protocol existem as suas convenções e umas de suas principais convenções é o Query Options – isso que torna nossas APIs flexíveis.

Query Options é usado para definir como sua API vai entregar os dados, podendo conter dados de pesquisas, filtros, ordenações, projeções e muito mais.

Abaixo um exemplo de uma API OData:

ASP.NET CORE E OData Protocol: como criar sua API OData

Vamos criar um API Rest com .NET Core utilizando o Protocolo OData. Para isso criaremos um projeto Web API conforme o exemplo abaixo:

Com o projeto criado vamos adicionar a referência do pacote do OData utilizando o Package Manager Console.

bash
Install-Package Microsoft.AspNetCore.OData

Agora utilizaremos o EntityFramework Core como nosso ORM padrão e o SQL Server como provider para realizar a persistência dos dados. Para isso vamos adicionar o pacote EntityFrameworkCore.SqlServer conforme comando abaixo:

bash
Install-Package Microsoft.EntityFrameworkCore.SqlServer

Vamos criar uma classe de Livro e assim utilizar o Entity Framework para mapear esta classe conforme o código abaixo:

public class Book
{
    [Key]
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string ISBN { get; set; }
    public string Author { get; set;}
}

Com a nossa classe de livro criada, vamos criar o nosso contexto. É nele ele que vamos consultar os dados do Livro conforme o código abaixo:

public class DataContext : DbContext
{
    public DbSet<Book> Books { get; set; }
    public DataContext() : base()
    {
    }
    public DataContext(DbContextOptions options) : base(options)
    {
    }
}

Com o nosso contexto criado, vamos criar os nossos migrations. Para isso, no terminal digite:

Add-Migration Initial
Update-Database

Muito bem! Vamos agora configurar nossos serviços OData. Para isso, entre no Startup.cs e modifique-o conforme código abaixo:

public class Startup
{
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public IConfiguration Configuration { get; }
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddOData();
            services.AddDbContext<DataContext>(options =>
            {
                options.UseSqlServer(Configuration.GetConnectionString("ODataSample"));
            });
            services.AddMvc().AddJsonOptions(opt =>
            {
                opt.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            });
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseMvc(o =>
            {
                o.MapODataServiceRoute("ODataRoutes", "odata", GetEdmModel());
            });
        }
        public static IEdmModel GetEdmModel()
        {
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            
            // Habilita funções OData como $filter, $select e etc..
            builder.EntitySet<Book>(nameof(Book))
                   .EntityType
                   .Filter()
                   .Count()
                   .Expand()
                   .OrderBy()
                   .Page()
                   .Select();
            return builder.GetEdmModel();
        }
 }

Com o nosso Startup já configurado, basta agora criar um Controller. Este Controller será uma API OData, e para isso basta herdar da classe ODataController conforme o exemplo abaixo:

[Produces("application/json")]
[Route("api/Book")]
public class BookController : ODataController
{
    private DataContext Context { get; set; }
    public BookController(DataContext context)
    {
        this.Context = context ?? throw new ArgumentNullException(nameof(context));
    }
    [HttpPost]
    public IActionResult Post([FromBody] Book model)
    {
        this.Context.Books.Add(model);
        this.Context.SaveChanges();
        return Created("/api/book/" + model.Id, model);
    }
    [EnableQuery]
    public IQueryable<Book> Get() => Context.Books.AsQueryable();
}

Pronto. Nossa API OData está pronta, bastando somente a consumir. Para testa-lá vamos abrir o Postman e enviar algumas requisições conforme imagem abaixo:

Criando um novo registro

Obtendo todos os registros

Selecionando determinados campos e ordenando por Autor

E ai galera, viram como é fácil criar uma API OData com o ASP.NET Core? Com uma API OData podemos criar diversas consultas especializadas com os seus filtros, paginações, seleções e etc, e nossa API ganha um poder muito grande para trabalhar em cima de dados.

O código fonte deste exemplo encontra-se no meu GitHub através deste link.

Abraços e até a próxima!

Rafael CruzAutor

Rafael Cruz é Partner e Lead Software Architect na Electric Dreams, Professor Universitário, Most Valuable Profissional (MVP), Instrutor Oficial Microsoft (MCT), Fundador do Coders in Rio, Pós graduado em Engenharia de Software pela UFRJ. Atua como palestrante e autor em portais voltado para tecnologia Microsoft com foco em Web, Cloud e Mobile

Ver perfil