GraphQL中@include/@skip指令后置处理问题及客户端工具问询
客户端自动剥离GraphQL @skip/@include指令的方案
可用工具与实现方法
graphql-transformer-tools 库:支持在客户端构建查询AST阶段,根据变量值动态移除满足@skip/@include条件的字段,完美适配
graphql-tag。示例代码:import { transform } from 'graphql-transformer-tools'; import gql from 'graphql-tag'; // 原始查询 const rawQuery = gql` query myListQuery($someTest: Boolean) { id price taxRate expensiveField @skip(if: $someTest) } `; // 根据变量值移除符合条件的字段 const processedQuery = transform(rawQuery, { skipFields: (fieldNode) => { const skipDirective = fieldNode.directives?.find(d => d.name.value === 'skip'); if (skipDirective) { const condition = skipDirective.arguments?.find(a => a.name.value === 'if').value.value; return condition; // 条件为true时移除该字段 } return false; } });自定义AST遍历处理:如果不想引入额外依赖,直接用
graphql库的visit方法操作AST,实现字段剥离:import gql from 'graphql-tag'; import { visit } from 'graphql'; // 自定义处理函数:根据变量值移除带条件指令的字段 function cleanConditionalFields(queryAST, variables) { return visit(queryAST, { Field(fieldNode) { // 处理@skip指令 const skipDirective = fieldNode.directives?.find(d => d.name.value === 'skip'); if (skipDirective) { const ifArg = skipDirective.arguments?.find(a => a.name.value === 'if'); if (ifArg?.value.kind === 'Variable' && variables[ifArg.value.name.value]) { return null; // 移除该字段 } } // 处理@include指令 const includeDirective = fieldNode.directives?.find(d => d.name.value === 'include'); if (includeDirective) { const ifArg = includeDirective.arguments?.find(a => a.name.value === 'if'); if (ifArg?.value.kind === 'Variable' && !variables[ifArg.value.name.value]) { return null; // 移除该字段 } } return fieldNode; } }); } // 使用示例 const queryVariables = { someTest: true }; const originalQuery = gql` query myListQuery($someTest: Boolean) { id price taxRate expensiveField @skip(if: $someTest) } `; const cleanedQuery = cleanConditionalFields(originalQuery, queryVariables);
注意点
- 这种预处理需要确保变量值在构建查询时已确定,如果变量是异步获取的,要等变量就绪后再执行转换。
- 配合Apollo Client使用时,可以把上述逻辑封装成自定义Link,在请求发送前自动处理查询,无需每次手动调用转换函数。
内容的提问来源于stack exchange,提问作者pavelmickevic
相关产品推荐
相关产品推荐

