Проблемы с переходом с graphql-import на только graphql-tools с ApolloServer, директивы перестают работать

Мое тяжелое положение началось с простого желания расширить мою схему graphql с одного файла.graphql до нескольких файлов, чтобы я мог лучше организовать схему и чтобы она не вырастала до одного огромного файла из-под контроля.

Мой исходный макет был очень простым, и у меня была рабочая схема в schema.graphqlфайл. Я мог бы разобрать его на строку, используяimportSchema('server/schema.graphql')из библиотеки graphql-import, которая теперь устарела https://github.com/ardatan/graphql-import

Они упоминают, что он был объединен с graphql-toolsв последней версии и предоставьте руководство по миграции здесь https://www.graphql-tools.com/docs/migration-from-import. Учебное пособие кажется очень простым, поскольку их первый пример в значительной степени иллюстрирует, как именно выглядит мой код (кроме Я не использую импорт es6, но старый требует):

import { importSchema } from 'graphql-import';
import { makeExecutableSchema } from 'graphql-tools';

const typeDefs = importSchema(join(__dirname, 'schema.graphql'));
const resolvers = {
  Query: {...}
};
const schema = makeExecutableSchema({ typeDefs, resolvers });

И тогда они говорят, что нужно изменить, просто внесите эти изменения

import { loadSchemaSync } from '@graphql-tools/load';
import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader';
import { addResolversToSchema } from '@graphql-tools/schema';

const schema = loadSchemaSync(join(__dirname, 'schema.graphql'), { loaders: [new GraphQLFileLoader()] });
const resolvers = { Query: {...} };

const schemaWithResolvers = addResolversToSchema({
  schema,
  resolvers,
});

Я внес эти изменения, но главное отличие в том, что они больше не используют makeExecutableSchema()в их примере, что для меня очень важно, так как мне нужно включить директивы. Что мне теперь делать со схемой? Как объявить директивы? их документация для директив все еще используетmakeExecutableSchema но я больше не могу его использовать, так как новый loadSchemaSync функция возвращает объект вместо строкового литерала, который мне нужно передать typeDefs в makeExecutableSchema

Я использую apollo-server, поэтому казалось возможным обходным путем просто объявить директивы в конструкторе apollo-server и просто передать этот новый schemaWithResolvers как схема как таковая

const server = new ApolloServer({
    schema, //this includes now the returned value of using addResolversToSchema()
    schemaDirectives : {
        auth:AuthDirective,
        authRole: AuthRoleDirective
    }
    context : ({req}) => //dostuff,

});

Это позволяет моему серверу работать, и я могу выполнять запросы и изменения, однако мои директивы больше не работают, и у меня больше нет аутентификации по защищенным запросам.

Мне нужен способ импортировать мой файл.graphql и разобрать его в строку, чтобы я мог использовать его внутри typeDefs как я привык с importSchema() или способом объявить мои директивы без использования makeExecutableSchema(), чтобы они снова продолжали работать!

Я просматривал документацию и видел другие библиотеки, и до сих пор я не останавливаюсь, любые советы или рекомендации очень ценятся

3 ответа

Решение

makeExecutableSchema все еще является частью graphql-toolsи вы можете продолжать использовать его, как показано здесь, в документации. Проблема с примером, показанным в документации, заключается в том, что он не эквивалентен тому, что вы делали раньше. Вы должны использоватьloadTypedefsSync вместо:

import { loadTypedefsSync } from '@graphql-tools/load';
import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader';
import { addResolversToSchema } from '@graphql-tools/schema';

const sources = loadTypedefsSync(join(__dirname, 'schema.graphql'), { loaders: [new GraphQLFileLoader()] });
const documentNodes = sources.map(source => source.document);
const resolvers = { Query: {...} };

const schema = makeExecutableSchema({ typeDefs, resolvers });

В качестве альтернативы, если вы пойдете loadSchema route, вы сможете применить директивы к своей схеме после ее загрузки:

import { SchemaDirectiveVisitor } from "@graphql-tools/utils";
import { loadSchemaSync } from '@graphql-tools/load';
import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader';
import { addResolversToSchema } from '@graphql-tools/schema';

const schema = loadSchemaSync(join(__dirname, 'schema.graphql'), { loaders: [new GraphQLFileLoader()] });
const resolvers = { Query: {...} };

const schemaWithResolvers = addResolversToSchema({
  schema,
  resolvers,
});

SchemaDirectiveVisitor.visitSchemaDirectives(schemaWithResolvers, schemaDirectives);

Я пробовал этот способ, но не смог решить проблему. Уникальное решение, в котором реализован следующий подход:

const { ApolloServer, makeExecutableSchema, gql} = require('apollo-server-express')
const { loadTypedefsSync }  = require('@graphql-tools/load')
const { GraphQLFileLoader } = require('@graphql-tools/graphql-file-loader')
const path = require('path')

const sources = loadTypedefsSync(
    path.resolve(__dirname, '../schema/root.graphql'),
    { loaders: [new GraphQLFileLoader()] }
)
const typeDefs = sources.map(source => source.document)
const schema = makeExecutableSchema({
    typeDefs: gql`${typeDefs[0]}`,
    resolvers,
})

У меня была та же проблема, через которую я загрузил схему, и я хочу добавить директиву graphql-constraint . Мое решение состояло в том, чтобы загрузить схему с помощью loadSchemaSync а затем использовать wrapSchema чтобы использовать функции преобразования, вам также необходимо добавить директивы в одну из ваших .graphql файлы:

      import { addResolversToSchema, wrapSchema } from 'graphql-tools';
import { GraphQLSchema } from 'graphql';
import resolvers from './resolver';

schema = loadSchemaSync('./**/*.graphql', {
  loaders: [new GraphQLFileLoader()],
});

const schemaWithResolver = addResolversToSchema({
    schema,
    resolvers
  });

const { constraintDirective } = require('graphql-constraint-directive')
  
const schemaConstrain = wrapSchema({
  schema: schemaWithResolver,
  transforms: [constraintDirective()]
})

Документация по упаковке схемы

Другие вопросы по тегам