Quem trabalha com programação de computadores fazendo CRUD, no geral não tem que lidar com questões sobre de redes de computadores. Na verdade, o conhecimento necessário sobre esse tema precisa ser mínimo para construir soluções para muitos problemas que podem ser resolvidos com um sistema de software, como uma API Rest sobre HTTP. Claro, à medida que sistemas de software crescem e passam a ser cada vez mais acessados, o gerenciamento dessas questões ganha um papel relevante. Mas, para o que quero apresentar, não, conhecer redes não é estritamente necessário. Por exemlo, para uma aplicação Java com Spring Boot, em poucos minutos é possível montar uma API Rest e rodá-la localmente. Além de saber configurar o computador na rede WiFi, não são necessários conhecimentos de rede mais relevantes que isso.
Padrões
Recentemente me deparei com algumas APIs web bastante complicadas. Elas disponibilizam diversos endpoints para realizar tipos de consultas específicas para cada cenário do sistema. A utilização de padrões do HTTP também não muito bem definida. Com isso, buquei algumas soluções de mercado que resolvem os problemas de filtragem de dados sobre API web.
Encontrei algumas soluções que apresento a seguir.
Query Parameters
Usar parâmetros de consulta (query parameters) é uma abordagem comum e direta para filtragem. Este método permite que os clientes da API passem parâmetros de filtro diretamente na URL. Um problema dessa abordagem é que a API deve ser programada para tratar cada um dos parâmetros de maneira apropriada.
Quem constrói API, mesmo nos níveis mais iniciais até mesmo de turoais ou cursos online, vai lidar com isso em algum momento.
Exemplo:
GET /api/funcionarios?nome=Pedro&idade=30&cidade=São Luís
RSQL (RESTful Service Query Language)
Essa abordagem me pareceu bastante flexível, permitindo a construção de consultas complexas para APIs. É baseada no conceito de filtros e operadores que são passados na URL da requisição, originado no padrão FIQL (Feed Item Query Language (Contextual Query Language).
O parâmetros de consulta podem ser passados na URL e, assim, não diferem muito de simples query parameters. No entanto, adiciona operados lógicos como and, or, ==, !=, etc. O servidor deve ser capaz de traduzir dinamicamente o filtro para o modelo de dados real utilizado internamente na implementação da API, como u m SQL para banco de dados relacional, por exemplo.
- Uma implementação para Java: https://github.com/jirutka/rsql-parser
- Utilização de RSQL com Spring Boot e JPA de maneira dinâmica: https://www.baeldung.com/rest-api-search-language-rsql-fiql
Exemplo:
GET /api/funcionarios?$filter=nome eq 'Pedro' and idade > 30 and cidade == 'São Luís'
OData (Open Data Protocol)
OData é um padrão de protocolo que permite a criação e consumo de APIs RESTful. Ele fornece um conjunto de operações de consulta e filtros que podem ser aplicados aos recursos.
- Tem um site sobre OData: https://www.odata.org/
Exemplo:
GET /api/funcionarios?$filter=nome eq 'Pedro' and idade ge 30 and cidade eq 'São Luís'
JSON:API
Esta é uma especificação para a construção de APIs que utiliza JSON como formato de transferência de informações. Ele define um padrão para filtragem de recursos usando parâmetros de consulta.
- Também tem um site sobre JSON:API: https://jsonapi.org/
GET /api/funcionarios?filter[nome]=Joao&filter[idade]=30&filter[cidade]=SaoPaulo
GraphQL
GraphQL permite que os clientes definam a estrutura da resposta e também fornece capacidades avançadas de filtragem. Este padrão já bem estabelecido e bastante usado. Existem implementações para diversas linguagens e integração com os frameworks mais famosos.
- O site do GraphQL é o mais bonito de todos: https://graphql.org/
Exemplo:
query {
funcionarios(filter: {nome: "Joao", idade: 30, cidade: "SaoPaulo"}) {
id
nome
idade
cidade
}
}
ElasticSearch DSL
ElasticSearch fornece uma DSL (linguagem de domínio específico) baseada em JSON para consultas complexas.
- Mais informações: https://elasticsearch-dsl.readthedocs.io/en/latest/
POST /api/funcionarios/_search
{
"query": {
"bool": {
"must": [
{"match": {"nome": "Joao"}},
{"range": {"idade": {"gte": 30}}},
{"match": {"cidade": "SaoPaulo"}}
]
}
}
}
HAL (Hypertext Application Language)
HAL é uma especificação de formato de hipertexto que define uma maneira de incorporar links e dados relacionados diretamente nas respostas de API.
- Mais informações: https://en.wikipedia.org/wiki/Hypertext_Application_Language
- Rascunho da definição do padrão: https://datatracker.ietf.org/doc/html/draft-kelly-json-hal-11
Exemplo:
GET /api/funcionarios?nome=Joao&idade=30&cidade=SaoPaulo
Uma resposta típica em formato HAL tem formato parecido com o que segue:
{
"_embedded": {
"funcionarios": [
{
"id": 1,
"nome": "Joao",
"idade": 30,
"cidade": "SaoPaulo",
"_links": {
"self": {"href": "/api/funcionarios/1"}
}
}
]
},
"_links": {
"self": {"href": "/api/funcionarios?nome=Joao&idade=30&cidade=SaoPaulo"}
}
}
Implementação
Dentro do contexto da construção de software, reinventar a roda quase sempre é ruim. Boa parte do esforço na construção de qualquer sistema é aplicado em problemas específicas do problema que se deseja resolver. Com isso, usam-se frameworks, bibliotecas e padrões já estabelecidos para resolver a maioria das outras necessidades.
Para implementar um sistema de filtragem em uma API REST também não é diferente. Um passo importante na escolha do padrão a ser seguido é verificar se ele tem alguma implementação para a linguagem e/ou framework que está sendo utilizado. A falta de uma biblioteca que já implementa o padrão de maneira eficaz pode ser um importante fator na escolha.
No entanto, padrões que adicionam rigidez excessiva também não são bons. O esforço para construir um software do zero é bem pequeno se comparado ao esforço para dar manutenção e voluir esse software. Nesse sentido, um padrão flexível é crucial.
Mas a beleza dos padrões desse tipo é que, quando adotados, quando são definidos e/ou mantidos por entidades internacionais, sempre vai existir uma comunidade que utiliza, documentação, respostas em fóruns, e implementações prontas para as principais linguagens e frameworks.
Conclusão
Após essa análise, fiquei interessado no simples e direto RSQL. Sou programador Java há um bom tempo e consigo imaginar algumas formas de integrar uma solução desse tipo dentro de um framework como Spring Boot. Dentro de um contexto onde é necessário apenas adicionar recursos de filtragem em uma API, RSQL realmente parece uma boa alternativa.
No entanto, fica claro que os padrões existem. É sempre importante considerar a familiaridade da equipe de software que vai lidar com a implementação desses padrões, e também a aderência dele para a tecnologia utilizada na construção dos sistemas. Sempre avalie bem a ideia de implementar alguma solução do zero.