GraphQL a révolutionné la façon dont nous récupérons et façonnons les données, en fournissant une couche d'abstraction propre entre les clients et les serveurs. L'une de ses fonctionnalités principales, les résolveurs, nous permet de définir comment chaque champ de notre schéma obtient ses données. Dans certains cas, les développeurs peuvent involontairement diminuer les avantages de GraphQL en s'appuyant sur des méthodes utilitaires dans les résolveurs. Cette pratique va non seulement à l'encontre de l'objectif de la conception de GraphQL, mais introduit également une complexité inutile et des bogues potentiels.
Voyons pourquoi cela pose problème et comment faire mieux.
Dans GraphQL, les résolveurs sont invoqués pour chaque instance d'un type, quel que soit l'endroit où ce type apparaît dans votre schéma. Cette abstraction garantit que la logique de résolution des données reste cohérente à tous les niveaux. Par exemple :
schema { query: Query } type Query { project(id: ID!): Project user(id: ID!): User } type Project { id: ID! name: String! owner: User! } type User { id: ID! name: String! email: String! }
Ici, le type Utilisateur est utilisé à deux endroits : directement dans la requête pour récupérer les utilisateurs et imbriqué dans le type Projet en tant que propriétaire. Grâce au système de résolution de GraphQL, nous pouvons définir un seul résolveur d'utilisateur pour gérer la façon dont les champs d'utilisateur sont résolus, garantissant ainsi un comportement cohérent partout où l'utilisateur apparaît.
Lorsque vous introduisez des méthodes utilitaires pour façonner les données en dehors de vos résolveurs, vous brisez cette abstraction. Prenons cet exemple :
// utils.ts function mapToUser(userData: DataSourceUser) { return { id: userData.id, name: userData.full_name, email: userData.contact_email, }; } // resolvers.ts const resolvers: Resolvers<Context> = { Query: { project: async (_, { id }, { dataSources }) => { const project = await dataSources.projectAPI.getProject(id); return { ...project, owner: mapToUser(project.owner), // Utility method called here }; }, user: async (_, { id }, { dataSources }) => { const user = await dataSources.userAPI.getUser(id); return mapToUser(user); // Utility method called here }, }, };
À première vue, cela peut sembler bien. Mais voici pourquoi c'est problématique :
Vous êtes obligé d'appeler mapToUser dans chaque résolveur où un type d'utilisateur apparaît. Oublier de l'appeler ou l'appeler de manière incorrecte peut entraîner un comportement incohérent au sein de votre API.
Le système de résolution de GraphQL est conçu pour centraliser la façon dont chaque type est résolu. En utilisant une méthode utilitaire, vous contournez cette fonctionnalité et rendez votre code moins intuitif.
Si jamais vous devez modifier la façon dont un type d'utilisateur est résolu (par exemple, en ajoutant de nouveaux champs ou en traitant des erreurs), vous devrez rechercher chaque endroit où mapToUser est appelé au lieu de mettre à jour un seul résolveur.
Au lieu d'utiliser des méthodes utilitaires, définissez des résolveurs pour vos types GraphQL. Voici comment vous pouvez réécrire l'exemple ci-dessus :
schema { query: Query } type Query { project(id: ID!): Project user(id: ID!): User } type Project { id: ID! name: String! owner: User! } type User { id: ID! name: String! email: String! }
L'utilisation de méthodes utilitaires dans vos résolveurs peut sembler un raccourci, mais cela compromet finalement la puissance et l'élégance de GraphQL. En définissant des résolveurs pour vos types, vous pouvez conserver une API propre, cohérente et évolutive. Alors arrêtez d'utiliser des utilitaires dans vos résolveurs et adoptez l'abstraction fournie par GraphQL : votre futur vous vous en remerciera !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!