Implementando o uso de contratos na API

Marcio Nizzola
5 min readFeb 24, 2020

--

Dando sequência num projeto iniciado na aula da Etec Itu, achei interessante criar uma explicação sobre o uso de contratos na nossa API.

Vimos na aula anterior o uso do Swagger para criarmos a documentação da API, agora daremos um pouco mais de profissionalismo para a aplicação.

Para começar, vamos falar sobre o que são “Contratos” ?

Um contrato de API é um documento que é um acordo entre equipes diferentes sobre como a API é projetada. Atualmente, a forma mais comum de contrato de API é uma Especificação OpenAPI, um formato de descrição neutro, portátil e aberto, que padroniza como as APIs REST são descritas. O Swagger é um conjunto de ferramentas de código aberto criadas em torno da Especificação OpenAPI que podem ajudá-lo a projetar, criar, documentar e consumir APIs REST.

Mas de quem é a responsabilidade de definir e especificar um Contrato de Api ? Isto pode variar de empresa para empresa, mas normalmente caso esteja criando uma API do zero, é comum que a equipe de desenvolvimento realize a especificação, já em casos onde a API nasce para integração entre um ou mais sistemas, é comum que as partes entrem em um acordo sobre a melhor forma de criá-la para que atenda à ambas as equipes.

Então para quem nunca utilizou, como podemos definir um contrato?

Para quem ainda caminha neste mundo das API´S, segue uma visão de um exemplo de uma API de cadastro de Produtos, onde o método POST requer o preenchimento de um objeto:

Vocês podem notar que este objeto, possui campos que não fazem sentido para quem está integrando uma informação:

  • o campo da chave primária não deve ser enviado no método POST que faz a inclusão, já que a mesma é gerada pela API.
  • o campo da data da inclusão não deveria ser enviado também, já que a própria API irá inserir a data conforme a hora em que foi enviado.
  • já o campo da data da alteração menos ainda, pois o mesmo só será preenchido ao utilizar um método de alteração.

Então é aí que entram os contratos ! Devemos criar uma pasta no projeto para armazenarmos os contratos, normalmente criamos uma pasta para os “Request” (requisições enviadas), e o “Response” (respostas da API), então crie as pastas conforme a imagem abaixo, e depois crie uma classe na pasta “Requests” chamando-a de “ProdutoCreateRequest” (peço calma aos colegas mais ortodoxos, não ficou legal nomear as classes em português, mas o foco aqui é apenas entender o conceito e já tive alunos confusos com nomes em inglês).

Se olharmos a nossa classe de produtos, ela foi construída assim:

[Table("Produtos")]public class Produto{  [Key]  public int ProdutoId { get; set; }  [MaxLength(100, ErrorMessage = "O campo {0} não pode ultrapassar {1} caracteres")]  public string Descricao { get; set; }  public UnidadeDeMedidaEnum UnidadeDeMedida { get; set; }  public Decimal ValorDeCusto { get; set; }  public Decimal MargemDeLucro { get; set; }  public Decimal ValorDeVenda { get; set; }  public DateTime DataCadastro { get; set; }  public DateTime? DataAlteracao { get; set; }  public bool Ativo { get; set; }}

Veja que a propriedade UnidadeDeMedida é do tipo “Enum”, abaixo segue o seu código fonte:

public enum UnidadeDeMedidaEnum{  UNDEFINED,  CX,  UN,  MT,  KG,  DZ}

Criada a classe, devemos então monta-la com os elementos que queremos que sejam enviados pelo consumidor da API para envio de um novo produto.

public class ProdutoCreateResponse{public string Descricao { get; set; }public string UnidadeDeMedida { get; set; }public Decimal ValorDeCusto { get; set; }public Decimal MargemDeLucro { get; set; }public Decimal ValorDeVenda { get; set; }}

Vejam que vários campos da classe produto foram suprimidos, ficando assim muito mais compacto o seu uso.

Outro tópico interessante é o que foi feito com o campo Unidade de Medida, onde o campo passou a ser do tipo String, ao invés de Enum para ser mais fácil de ser identificado pelo consumidor do serviço.

Então é isto, fizemos a classe, porém, ao devolver os resultados para os clientes, temos que fazer uma transformação da classe “Produto” para a classe “ProdutoCreateResponse”, então podemos fazer de várias formas distintas:

Com utilização de métodos (podendo ser um método de Extensão da classe produto), ou com um mapeamento através do AutoMapper, ou simplesmente copiando propriedade por propriedade para a nova classe.

Exemplo com Extension Methods

Criando um extension method (vide artigo), você pode extender a classe “Produto” e implementar um método que devolva um objeto do tipo “ProdutoCreateResponse”.

public static ProdutoCreateResponse ConverteParaResponse(this Produto prod)
{
ProdutoCreateResponse response = new ProdutoCreateResponse();
response.Descricao = prod.Descricao;
response.MargemDeLucro = prod.MargemDeLucro;
response.UnidadeDeMedida = prod.UnidadeDeMedida.ToString();
response.ValorDeCusto = prod.ValorDeCusto;
response.ValorDeVenda = prod.ValorDeVenda;
return response;
}

Depois de criar o “Extension Method”, agora é só utilizá-lo na nossa controller, conforme demonstrado abaixo:

Exemplo com AutoMapper

Instale a biblioteca do Automapper, através do Nuget Package Manager ou pela linha de comando no Package manager Console:

Install-Package AutoMapper

Tendo instalado o Automapper, é necessário criar o mapeamento “de-para” das classes que deseja utilizar, no arquivo startup.cs, você deve incluir o mapeamento.

Neste projeto que é algo simples, fizemos no startup, mas o correto é criarmos uma classe específica para este mapeamento para que deixemos o Startup mais clean e que a manutenção do projeto fique mais limpa.

Agora é só chamar o Automapper na nossa controller.

Portanto agora é só escolher a melhor forma de utilização e seguir em frente, nem tudo são flores, sempre temos situações específicas que irão requerer configurações diferentes do padrão, mas para isto deixo aqui as referências para que possam aprofundar-se mais nesse assunto.

Gostou do artigo? clique no ícone👏e me siga para ver as próximas publicações !!

Referências:

--

--

Marcio Nizzola
Marcio Nizzola

Written by Marcio Nizzola

Microsoft MVP | Software Architect na CI&T | Prof. da Etec Itu | Membro Fundador da Comunidade Itu Developers.

No responses yet