Estratégias Práticas para Limitação de Taxa em APIs GraphQL

January 4, 2024

Technology

A implementação de limitação de taxa em APIs REST é relativamente simples, pois comumente usamos caminhos de URI para representar recursos específicos da API e métodos HTTP para indicar operações sobre esses recursos. A camada de proxy pode facilmente aplicar regras predefinidas de limitação de taxa com base nessas informações.

No entanto, o cenário se torna significativamente mais complexo quando se trata de APIs GraphQL. Vamos explorar como superar esses desafios.

Cenários Simples

Em contraste com as APIs REST, o GraphQL utiliza uma linguagem de consulta proprietária. Ele não depende mais de caminhos e métodos HTTP para recuperação e manipulação de recursos, mas unifica a consulta e operações de dados sob Query e Mutation, onde Query busca dados e Mutation realiza manipulações como criação, atualização e exclusão.

GET /users
GET /users/1
POST /users
PUT /users/1
DELETE /users/1

query { users { fullName } }
query { user(id: 1) { fullName } }
mutation { createUser(user: { lastName: "Jack" }) { id, fullName } }
mutation { updateUser (id: 1, update: { lastName: "Marry" }) { fullName } }
mutation { deleteUser (id: 1) }

Os exemplos acima destacam a mudança nos métodos de consulta de API. Diferente do REST, o GraphQL se assemelha a chamar funções em recursos, passando parâmetros de entrada necessários, com a resposta contendo os dados consultados. Além das diferenças nos métodos de consulta, o GraphQL expõe APIs normalmente através de um único endpoint (por exemplo, /graphql), com consultas e parâmetros de entrada enviados via corpo POST.

Considere o seguinte exemplo:

query {
    users {
        fullName
    }
    photos {
        url
        uploadAt
    }
}

Neste cenário, simulando a página inicial de um álbum, uma chamada de API para o endpoint /graphql consulta simultaneamente as listas de usuários e fotos. Agora, considere se as estratégias tradicionais de proxy reverso, executadas no nível da solicitação, ainda são aplicáveis a APIs GraphQL.

A resposta é não. Servidores de proxy reverso tradicionais não conseguem lidar efetivamente com chamadas de API GraphQL que contêm as próprias consultas, tornando impossível aplicar políticas como limitação de taxa. Para APIs GraphQL, a granularidade de "solicitações HTTP" parece muito ampla.

No entanto, o gateway de API, Apache APISIX, incorpora suporte nativo para capacidades de GraphQL para HTTP. Administradores podem pré-configurar uma declaração de consulta, permitindo que clientes a chamem diretamente através de um POST HTTP sem entender detalhes do GraphQL, apenas fornecendo os parâmetros de entrada necessários. Isso não apenas aumenta a segurança, mas também permite a aplicação de políticas de API HTTP neste contexto.

limitação de taxa

Efetivamente, isso transforma consultas dinâmicas do GraphQL em consultas estáticas fornecidas pelos provedores de API, apresentando vantagens e desvantagens. Às vezes, podemos não querer sacrificar o recurso de consulta dinâmica do GraphQL. Vamos continuar a discussão de outros cenários.

Cenários Complexos

O GraphQL utiliza sua linguagem especializada para modelagem de dados e descrição de APIs, permitindo estruturas de dados aninhadas. Expandindo o exemplo anterior:

query {
    photos(first: 10) {
        url
        uploadAt
        publisher {
            fullName
            avatar
        }
        comments(first: 10) {
            content
            sender {
                fullName
                avatar
            }
        }
    }
    // users...
}

Neste caso, simulando a recuperação das primeiras 10 fotos, incluindo o editor de cada foto e os primeiros 10 comentários com seus remetentes, o serviço de backend deve lidar com consultas envolvendo várias tabelas de banco de dados ou chamadas a microsserviços. Em cenários de consulta aninhada, à medida que a quantidade de dados e os níveis de aninhamento aumentam, o estresse computacional sobre os serviços de backend e bancos de dados aumenta exponencialmente.

Para evitar que consultas complexas sobrecarreguem o serviço, podemos querer inspecionar e bloquear tais consultas na camada de proxy. Para aplicar essa estratégia, o componente de proxy deve analisar as declarações de consulta em dados estruturados, percorrê-las para obter campos aninhados em cada camada e seguir a prática comum do GraphQL de atribuir valores de complexidade aos campos como custos de consulta. Limites globais no custo total da consulta podem então ser aplicados. Para a consulta acima, assumindo um custo de 1 para cada campo individual:

10 * photo (url + uploadAt + publisher.fullName + publisher.avatar + 10 * comment (content + sender.fullName + sender.avatar))

10 * (1 + 1 + 1 + 1 + 10 * (1 + 1 + 1)) = 340

Com um custo total de consulta de 340, parece aceitável, e podemos configurar limites de custo de consulta de API com base nessas regras. No entanto, se um cliente malicioso tentar buscar dados para 100 fotos em uma única consulta, o custo da consulta subirá para 3400, ultrapassando o limite predefinido e resultando em uma solicitação negada.

Além de restringir o custo máximo por consulta do cliente, limites adicionais em intervalos de tempo, como permitir um total de 2000 consultas por minuto e rejeitar consultas excedentes, podem frustrar rastreadores maliciosos.

Para implementar tais capacidades, o componente de proxy deve analisar e calcular os custos das consultas. A API7 Enterprise suporta esses recursos, permitindo a análise dinâmica de consultas GraphQL e a implementação de limites de taxa com base em configurações.

APIs GraphQL enfrentam desafios na camada de proxy, onde proxies reversos tradicionais lutam para perceber e lidar efetivamente com a complexidade e relações de aninhamento nas declarações de consulta do GraphQL. Em contraste, tecnologias de gateway de API provam ser inestimáveis para superar esses desafios, onde a API7 Enterprise pode ser uma ótima escolha.

Tags: