在 GraphQL 架构中迭代自定义指令

Iterate Over Custom Directives in GraphQL Schema

我有一个简化的 schema.graphql 文件,其中包含一种类型和一个自定义指令(在字段和对象级别)。在 Typescript 中,如何以编程方式获取类型和类型指令,并迭代字段和字段指令?

type Test @myCustomDirective() {
  id: String! @myCustomDirective()
}

这 post 说“GraphQL 当前不支持”:
Is there any way to read GraphQL Directives on a Type with Query Introspection?

GitHub 问题表明正在考虑此功能:
https://github.com/graphql/graphql-spec/issues/300

那么 AWS AppSync 是如何做到这一点的呢?见下文。

// The following keeps custom directives:
parse(schema); // Return type: graphql.DocumentNode

// The following removes custom directives:
buildSchema(schema); // Return type: GraphQLSchema
  1. AWS AppSync > Export Schema > Schema.json 确实包含自定义指令,但它是 AWS AppSync 特定的解决方案,是一项昂贵的 API 操作。
aws appsync get-introspection-schema --api-id abc123 --format JSON --include-directives output.json
  1. 我试过 GraphQL Code Generator Introspection 插件。但它从类型和字段中删除了自定义指令。

    https://www.graphql-code-generator.com/plugins/introspection

  2. 我试过 graphql/utilities 但它也从类型和字段中删除了自定义指令。

graphql.introspectionFromSchema(graphqlSchema)

// or

graphql.graphqlSync({ schema: graphqlSchema, source: graphql.getIntrospectionQuery() }).data as unknown as graphql.IntrospectionQuery;

https://graphql.org/graphql-js/utilities/

这种“GraphQL 工具”方法创建了一个可迭代的模式,但可能不是最有效的方法:

“graphql-tools 包允许您使用函数 makeExecutableSchema 从 GraphQL 模式语言创建 GraphQL.js GraphQLSchema 实例”
https://www.graphql-tools.com/docs/generate-schema

import { promises as fs } from 'fs';
import { makeExecutableSchema } from '@graphql-tools/schema';
import gql from 'graphql-tag';


const schemaFile = await fs.readFile(
    './schema.graphql'
);

const executableSchema = makeExecutableSchema({
    typeDefs: gql(schemaFile.toString())
});``

const output = executableSchema.getType('Test');


// output.astNode.directives sample output:

{
    kind: 'Directive',
    name: { kind: 'Name', value: 'myCustomDirective1' },
    arguments: [ [Object] ]
},
{
    kind: 'Directive',
    name: { kind: 'Name', value: 'myCustomDirective' },
    arguments: [ [Object] ]
}

// output.astNode['fields'] sample output:

[{
    kind: 'FieldDefinition',
    description: undefined,
    name: { kind: 'Name', value: 'id' },       
    arguments: [],
    type: { kind: 'NamedType', name: [Object] },  
    directives: [ [Object] ]
}]