graphql - pièges

Il n'y a probablement pas de technologies parfaites. Graphql ne fait pas exception. Si vous n'avez pas d'expérience avec cette technologie, vous devez avoir une bonne idée des problèmes que vous pourriez rencontrer et vous y préparer à l'avance.

Pour commencer, je dirai que je suis plus un partisan qu'un adversaire de l'utilisation de graphql dans la mesure du possible. Et je ne vais dissuader personne du tout de l'opportunité d'utiliser cette technologie. Et c'est pourquoi je soulève des questions liées aux problèmes non résolus dans le cadre de la technologie graphql.

Par exemple, pour quelqu'un, il peut être inattendu que chaque objet dans graphql doive être décrit au moins deux fois: une fois comme type de retour de l'objet, et encore une fois comme type d'entrée de l'objet (voir graphql.org/graphql-js/mutations- et-types-d'entrée ). Cependant, je l'ai dit pour commencer et ne considère même pas cela comme un inconvénient important. Aujourd'hui, nous nous concentrerons sur ces problèmes qui, en règle générale, doivent être résolus lors du développement d'une application utilisant la technologie graphql:

  1. Séparation des accès pour les utilisateurs et les groupes d'utilisateurs.
  2. Gestion des erreurs.
  3. SELECT N + 1 Problème

Séparation des accès pour les utilisateurs et les groupes d'utilisateurs


graphql ne sait rien du partage d'accès entre les utilisateurs et les groupes. Ainsi, tout le travail de partage d'accès est à la charge du développeur de l'application. Le troisième paramètre transmet l'objet de contexte d'application à la fonction résolveur. Par conséquent, si vous travaillez, par exemple, avec l'implémentation de graphql JavaScript + express, alors dans le paramètre context vous pouvez obtenir l'utilisateur actuel à partir de l'objet request express.js. Mais des travaux supplémentaires sur le contrôle d'accès doivent être effectués directement dans chaque résolveur:

function(root, {id}, ctx) { return DB.Lists.get(id) .then( list => { if(list.owner_id && list.owner_id != ctx.userId){ throw new Error("Not authorized to see this list"); } else { return list; } }); } 

Naturellement, cette approche complique le contrôle d'accès car il n'y a aucun moyen de définir des droits d'accès de manière déclarative, et le contrôle des droits est réparti sur des dizaines (pour certains grands systèmes, sur des milliers) de fonctions de résolution. Par conséquent, il existe un certain nombre de bibliothèques qui résolvent ce problème. Certains d'entre eux sont assez populaires (à en juger par le nombre d'étoiles sur github.com), par exemple github.com/maticzav/graphql-shield .

Gestion des erreurs


Si votre interface nécessite une validation d'entrée et la génération de messages détaillés pour chaque champ qui n'a pas passé la validation, la gestion des erreurs dans graphql ne vous semblera probablement pas assez flexible. Par exemple, si le paramètre d'entrée a été décrit comme une chaîne et qu'une valeur numérique a été reçue, le message d'erreur sera de peu d'utilité pour cela:

 { "errors": [ { "message": "Expected type String, found 1.", "locations": [ { "line": 2, "column": 15 } ] } ] } 

S'il y a une erreur brute dans le type de paramètre d'entrée, un message d'erreur sera généré automatiquement et il n'y a aucun moyen de contrôler ce processus. Si la validation par type de paramètre d'entrée a réussi, il est possible d'envoyer un message d'erreur personnalisé au client en lançant un new Error ('custom message ...') objet new Error ('custom message ...') . Il ne fonctionnera pas pour ajouter des champs personnalisés à l'objet d'erreur (la personnalisation d'erreur est implémentée dans les bibliothèques apollo-server-express et apollo-errors lorsqu'elles sont utilisées ensemble). Bien sûr, il y a toujours la possibilité de sérialiser l'objet en une chaîne de message sur le serveur et de le désérialiser sur le client. Mais est-il nécessaire de le faire?

SELECT N + 1 Problème


Ce problème a été discuté en détail dans le message .

graphql est construit sur des fonctions de résolution. Cela signifie que la récupération des données de la base de données peut provoquer un problème appelé SELECT N + 1. Supposons que dans la fonction résolveur, une liste d'objets a été obtenue dans laquelle les données associées à cet objet sont représentées par des identifiants (clés étrangères). Pour chacun de ces identifiants, son propre résolveur de fonction sera appelé, dans lequel (dans chacun) une demande supplémentaire à la base de données sera effectuée. Ainsi, au lieu d'une seule requête de base de données (avec SQL JOIN), de nombreuses requêtes seront exécutées, ce qui surchargera la base de données de requêtes.

Pour résoudre ce problème, Facebook a développé la bibliothèque github.com/graphql/dataloader , qui utilise une stratégie de demande en attente. Au lieu d'exécuter la requête directement dans le résolveur de fonctions, il est proposé d'accumuler des identifiants (clés secondaires) dans le tableau, puis de les recevoir immédiatement avec une seule requête.

apapacy@gmail.com
13 mai 2019

Source: https://habr.com/ru/post/fr451466/


All Articles