Construção de uma WEB API em ASP.NET Core 3.1 com Entity Framework e MVC [Parte 2] — Swagger e Migrações

Sandro Mendes
7 min readAug 16, 2020

--

Dando sequência à primeira parte do tutorial de construção de uma WEB API, vamos aprender como criamos e aplicamos migrações, como mapear relacionamentos entre as entidades do modelo, também iremos refatorar o código para que fique mais limpo e padronizado, além de documentar a API com o Swagger.

Parte 1:

  • Um pouco sobre REST
  • Recurso
  • Criação do projeto no Visual Studio 2019
  • Configurações
  • Camadas da aplicação
  • Testando a API com Postman

Parte 2:

  • Migrações (EF Migrations)
  • Relacionamentos One-to-Many
  • Padronizando o retorno da camada de dados
  • Ajustando o Controlador de Produtos
  • Documentando a API

Estrutura do projeto pós refatoração

Estrutura do projeto + pacotes instalados

Migrações (EF Migrations)

Migrações são um recurso poderoso oferecido pelo Entity Framework, em que teremos uma sincronização entre o modelo físico na base de dados e o mapeamento das classes do modelo do projeto. Esse recurso é acessado por alguns comandos que podem ser executados tanto no PMC(Package Management Console | Console do Gerenciador de Pacotes) ou pelo CLI do Dotnet.

Principais comandos de migrações
  • Para criar uma migração:

No Visual Studio, acesse Ferramentas > Gerenciador de pacotes do NuGet > Console do Gerenciador de Pacotes e informe o comando:

Add-Migration Criacao

No CLI, é preciso ir ao diretório do projeto onde a classe do contexto está definida e informar o comando:

dotnet ef migrations add Criacao

Se estiver trabalhando com um projeto arquitetado em camadas de várias soluções, é necessário informar o nome do projeto em que está a classe do Contexto, por exemplo:

Add-Migration Criacao -Project Estoque.Infrastructure.Data

Pasta onde as migrações serão criadas
  • Aplicando a migração na base de dados

Para fazer surtir efeito da migração, ou seja, a criação do modelo físico e posteriores mudanças nesse modelo, como inclusão/remoção de colunas e tabelas, iremos utilizar o comando:

No PMC: Update-Database

No CLI: dotnet ef database update

Como nosso modelo de entidades é simples, tendo apenas duas classes e uma relação One-to-Many, o efeito da migração é a criação de uma estrutura de apenas duas tabelas que correspondam a este modelo.

Classes do Modelo
Tabelas criadas após aplicar a migração

Relacionamento One-to-Many

  • Criação da classe de Categoria
Classe de Categoria
  • Associando com Produto
Classe de Produto
  • Alterando o Contexto da aplicação

Padronizando o retorno da camada de dados

  • Retorno dos métodos

O retorno dos métodos dentro do repositório será padronizado como bool, pelo fato de que queremos saber se a execução de determinada operação terminou em sucesso ou falha. Existem outras abordagem para utilizar isto, mas para simplificar nossa aplicação vamos fazer uso desse recurso, bem como da passagem por referência out.

  • Modificador de parâmetro “out”

A palavra-chave out faz com que os argumentos sejam passados por referência. Ela torna o parâmetro formal um alias para o argumento, que deve ser uma variável. Em outras palavras, qualquer operação no parâmetro é feita no argumento. Em diversos momentos, no repositório de Produtos, utilizamos esse recurso quando queremos carregar os dados em determinado objeto ou coleção, contudo retornando outro tipo de dado, que nesse caso é bool, pela padronização de retornos. O Controlador, que requisitou ações do Repositório, recebe os objetos informados por referência ao mesmo tempo que tem o retorno da ação true ou false, informando o resultado esperado pela execução de determinado comando.

  • Eager Loading (Carregamento rápido)

O carregamento rápido é o processo pelo qual uma consulta para um tipo de entidade também carrega entidades relacionadas como parte da consulta e é obtido pelo uso do método Include().

Isso significa que a solicitação de dados relacionados seja retornada junto com os resultados da consulta do banco de dados.

No caso da entidade Produtos, temos um relacionamento com Categoria, e o uso de Include(p => p.Categoria) faz com que os dados da categoria relacionada ao produto que estamos pesquisando seja retornado junto com ele, evitando um novo acesso à base se quiséssemos buscar essa informação numa futura ação do usuário ou do sistema, por exemplo.

Ajustando o Controlador de Produtos

O controlador de produtos criado na parte I deste tutorial estava disponibilizando o retorno das chamadas aos endpoints de maneira específica, ou seja, retornando um tipo de dado como coleção de produtos. Entretanto, quando temos vários tipos de retorno possíveis, é comum utilizar um ActionResult com um objeto ou coleção de objetos, ou juntar uma mensagem e código de retorno ao que é devolvido pelo endpoint. O IActionResult ou oActionResult<T> são ótimos retornos disponibilizados pelo .NET Core MVC para trabalharmos em nossa API.

Logo abaixo temos o código do controlador de produtos e em seguida cada seção explicando as alterações realizadas:

Controlador de produtos refatorado

Versão

Vamos colocar a anotação [Route(“{version}/api/produtos”)] que representa a rota para o controlador de Produtos. Cada um dos métodos que representarão os endpoints de acesso a esta API terá apenas o nome da terminação que caracteriza o método

Ajustando ao retorno da camada de dados

A interface do repositório que será acessado pelo controlador de produtos está definida segundo estas assinaturas:

Interface do repositório de produtos

Esta abordagem permite que retornemos uma flag do tipo bool para o controlador, indicando que a operação concluiu com sucesso ou falhou. Dentro do controlador iremos implementar uma lógica para tratar esse retorno. Nos parâmetros dos métodos iremos informar o modificador de parâmetros “out” indicando que necessariamente, quem implementar este método irá instanciar o parâmetro recebido para que fique disponível para a classe demandante sem a necessidade de retorná-lo explicitamente.

Por exemplo, o controlador de produtos está invocando o método GetProduto(int, Produto) do repositório, indicando a passagem por referência da variável Produto produto e fazendo uso dela, retornando dentro do método Ok().

Enquanto no repositório temos o método GetProduto() implementado para usar o DBSet de Produto, no contexto da aplicação, para buscar o produto que tenha a mesma chave primária e atribuir ao parâmetro recebido enquanto retorna se a operação foi sucesso ou falha.

ActionResult

Principais formas de retorno dos métodos de uma API

Os tipos ActionResult representam vários códigos de status HTTP. Qualquer classe não abstrata derivada de é ActionResult qualificada como um tipo de retorno válido. Alguns tipos de retorno comuns nessa categoria são BadRequestResult (400), NotFoundResult (404), OkObjectResult (200) e CreatedResult(201). Como alternativa, os métodos de conveniência na ControllerBase classe podem ser usados para retornar ActionResult tipos de uma ação. Por exemplo, return BadRequest(); é uma forma abreviada de return new BadRequestResult();

A vantagem do ActionResult <T> é que o tipo de retorno da função é claro, facilitando a legibilidade e entendimento da API. Os endpoints do controlador de produtos, foram alterados para essa abordagem. Por exemplo, o método GetProduto() alterado para retornar um ActionResult<Produto> e responder de acordo com o resultado da chamada ao repositório.

Documentando a API

A documentação da API é uma forma de fornecer, de maneira prática, uma visualização dos endpoints mapeados por cada controlador, junto com suas especificações: o verbo HTTP utilizado, a URL, os parâmetros no corpo da requisição ou na URL, etc.

Utilizaremos o Swagger para criar uma interface visual dos endpoints dessa API, para isso será necessário instalar o pacote Swashbuckle.AspNetCore, via NuGet, que irá rastrear os controladores e os métodos implementados. Lembrando que utilizamos o .NET Core 3.1 nesse exemplo.

Depois de instalado o pacote do Swashbuckle, precisamos abrir a classe Startup.cs e fazer duas alterações bem simples no método +Configure() e +ConfigureServices() informando que utilizaremos o Swagger.

Método +ConfigureServices()

Startup.cs +ConfigureServices()

Método +Configure()

Startup.cs +Configure()

Feito isso, agora é só rodar a aplicação, abrindo o Powershell ou Cmder no diretório da API e digitando o comando dotnet watch run. O Swagger irá rodar na URL http://localhost:5000/swagger/index.html.

Documentação da API com Swagger

--

--