Servidor GraphQL code-first
O schema GraphQL define os contratos de um serviço GraphQL, expondo o conjunto de tipos, campos e mutations que podem ser executados no serviço. Ao criar um serviço GraphQL, podemos decidir:
- fazer do schema a fonte de verdade e adaptar todo o nosso código de implementação às suas definições
- fazer do nosso código a fonte de verdade e gerar o schema como um artefato a partir do código
Em ambos os casos teremos um serviço GraphQL completamente funcional, mas, dependendo da abordagem escolhida, poderemos realizar mais ou menos funcionalidades, com mais ou menos facilidade, no longo prazo. Essas duas abordagens são chamadas, respectivamente, de "schema-first" (mais precisamente "SDL-first") e "code-first".
O Gato GraphQL utiliza a abordagem code-first. Vamos entender o porquê.
Por que o Gato GraphQL utiliza code-first
Na abordagem code-first, começamos codificando os resolvers e, a partir do código como única fonte de verdade, geramos o schema como um artefato. Portanto, o schema é criado executando um script, em vez de ser criado manualmente como no SDL-first. Como o code-first também possui um schema, ele não perde nada de significativo em relação ao que o SDL-first oferece.
No entanto, o code-first oferece uma característica importante em relação ao SDL-first: a possibilidade de fornecer schemas dinâmicos, que podem mudar de forma e atributos dependendo do contexto, regulados por código em tempo de execução. De fato, todas as grandes funcionalidades oferecidas pelo Gato GraphQL são uma consequência direta de sua adoção do code-first.
Vantagens do code-first
Um schema dinâmico oferece, entre outros, todos os benefícios listados abaixo:
A fonte de verdade para o schema é um superconjunto daquela exigida pelo GraphQL. As propriedades adicionais (como os campos globais, conexões globais, directives globais e fragmentos persistidos) já podem ser usadas em nossa API sem precisar esperar que sejam adicionadas à especificação do GraphQL, se isso vier a ocorrer.
Como a fonte de verdade não está vinculada ao schema, podemos gerar qualquer schema para qualquer outro sistema também: o GraphQL é apenas um dos alvos possíveis. Por exemplo, é possível gerar um JSON-schema para um serviço REST a partir da mesma fonte de verdade.
A API pode ser pública/privada ao mesmo tempo, dependendo de o usuário estar autenticado ou não e dos papéis do usuário autenticado, ou oferecer mais ou menos campos dependendo de alguma outra propriedade, como se o usuário pagou pela assinatura PRO.
Os tipos não sabem de antemão quais campos irão resolver. Em vez disso, os resolvers de campo se associam aos resolvers de tipo usando o padrão publish-subscribe, e os resolvers de campo podem sobrescrever outros resolvers de campo. Essa característica torna a API muito extensível, permitindo que tenhamos um código geral para nossa API e o personalizemos no nível da aplicação para um cliente ou projeto específico.
Um campo pode ser processado não por apenas um resolver, mas por muitos resolvers de campo: cada resolver de campo na cadeia pode decidir, em tempo de execução, se processa o campo ou não com base em alguma propriedade, ou o passa adiante na cadeia. Por exemplo, um resolver de campo especial pode ser usado apenas se um argumento de campo "source: testing" for passado, permitindo ser testado em alguns sites em produção antes do lançamento geral; a mesma estratégia também permite fornecer correções rápidas de bugs para um cliente ou ambiente específico sem correr o risco de efeitos colaterais indesejados em outros lugares.
Tipos e interfaces podem ser automaticamente inseridos em namespaces para evitar colisões com terceiros.