Estou pedindo ajuda ao ChatGPT para aprofundar as possibilidades de consulta do GraphQL, enquanto estou brincando em criar uma variante JSON do GraphQL para fins de aprendizagem. Uma coisa que me deixa perplexo há algum tempo é como você pode oferecer suporte a argumentos/parâmetros de entrada de consulta em um nó, mas não em outro do mesmo tipo de nó.
Construindo aquele longo tópico do ChatGPT (que você não precisa ler para esta postagem), digamos que você tenha um tipo de sistema como este:
const resolvers = {
Query: {
author: (parent, args) => {
// Implement logic to fetch an author by ID
},
post: (parent, args) => {
// Implement logic to fetch a post by ID
},
},
Author: {
posts: (author) => {
// Implement logic to fetch all posts by this author
},
},
Post: {
comments: (post) => {
// Implement logic to fetch all comments for this post
},
},
Comment: {
author: (comment) => {
// Implement logic to fetch the author of this comment
},
},
};
Estou tentando imaginar uma imagem onde você tenha algo como esta consulta:
query {
author(id: "1") {
id
name
posts(limit: 10) {
id
title
content
comments(limit: 10) {
id
text
author {
id
name
posts(createdAtGt: someDate) {
id
title
content
}
}
}
}
}
}
Ou algo ainda mais complexo.
Basicamente, vemos aqui que existe Query.author
e também Comment.author
, então a primeira parte da pergunta é: por que você precisa do Comment.author
escopo, por que não apenas usar o Query.author
escopo? Não é como se estivéssemos criando um Author.posts.comments()
escopo; em vez disso, temos um Post.comments
resolvedor de nível superior.
Mas e se tivéssemos uma situação em que (e ainda não consigo encontrar um exemplo simples e claro) você quisesse filtrar de uma maneira as postagens de author.posts
, mas de uma maneira completamente diferente comment.author.posts
, _e não quisesse permitir a filtragem de postagens em um contexto para serem usadas na consulta GraphQL no outro contexto na árvore de consulta...
Você já se deparou com essa situação?
Basicamente, estou me perguntando por que você escolheria uma direção em vez de outra:
- Permitir que apenas 1 tipo de filtragem funcione em todos os nós/registros de um tipo específico.
- Ou 2, especifique uma funcionalidade exclusiva de entrada/filtragem em nível por ramificação, de modo que um tipo de registro possa ter 10 mecanismos de filtragem diferentes com base em sua localização na árvore de consulta.
Se (2) acontecer em aplicativos de produção mais complexos, parece que você teria que reimplementar muita lógica básica em vários pontos diferentes nos resolvedores e, em seguida, personalizar onde for necessário. Basicamente me perguntando por que você não criaria um resolvedor mais parecido com este (lembrando que estou pensando em uma alternativa JSON ao GraphQL para fins de aprendizado):
{
author: {
resolve(parent, args) {
// Find author by id
},
children: {
posts: {
resolve(parent) {
// find posts by author id, and allow `limit` on the posts query, only here.
},
children: {
comments: {
resolve(parent) {
// find comments by post id
},
children: {
author: {
resolve(parent) {
// find author by comment author id
},
children: {
posts: {
resolve(parent) {
// find posts by author id, but only allow searching for greater than certain date.
}
}
}
}
}
}
}
},
comments: {
resolve(parent) {
// now find comments by author id
},
children: {
author: {
resolve(parent) {
// maybe here we have different logic and only return authors with a first name starting with "A".
},
children: {
posts: {
resolve(parent) {
// and another variant here too... it can go on more and more custom cases.
}
}
}
}
}
}
}
}
}
Algo assim ocorre no mundo do GraphQL? Em caso afirmativo, qual é um exemplo semicomplexo para demonstrar? Se não, por que não?
Sua pergunta:
É perfeitamente razoável no GraphQL.
author
byid
seria controlada no resolvedor daauthor
consulta.posts
resolvedor de campo para oAuthor
tipo precisa então examinar oargs
parâmetro para encontrar olimit
e 'createdAtGtarguments alongside the
parentargument. In the case of the first
postsfield, the parent will be the
Authorwith
id==1. Later under comments the
Authorparent for the
postsfield resolver will be some other
Author` que comentou na postagem do autor original.comments
resolvedor de campo sob oPost
tipo também precisa examinar seu pai e oargs
parâmetro para descobrir quais comentários incluir.posts
resolvedor de campo não precisa se preocupar com a profundidade em que está sendo chamado, o pai e oargs
são tudo o que precisa.Com isso em mente, estas outras consultas também seriam válidas:
Agora, para a próxima parte da pergunta:
Pode-se anexar quaisquer dados desejados a um objeto ao resolvê-lo. Esses dados extras são transmitidos aos resolvedores filhos, mas eliminados quando a árvore JSON é retornada ao cliente.
Assim, por exemplo, no
comment
resolvedorunder post when you resolve the
autoryou could add an
isCommentAuthorkey to the
autorobject and then the
postsresolver under
Author` poderia verificar se essa chave está no pai e então resolver de forma diferente.Alternativamente, você pode estender o
Author
tipo para umCommentAuthor
tipo (com todos os mesmos campos e talvez alguns outros) e então ter um resolvedor completamente diferente paraposts
underCommentAuthor
do que você faz underAuthor
.Cada uma dessas soluções pode parecer desajeitada em alguma dimensão, mas já foi feita antes.
Há alguma tensão inerente à sua pergunta entre o que um desenvolvedor front-end pode querer da consulta e como o desenvolvedor back-end deseja restringir possíveis resultados. Normalmente, o desenvolvedor back-end deve (opinião) fornecer flexibilidade máxima, ao mesmo tempo em que aplica regras de segurança e fornece alto desempenho. Definitivamente, é difícil para o desenvolvedor back-end prever todas as formas como uma consulta pode aparecer. Fazer com que os resolvedores de campo atuem de maneira diferente dependendo de seus avós e bisavós aumenta a complexidade. Certifique-se de que o benefício vale esse custo.