Как разделить схему в GraphQL без круговых зависимостей?

Мой вопрос похож на круговую зависимость Javascript в коде GraphQL, но моя проблема не в уровне структуры и базы данных, а в javascript (ES6).

Мое определение схемы становится слишком большим, но я не вижу, где бы я мог вырезать файл на куски. Кажется логичным вырезать на основе разных типов объектов, но это приводит к круговым зависимостям аналогично этому очень упрощенному, нерабочему примеру:

    // -- file A.js

    import { bConnection, getBs } from 'B';

    export class A { /*...*/ };
    export var getA = (a) => { /*...*/ };
    export var getAs = (array_of_as) => { /*...*/ };

    export var aType = new GraphQLObjectType ({
      name: 'A',
      fields: () => ({
        bs: {
          type: bConnection,
          /*...*/
        },
        resolve: (a, args) => connectionFromPromisedArray (
          getBs (a.bs)
        ),
        /*...*/
      }),
      interfaces: () => [ require ('./nodeDefs').nodeInterface ],
      /*...*/
    })

    export var {
        connectionType: aConnection,
        edgeType: aEdge
      } = connectionDefinitions ({
        name: 'A',
        nodeType: aType
      });

    // -- file B.js

    import { aConnection, getAs } from 'A';

    export class B { /*...*/ };
    export var getB = (b) => { /*...*/ };
    export var getBs = (array_of_bs) => { /*...*/ };

    export var bType = new GraphQLObjectType ({
      name: 'B',
      fields: () => ({
        as: {
          type: aConnection,
          /*...*/
        },
        resolve: (b, args) => connectionFromPromisedArray (
          getAs (b.bs)
        ),
        /*...*/
      }),
      interfaces: () => [ require ('./nodeDefs').nodeInterface ],
      /*...*/
    })

    export var {
        connectionType: bConnection,
        edgeType: bEdge
      } = connectionDefinitions ({
        name: 'B',
        nodeType: bType
      });

    // -- file nodeDefs.js

    import {
      fromGlobalId,
      nodeDefinitions,
    } from 'graphql-relay';

    import { A, getA, aType } from 'A'
    import { B, getB, bType } from 'B'

    export var {nodeInterface, nodeField} = nodeDefinitions (
      (globalId) => {
        var {type, id} = fromGlobalId (globalId);
        if (type === 'A') {
          return getA (id);
        } else if (type === 'B') {
          return getB (id);
        }
      },
      (obj) => {
        if (obj instanceof A) {
          return aType;
        } else if (obj instanceof B) {
          return bType;
        }
      }
    )

    // -- file schema.js

    import {
      GraphQLObjectType,
      GraphQLSchema,
    } from 'graphql';

    import { nodeField } from './nodeDefs';

    var queryType = new GraphQLObjectType ({
      name: 'Query',
      fields: () => ({
        node: nodeField,
        /*...*/
      }),
    });

Есть ли общий способ или передовая практика для этого?

Ответ 1

У меня та же проблема. Я думаю, что более чистые решения касаются использования gruntjs concat.

grunt.initConfig({
  concat: {
    js: {
      src: ['lib/before.js', 'lib/*', 'lib/after.js'],
      dest: 'schema.js',
    }
  }
});

С помощью этой конфигурации вы можете разделить свою схему на несколько файлов, создав окончательный файл schema.js.

before.js может быть следующим образом:

 import {
    GraphQLObjectType,
    GraphQLInt,
    GraphQLString,
    GraphQLSchema,
    GraphQLList,
    GraphQLNonNull
} from 'graphql';
import db from '../models/index.js';
import Auth from '../classes/auth';

after.js может быть следующим образом:

const Schema = new GraphQLSchema({
    query: Query,
    mutation: Mutation
})
export default Schema;

Другие файлы будут содержать такие объекты, как:

const Funcionario = new GraphQLObjectType({
name: 'Funcionario',
description: 'This represent a Funcionario',
fields: () => {
    return {
        id: {
            type: GraphQLInt,
            resolve(funcionario, args) {
                return funcionario.id;
            }
        },
        CPF: {
            type: GraphQLString,
            resolve(funcionario, args) {
                return funcionario.CPF;
            }
        },
        nome: {
            type: GraphQLString,
            resolve(funcionario, args) {
                return funcionario.nome;
            }
        },
        sobrenome: {
            type: GraphQLString,
            resolve(funcionario, args) {
                return funcionario.sobrenome;
            }
        },
        sessions: {
            type: new GraphQLList(Session),
            resolve(funcionario, args) {
                return funcionario.getSessions();
            }
        }
    }
}
})