Níveis de maturidade de uma API REST
Por Guilherme Forte
No quadrinho acima, visualizamos uma representação da comunicação entre dois softwares, e APIs são exatamente uma das maneiras mais utilizadas hoje para a comunicação entre sistemas. API vem de Application Programming Interface (Interface de Programação de Aplicação) e pode ser utilizada em qualquer contexto de desenvolvimento de software quando se quer que um aplicativo se comunique com outro através de uma interface.
Agora em um contexto WEB onde a comunicação ocorre através da internet temos as famosas APIs REST que não deixam de ser APIs, porém utilizam o protocolo HTTP como meio de comunicação e sua criação segue o modelo de arquitetura REST (Representational State Transfer – Transferência de Estado Representacional ), que nada mais é do que um conjunto de restrições usadas na construção de uma API desse tipo.
Mas quando se dá início no desenvolvimento de uma API REST, você já pode ter se perguntado, como estruturar os endpoints para escalabilidade, organização e garantir que a ela esteja utilizando os conceitos REST para evitar problemas como:
- Má utilização das ações HTTP, que podem gerar lentidões;
- Aumento de complexidade no código devido à má organização e tratamento de lógica para endpoints únicos, gerando custo maior no desenvolvimento e dificuldade de manutenção no código;
- Dificuldade de compreensão da estrutura para quem vai consumir API;
- Utilização de mais recursos de infraestrutura de forma desnecessária.
É preciso conhecer os níveis de maturidades existentes e aplicar seus conceitos garantindo que a API atinja a maturidade mais elevada, para assim ser considerada uma API REST rápida, robusta e escalável agregando muitos benefícios a arquitetura onde está sendo implementada.
Níveis existentes de uma API REST
Uma API pode ter 4 níveis de maturidade, sendo o mais baixo o nível 0 onde mais códigos serão escritos, mais desorganização será encontrada, mais recursos serão utilizados para mantê-las, tendo possíveis problemas durante as requisições, seguindo até o nível 3 onde a API estará completamente organizada trazendo informações que ajudarão seu consumidor entender a estrutura dos recursos disponíveis.
Usando o conceito de abstração da orientação a objetos, entende-se que podemos abstrair qualquer item do mundo real, sendo ele físico ou virtual, para uma classe, com funções e atributos que a represente. Um recurso nada mais é que um objeto abstraído em uma API. Todo substantivo abstraído em forma de classe é considerado um recurso em uma API e da mesma forma que organizamos nosso código utilizando boas práticas, como SOLID e o clean CODE, devemos pensar a melhor forma de disponibilizar os recursos de uma API, considerando o crescimento e o as necessidades das aplicações que irão consumi-la.
A seguir iremos passar por cada fase de maturidade de uma API REST.
API REST Maturidade 0
Na API com nível mais baixo de maturidade encontramos apenas um verbo a ser utilizado como tipo de operação, o POST. Todas as URLs criadas sendo elas para ações de obter dados, atualizar dados, inserir e deletar são chamadas usando o POST. Outro ponto interessante nesse nível é que apenas existira uma URL publicado para acesso a API. Então caso seja feita uma requisição para obter todos os usuários de um aplicativo, teríamos o seguinte exemplo:
Da mesma forma caso a requisição realizada para essa API seja com a finalidade de inserir um novo cliente a URL utilizada seria a mesma, trocando alguns parâmetros onde o programador teria que garantir no desenvolvimento, que os processos requisitados fossem devidamente recebidos. Exemplo da URL para inserir usuários:
O problema de uma API nesse nível é que para operações simples se faz necessário a criação de muita documentação, pois além da falta de clareza sobre a estrutura e suas relações, os comandos são personalizados na URL. Existindo vários recursos disponíveis nessa API, o código e a escalabilidade dela pode ficar inviável no futuro, sem falar que o desenvolvedor irá ter mais trabalho para controlar o que deve ser feito dependendo da requisição solicitada.
Também poderá ser encontrado um tráfego maior de dados desnecessários, se a codificação não garantir corretamente como os dados devem ser entregues e isso pode influenciar muito na arquitetura, gerando lentidão e uma escalabilidade de recursos desnecessária caso a API REST esteja na nuvem.
API REST Maturidade 1
Nesse nível de maturidade as APIs se tornam mais organizadas. Uma URL é criada para cada recurso que será consumido. Um exemplo de URL nesse nível de maturidade pode ser visto abaixo:
Da mesma forma caso a requisição seja apenas para obter os dados específicos de um recurso a URL muda adicionando o identificador daquele recurso no final, como no exemplo:
Caso exista uma relação desse recurso com um sub recurso, teríamos o seguinte exemplo de endpoint:
Segundo Ian Robinson o nível de maturidade 1: “Combina com o método de lidar com uma complexidade dividindo e conquistando, quebrando um único endpoint com diversos serviços em múltiplos recursos.” (Fowler MARTIN, 2010, Tradução nossa)
Porém nesse nível ainda é utilizado apenas um tipo de operação, o POST. Também é importante garantir nesse nível que os nomes dos recursos estejam no plural, sem letras maiúsculas e utilizando um hífen para separação, como visto nos exemplos acima. Nota-se a existência de recursos raiz e sub recursos, neste caso os sub recursos são recursos que só existem a partir de outro, baseado na regra de negócio do sistema. Um recurso usuário pode ter como sub recurso um dia de treino, nesse exemplo o dia de treino só existe se um usuário existe e o planeja.
É interessante enxergar que nesse nível já podemos ter uma grande redução de problemas na arquitetura, como a remoção de complexidade no desenvolvimento, o que pode inclusive reduzir custos na criação das APIs.
API REST Maturidade 2
Na criação de uma tela de cadastro, é de extrema importância que as operações simples como, criar recurso, atualizar recurso, buscar recurso e deletar recurso sejam implementadas. Nesse nível de maturidade a mesma ideia deve ser utilizada com os verbos HTTP, eles devem ser suficientes para um CRUD (Crate, Read, Update, Delete). Para cada ação de um recurso da API são aplicados verbos diferentes. Dentre as opções disponíveis, baseado na arquitetura REST, as mais conhecidas são as seguintes:
– POST: criação de um novo recurso, quando pensamos no recurso cliente, a ação realizada seria de criar um cliente;
– GET: buscar dados de um ou vários recursos;
– PUT: atualizar um recurso, por inteiro. Se um recurso cliente tem como informações os atributos nome, e-mail, data de nascimento e CPF, ao efetuar uma atualização passando o verbo PUT na requisição a API, todos os atributos do cliente devem ser enviados no corpo da requisição, mesmo aqueles que não serão atualizados;
– PATCH: atualizar um recurso, parcialmente. Seguindo o mesmo exemplo da ação PUT, um cliente com seus atributos, nesse tipo de requisição apenas o atributo desejado será enviado no corpo da requisição. Geralmente para atualização é a ação mais utilizada, pois utiliza menos dados para navegação no tráfego de informação;
– DELETE: remover um recurso. É importante ter-se o conhecimento de que cada recurso tem um identificador único e é esse identificador que deve ser enviado para API como um parâmetro, para que assim a API saiba qual é o recurso exato a ser deletado;
– HEAD: verificar se um recurso existe, evitando o mínimo de tráfego entre a requisição a recomendação do nível de maturidade 2 é a utilização do HEAD. Se o recurso existir apenas no código 200, será retornado informado a sua existência, se não o código 404 será enviado, informando a não existência do recurso;
– OPTIONS: verificar todos os tipos de operações disponíveis para um determinado recurso. Se um recurso tem operações de criação, busca, atualização é nessa requisição que devem-se ser disponibilizadas a informação dessas possibilidades. É importante que o consumidor da API saiba exatamente todas as operações disponíveis para aquele recurso. Assim caso a ação desejada não esteja disponível o desenvolvedor poderá entrar em contato com o criador da API e solicitar que essa operação seja implementada.
Para Ian Robinson nesse nível temos: “Introdução de verbos padrões para lidar com situações similares da mesma forma, removendo variações desnecessárias.” (Fowler MARTIN, 2010, Tradução nossa)
Dessa forma a API fica muito mais legível para manutenções, reduzindo seu custo e passando ser mais fácil de ser consumida. Já se sabe por exemplo que ao fazer um GET é esperado o retorno de dados, e isso ajuda inclusive na performance na transferência de dados.
API REST Maturidade 3
Último nível de maturidade de uma API é atingido quando aplicamos nela o HATEOAS (Hypermedia as the Engine of Application State). Ian Robinson define o nível da seguinte forma: “Introduz a descoberta, promovendo um caminho de deixar o protocolo com uma auto documentação.” (Fowler MARTIN, 2010, Tradução nossa)
Como exemplo podemos imaginar a navegação em um Website, onde um usuário deve saber para onde ele vai ser levado ao clicar em um link disponível na tela, sendo que todos os recursos do website ficam disponíveis para acesso com fácil entendimento para quem está navegando. A mesma ideia ocorre na API com esse nível de maturidade, porém aplicado ao sistema que está consumindo a mesma. Um exemplo seria, ao fazer uma inserção de um recurso teríamos que realizar a ação POST para a URL disponível pela API:
Ao mesmo tempo no corpo dessa requisição, os atributos desse cliente devem ser enviados, no formato requisitado pela API, como nome, idade entro outros necessários.
O retorno dessa API nos níveis anteriores já trazia um status indicando que o novo cliente foi criado e ao mesmo tempo trazia todos os dados desse cliente, junto ao seu identificador único.
Com o HATEOAS aplicado nessa API o retorno também trará todas as ações possíveis para este recurso, junto as relações que este recurso tem com outros recursos e exemplos de como acessá-los.
Uma API no nível 3 de maturidade fornece auto documentação, facilidade de entendimento e reaproveitamento, sendo suficiente para o cliente da API ir navegando e descobrindo os recursos possíveis. Exatamente como um Website informa o usuário sobre os recursos possíveis para a tela que ele está navegando, uma API no nível 3 deve fazer o mesmo para o sistema que a está consumindo.
Afinal em que nível de maturidade construir sua API?
Analisando todos os níveis de maturidade existentes e aplicando todos as práticas para atingi-los, é garantido que construindo uma API com nível 3 de maturidade, ela estará organizada, com os endpoints fáceis de compreender, recursos fáceis de serem encontrados, escalabilidade garantida e uma auto documentação para seus recursos, facilitando assim a vida dos usuários que irão consumi-lá e dos desevolvedores que vão mantê-la. Os conceitos REST estarão aplicados e poderá ser dito de “boca cheia” que ela é uma API REST completa.
Por isso, se está pensando em construir APIs REST para comunicação entre os softwares de sua empresa lembre-se que aplicar corretamente os níveis de maturidade vão ajudar a garantir que a complexidade de seu desenvolvimento e manutenção seja menor, o que afeta diretamente os custos, não apenas da mão de obra como também de infraestrutura, pois uma API madura “quase“ garante o uso dos recursos necessários.
Ainda que uma API madura traga enormes benefícios, fica o aviso que existem alguns sinais de esgotamento dessa tecnologia, como o overfetching e o underfetching. Porém novas tecnologias já existem para resolver esses esgotamentos, como ODATA da Microsoft e o GraphQL do Facebook. Então dependendo das necessidades, considere estudos dos desgastes e tecnologias citados, para assim poder garantir uma arquitetura muito bem estruturada. Mas isso é papo para outro artigo.
Bibliografia
MARTIN, Fowler. Richardson Maturity Model steps toward the Glory of REST. 2010. Disponível em: https://martinfowler.com/articles/richardsonMaturityModel.html
Guilherme Forte é graduado em Gestão da Tecnologia da Informação e especializado em Engenharia de Software. Entusiasta na área de programação, possui mais de 5 anos de experiência profissional e adora aprender novas tecnologias e metodologias de desenvolvimento. No tempo livre, gosta de pegar seu violão e praticar um pouco.