JSON além do CRUD — Restfull, GraphQL
Primeiro aprendemos a utilizar o recuso
Utilizamos o http para retonar json, fazendo GET realizávamos todas as operações de um crud.
Segunda onda de aprendizado — verbos
Na primeira onda de aprendizado, aprendemos a utilizar os verbos do http para fazer as requisições de maneira mais semântica, aprendemos que o GET retorna os dados, DELETE apaga, PUT atualiza todos os dados, PATCH atualiza parte dos dados, POST cria novos dados
Terceira onda de aprendizado — metadados
Em uma segunda leva de aprendizados, adicionamos metadados no retorno, abaixo temos uma imagem que lista usuários.
Permitimos que o usuário da nossa API além de poder utilizar o post para criar os dados, no header de retorno adicionamos informações extras, como o location, para dizer onde o cliente pode recuperar os dados inseridos
Ao utilizar o POST poderia customizar um header informando que a aplicação deve exibir um alerta com os parâmetros informados, abaixo você vê um código em Java criando este header.
Ao realizar o DELETE, é interessante passar no retorno um Header identificando a informação excluída, no caso da imagem abaixo vemos o Entity =3
Também se deve utilizar os códigos HTTP para informar o cliente, por exemplo, ao fazer um POST e não enviar os dados necessários, podemos retornar um 400 (Bad request) e no corpo uma mensagem de erro.
Sempre que possível utilize o código mais específico, como o 422 (Unprocessable Entity) para o caso de enviar todos os atributos necessários, mas com o valor no formato errado como um e-mail inválido por exemplo.
Pode ser interessante enviar um array de erros para que o front (cliente) não precise fazer várias requisições e descobrir as diversas possibilidades de erros, um a um. Desta maneira em uma única requisição é possível exibir todos os erros ou validações que o front-end developer precisa programar, melhorando a experiência do usuário. Neste caso, é comum utilizar apenas o código 400.
Ao utilizar query parameters, você pode indicar para a aplicação que faça algo, a baixo você vê um exemplo que indica que o POST deve ser processado em background. Neste caso o retorno é um 202 (accepted), indicando que foi aceito, mas o processamento não está completo.
Neste caso, ao usar o quer parameter para indicar que o processamento deve ser em background, pode ser interessante utilizar o que conhecemos como Service callback ou callback rest, na prática sigfica que você enviará na requisição uma url de retorno, que será chamado quando o processamento acabar, você pode enviar como query parameter, ou no payload.
Query params também são encontrados em casos de paginação, filtro de consultas, autenticação utilizando tokens. Lembra dos metadata? Você poderá encontrá-los nos casos de filtros e paginação, indicando a página atual, tamanho da página, quantidade total de registros disponíveis.
Também, apendemos a utilizar os parâmetros para informar que queremos partes dos dados, a url seria algo +/- assim:
/pedidos/codigo_do_pedido?fields=numero,data,valor
Isto, nos leva ao rsql, sim uma forma de definir queries na url a fim de filtrar os dados, você poderia por exemplo, ter uma url pedindo o filme Kill Bill com ano maior que 2003 assim:
/movies?query=name==”Kill Bill”;year=gt=2003
E o JHipster nos apresenta uma alternativa ao RSQL, ele nos entrega uma classe chamada QueryService, que visa oferecer filtros através da url, o programador mais purista pode não gostar desta alternativa devido ao código que acaba sendo gerado, cheio de ifs. Mas lembre-se que inicialmente toda as classes para permitir este tipo de consulta é gerada, você terá de botar a mão apenas em caso de customizações, e terá de lembrar de desligar a verificação para estas classes no seu SonarQube para não reclamar da complexidade ciclomática.
Exemplo de consulta que você pode fazer com a solução do JHipster:
/grupos?id.greaterThan=5&attr1.contains=something&attr2.specified=false
Quarta onda de aprendizado — HETEOS
Agora, ao invés de trazer um array das informações complementares, tornando o JSON gigantesco, retornamos a url de onde o cliente pode recuperar as informações caso necessário, você pode dar uma olhada na PokemonAPI abaixo, onde você tem a consulta pelo id 1 que é o bulbasaur, mas se desejar saber detalhes da habilidade chlorophyll, você terá de fazer outra requisição na url indicada. Outra fonte interessante na internet é a StarWars API.
Esta estratégia permite um “Lazy loading” das informações, melhorando a experiência do usuário, legibilidade do json, porém tende a demorar mais pra implementar e necessita alguns neurônios a mais planejanto a API.
Considere também o dispositivo que está requisitando este json, caso você esteja em um smartphone, HATEOAS tende a gastar mais bateria.
É possível utilizar o query parameters para indicar, se quer o retorno no padrão HATEOAS ou o json completo, com todas as informações.
Assim, conseguimos alcançar no nível 3 de Maturidade de Richardson, sendo considerado RESTful.
Controle de Transação
A abordagem usual é isolar esses microservices o máximo possível — tratá-los como unidades únicas. Em seguida, as transações podem ser desenvolvidas no contexto do serviço como um todo (ou seja, não fazem parte das transações DB comuns, embora você ainda possa ter transações DB internas no serviço)
Há alguns métodos para se fazer isto, mas o caso que acredito ser mais coerente, é o método do voto.
Método do voto — A ideia é ter uma máquina de estado gerenciando o estado da transação, de maneira que esta máquina receba um ou mais votos, confirmando que os dados foram processados, quando todos os votos forem feitos, a transação está confirmada, se algum voto faltar, ocorrerá o timeout e a transação muda para o estado de rollback.
O voto pode ser negativo, ou seja informando que não foi possível realizar a operação desejada. Alguns estados que você pode encontrar, EM_PROCESSAMENTO, CONFIRMADO, ERRO, TIMEOUT.
Quanto mais microserviços envolvidos, mais votos, mais complexidade para implementar.
Restcallback, ou servicecallback cai muito bem neste caso, pois ao enviar uma chamada para um microserviço pode ser que você deseje informar qual é o endereço que ele irá retornar, chamando-o para confirmar ou cancelar a transação.
Você pode derivar esse conceito em SAGA, Orquestração e Coreografia.
Recomendações
- RESTfulAPI —bom para expor serviços para fora da sua rede interna, para terceiros consumir;
- GraphQL — Diretamente relacionado com SPA e dispositivos móveis ou App nativo;
- Binary protocols (gRPC,…) — Excelente para comunicação na rede interna, entre diversos micro serviços;
- Messaging interfaces — necessário para suportar o EDA e implementar comunicação assíncrona e invocações de serviço sem bloqueio.
E depois disto, oque o mercado tem feito e para onde tem evoluído?
GraphQL
Principais características
- Linguagem de consulta
- Filtragem de dados
- Backend e Fontend
Falcor (tanto no front quanto back)
Principais características:
- Modelo único
- Os dados são a API
- Backend e fontend
resQL
Projeto brasileiro, criado pela B2W que implementa uma linguagem de consulta, que pode ser utilizado em uma aplicação existente. Posso estar enganado, mas esta me parece ser uma opção para aplicações construídas sem RXJS, pois os problemas que ela se propõe resolver, são resolvidas com RXJS no front ou no back.
Recomendação de leitura
Introdução ao JSON (Português)
Conhece algo que possa agregar ao assunto? Compartilhe para que eu também possa aprender :)
Referências
https://blog.goodapi.co/rest-vs-graphql-a-critical-review-5f77392658e7
https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-design
https://developer.twitter.com/en/docs/api-reference-index
http://soapatterns.org/design_patterns/atomic_service_transaction
https://stackoverflow.com/questions/30213456/transactions-across-rest-microservices
https://dzone.com/articles/rest-callbacks
https://github.com/WhiteHouse/api-standards
https://www.youtube.com/watch?list=PLz_YTBuxtxt4mPj7VncW1iRJyYUKKGsDt&v=5I56m9o4TvI