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.
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:
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!