Recursos
RecursosMelhores práticas em GraphQL

Melhores práticas em GraphQL

GraphQL é suficientemente maduro, e está presente há tempo suficiente, para que a comunidade tenha publicado numerosos artigos compartilhando melhores práticas. Essas guias cobrem praticamente todos os aspectos do GraphQL, incluindo design de schema, convenções de nomenclatura, tratamento de segurança e fornecimento de erros significativos, entre outros.

Estas são algumas das guias mais relevantes sobre melhores práticas em GraphQL.

Melhores práticas em graphql.org

O site oficial do GraphQL oferece uma introdução geral às melhores práticas em GraphQL.

Esses itens cobrem principalmente preocupações de alto nível, como:

Onde o layer GraphQL é posicionado dentro da arquitetura

As recomendações de Lee Byron

Pouco depois de lançar o GraphQL ao mundo, o criador do GraphQL Lee Byron publicou o artigo Lessons From 4 Years of GraphQL, descrevendo como devemos conceitualmente tentar trabalhar com GraphQL:

  • Nomenclatura importa
  • Pense em grafos, não em endpoints
  • Descreva os dados, não a visão
  • GraphQL é uma interface leve
  • Oculte detalhes de implementação

Ele também detalha vários princípios e lições valiosas que aprendeu ao usar GraphQL no Facebook.

GraphQL Rules

GraphQL Rules é um site especialmente dedicado a apresentar as melhores práticas do dia a dia para trabalhar com GraphQL, abordando principalmente o design do schema GraphQL.

Este recurso é muito completo. Ele compila informações de alguns recursos excepcionais (como o artigo Designing GraphQL Mutations e o tutorial da Shopify Designing a GraphQL API) e os apresenta todos juntos de forma concisa.

As regras descritas incluem:

  1. Regras de nomenclatura
    • Use camelCase para campos e argumentos GraphQL.
    • Use UpperCamelCase para tipos GraphQL.
    • Use CAPITALIZED_WITH_UNDERSCORES para nomear tipos ENUM.
  2. Regras de tipos
    • Use tipos escalares personalizados se quiser declarar campos ou argumentos com valor semântico específico.
    • Use Enum para campos que contêm um conjunto específico de valores.
  3. Regras de campos (Output)
    • Use nomes semânticos para os campos e evite vazar detalhes de implementação nos nomes dos campos.
    • Use o campo Non-Null se o campo sempre terá um determinado valor.
    • Agrupe o maior número possível de campos relacionados em um Object type personalizado.
  4. Regras de argumentos (Input)
    • Agrupe argumentos relacionados em um novo input-type.
    • Use tipos escalares rigorosos para argumentos, por exemplo DateTime em vez de String.
    • Marque argumentos como required se forem necessários para a execução da query.
  5. Regras de listas
    • Para filtrar listas, use o argumento filter, que contém todos os filtros disponíveis.
    • Use o argumento sort do tipo Enum ou [Enum!] para ordenação de listas.
    • Use limit com valor padrão e skip para limitar o número de itens retornados na lista.
    • Use os argumentos page, perPage para paginação e retorne um output type com items (array de elementos) e pageInfo (metadados).
    • Para listas infinitas (scroll infinito), use a Relay Cursor Connections Specification.
  6. Regras de mutations
    • Use Namespace-types para agrupar mutations dentro de um único recurso.
    • Vá além do CRUD — crie mutations pequenas para diferentes operações de negócio nos recursos.
    • Considere a possibilidade de executar mutations em múltiplos itens (alterações batch do mesmo tipo).
    • As mutations devem descrever claramente todos os argumentos obrigatórios; não deve haver opções either-either.
    • Nas mutations, coloque todas as variáveis em um único argumento input.
    • Cada mutation deve ter um payload type único.

Melhores práticas para resolvers

O artigo GraphQL Resolvers: Best Practices descreve como criar melhor os resolvers de campos. Embora seja voltado para servidores Node.js (a infraestrutura do PayPal é baseada em Express), várias de suas lições também podem ser aplicadas a outras tecnologias, incluindo PHP.

Os principais aprendizados são:

  • Buscar e passar dados de pai para filho deve ser usado com moderação.
  • Use bibliotecas como dataloader para deduplicar requisições downstream.
  • Esteja ciente de qualquer pressão que você está causando nas suas fontes de dados.
  • Não mute "context". Garante um código consistente e com menos bugs.
  • Escreva resolvers legíveis, manuteníveis e testáveis. Não muito complexos.
  • Torne seus resolvers o mais enxutos possível. Extraia a lógica de busca de dados para funções async reutilizáveis.

OWASP - GraphQL Cheat Sheet

OWASP (Open Web Application Security Project) é uma fundação sem fins lucrativos que trabalha para melhorar a segurança de software. Realiza pesquisas sobre como diferentes tecnologias são vulneráveis a exploits e descreve detalhadamente soluções para problemas de segurança, facilitando para os desenvolvedores a prevenção de ataques.

OWASP publicou a GraphQL Cheat Sheet, explicando quais são os ataques mais comuns e os maiores problemas de segurança em GraphQL, e como abordá-los.

Os ataques comuns ao GraphQL são:

  1. Injection - isso geralmente inclui, mas não se limita a:
    • Injection SQL e NoSQL
    • Injection de comandos OS
    • Injection SSRF e CRLF / Request Smuggling
  2. DoS (Denial of Service)
  3. Abuso de autorização quebrada: acesso impróprio ou excessivo, incluindo IDOR
  4. Batching Attacks, um método de ataque brute force específico do GraphQL
  5. Abuso de configurações padrão inseguras

O OWASP então fornece recomendações sobre como evitar cada um desses casos.

Melhores práticas com queries GraphQL

A equipe do Apollo publicou as GraphQL query best practices, oferecendo insights práticos sobre maneiras concretas de compor a query GraphQL.

Por exemplo, essas duas queries atingem o mesmo objetivo, mas como a primeira tem um nome de operação, ela é mais compreensível e útil durante o debugging:

# Recomendado ✅
query GetBooks {
  books {
    title
  }
}
 
# Não recomendado ❌
query {
  books {
    title
  }
}

As sugestões deles incluem:

  • Nomear todas as operações
  • Usar variáveis para fornecer argumentos GraphQL
  • Consultar apenas os dados de que você precisa, onde precisa
  • Usar fragments para encapsular conjuntos de campos relacionados
  • Consultar dados globais e dados específicos do usuário separadamente

Aproveitando o one graph

Também da equipe do Apollo, o site Principled GraphQL explica que GraphQL não é apenas uma especificação, mas, possivelmente mais importante, uma interface para interagir com o "grafo" de dados da nossa empresa.

Por meio de uma lista de 10 princípios, este site descreve como aproveitar ao máximo o grafo único:

  1. One Graph: sua empresa deve ter um grafo unificado, em vez de múltiplos grafos criados por cada equipe.
  2. Federated Implementation: embora haja apenas um grafo, a implementação desse grafo deve ser federada entre múltiplas equipes.
  3. Track the Schema in a Registry: deve haver uma única fonte da verdade para registrar e rastrear o grafo.
  4. Abstract, Demand-Oriented Schema: o schema deve atuar como uma camada de abstração que oferece flexibilidade aos consumidores enquanto oculta os detalhes de implementação do serviço.
  5. Use an Agile Approach to Schema Development: o schema deve ser construído incrementalmente com base em requisitos reais e evoluir suavemente ao longo do tempo.
  6. Iteratively Improve Performance: o gerenciamento de desempenho deve ser um processo contínuo, baseado em dados, adaptando-se progressivamente às cargas de queries e implementações de serviços em evolução.
  7. Use Graph Metadata to Empower Developers: os desenvolvedores devem ser equipados com rica consciência do grafo durante todo o processo de desenvolvimento.
  8. Access and Demand Control: conceda acesso ao grafo por cliente e gerencie o que e como os clientes podem acessá-lo.
  9. Structured Logging: capture logs estruturados de todas as operações do grafo e utilize-os como a principal ferramenta para entender o uso do grafo.
  10. Separate the GraphQL Layer from the Service Layer: adote uma arquitetura em camadas com a funcionalidade do grafo dividida em uma camada separada em vez de incorporada em cada serviço.