APIs REST não são bancos de dados

APIs REST não são bancos de dados
Tempo de Leitura: 5 Minutos

Um dos erros comuns que os desenvolvedores cometem em relação às APIs REST é tratá-las como bancos de dados, e não são! Basta olhar qualquer documentação de estrutura da web e, em algum momento, você encontrará uma maneira mágica de mapear as operações CRUD do banco de dados de modelos ORM com endpoints da API REST. Cada letra de CRUD se torna verbos HTTP, temos que admitir que essas operações se combinam naturalmente, o que justificaria combiná-las, porém, o problema começa quando os desenvolvedores começam a associar APIs REST com conceitos de banco de dados e perdem o ponto principal, que é o conceito da arquitetura RESTful. Este artigo tem o objetivo de desmistificar isso.

Primeiro, vamos entender o conceito básico de cada um, o objetivo dos bancos de dados é o mais simples do mundo armazenar dados, e das APIs é tratar o modo como os componentes interagem entre si. Um problema em usar a API como uma interface de banco de dados é que se você construir uma API em torno deste conceito há uma grande chance de com o tempo, ela se tornar ambígua e difícil de manter, porque é justamente isso que acontece naturalmente com os banco de dados.

REST significa em uma tradução livre (RE represent,  S state,  T Transfer) ou Apresentação do Estado de Transferência. Você pode interpretar literalmente que significa que quando você faz REST, você transfere o estado de algo por meio de algum protocolo e HTTP é a escolha mais comum. Entenda por “algo” que obtém seu estado transferido também é conhecido como um “recurso”. E o “estado” é como uma foto instantânea do recurso. O recurso pode ser mapeado diretamente para um modelo ORM, porém  pode ser muitas coisas além disso é muito comum que alguns recursos sejam uma compilação de dados somente leitura, e não uma única fonte de dados.

Um jogo mental interessante para dissociar APIs REST de conceitos de banco de dados é imaginar como você criaria pontos de extremidade para um recurso “tempo” . Certamente o “tempo” não precisaria existir no banco de dados, mais você ainda pode ter uma API que trata de objetos temporais e usar GET para ler a hora atual, você também pode usar POST para criar um apontamento para datas futuras adicionando dias a outras datas, retornar um dia da semana para uma determinada data, ou se a data é válida para uma determinada transação, como dia util ou fim de semana, entre uma centena de outros recursos tudo sem necessidade de um banco de dados.

Então, como as APIs REST devem ser construídas?

Crie APIs em torno de contextos de usuário, imagine uma API que é consumida de maneiras muito diferentes por cada usuário. Por exemplo, uma empresa de transporte que possui uma API com um recurso de Remessa, ela será vista de formas diferentes por um Comprador, um Vendedor e uma empresa de Transporte, porém, uma API esses usuários têm visualizações do recurso Remessa e precisam fazer diferentes operações na API, porém os mesmos recursos estão disponíveis e atendem a contextos diferentes. O comprador deseja pagar e rastrear a remessa. O vendedor, por outro lado, está preocupado apenas com o tempo de retirada e o prazo de transporte. A transportadora se preocupa com as dimensões e o peso do pacote e sua origem e seu destino.

Se você construir esta API como uma solução única para esses três usuários, você terminará com uma API ambígua e sobrecarregada diretamente atrelada aos dados e que será difícil de evoluir, difícil de manter e que deixará exposto mais dados do que deveria para os contextos de usuários. Nesse caso, você deve construir três APIs especializadas, uma para cada contexto de usuário. Por causa do alto acoplamento no nível de dados, essas três APIs devem viver em um mesmo projeto, a maioria dos frameworks web modernos oferece suporte a subdomínio ou roteamento de prefixo, e implementá-lo não é um problema . Pode parecer muito trabalhoso, mas com o tempo vai valer a pena.

Uma alternativa aos contextos seria implementar permissões ou algum tipo de controle de acesso na API. Estou um pouco desconfiado dessa abordagem, pois ela adiciona complexidade desnecessária na minha opinião.

Quando os contextos não são possíveis

Se uma API tem tantos usuários que torna impossível ter contextos, a coisa certa a fazer é aceitar essa realidade e abraçá-la, mas fazer o seu melhor para ajudar os usuários da API. Por exemplo, você pode usar tecnologias como GraphQL para capacitar os usuários sobre o que eles pedem e obtêm da API. Esse pequeno controle pode fazer toda a diferença.

Mas se suas APIs são pequenas, pare de complicar as coisas. Há uma relação direta entre tamanho e escopo, quanto menor for uma API, menos escopo ela tem. Você pode mantê-la simples e fazer suas operações CRUD mapeadas para terminais REST. Mas fique de olho em como isso evolui, se você estiver enchendo o código da API com condicionais e outros tipos de patch, considere que é hora de criar uma segunda versão seguindo as abordagens acima.

Considerações

Quando você pensa em uma API diretamente mapeada para operações CRUD, muitas vezes você acaba adicionando complexidade desnecessária, em algum contexto, imagine o caso acima da API de REMESSAS, sendo fornecida pela empresa de TRANSPORTES X, como um serviço para calculo de fretes e contratação por parte de consumidores e de empresas, se você mapear diretamente uma operação CRUD por exemplo para um POST muito provavelmente serão necessários dados sobre tamanho e peso da encomenda já direto na hora que o consumidor realizou a compra da sua mercadoria e excolheu o frete da TRANSPORTES X. O vendedor, vai saber quanto o USUÁRIO pagou pelo serviço da TRANSPORTE X e exatamente qual a modalidade de transporte usada, sendo que ele só precisaria saber quando a encomenda será retirada em sua empresa.

Nesta situação, muito provavelmente uma chamada a um PATCH tem um enorme potencial de ser necessária, para ajustar o tamanho exato da embalagem, e dados de retirada disponibilizados, o que gera maior consumo de recursos e muitos outros problemas. Tratar cada contexto em um universo diferente vai gerar muitos benefícios e economia de recursos.

Romeu G.

Engenheiro de Software, especializado em Redes de Computadores desde 1995 sou amante de linguagens de programação, robótica e softwares embarcados.

Deixe um Comentário