Graphql-tools: Schema loaders for federated servers

Created on 3 Jun 2020  Â·  8Comments  Â·  Source: ardatan/graphql-tools

How can we load a schema that has federation directives defined with any schema loaders?

At the moment just fails not recognising the directives

type Account @key(fields: "id") {
  id: ID!
  ...
}
import { loadDocuments } from '@graphql-tools/load';
import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader';

const documents = await loadDocuments('./src/**/graphql/*.ts', {
  loaders:[
    new GraphQLFileLoader()
  ],
})
waiting for answer

All 8 comments

loadDocuments is for operation files not schema files. You can use loadSchema instead.
loadDocuments is modified version of loadTypedefs, it filters the content that is not related to the operation, so loadSchema does that filtering in opposite way and it returns GraphQLSchema.

You have two options;

import { loadSchema } from '@graphql-tools/load';
import { CodeFileLoader } from '@graphql-tools/code-file-loader';
import { printSchemaWithDirectives } from '@graphql-tools/utils';

// This returns `GraphQLSchema`
const schema = await loadSchema('./src/**/graphql/*.ts', {
  loaders:[
    new CodeFileLoader()
  ],
  assumeValidSDL: true, // this will bypass validation
});
const printedSchema = printSchemaWithDirectives(schema); // This can be used as `typeDefs`

OR

// This returns `Source` object for each file and `Source` object contains `DocumentNode`
or you can use `loadTypedefs` directly. 

const sources = await loadTypedefs('./src/**/graphql/*.ts', {
  loaders:[
    new CodeFileLoader()
  ],
});

const documentNodes = sources.map(source => source.document); // This can be used as `typeDefs`

@ardatan Awesome!!! I will give it a try!

@ardatan right, i've done some tests with both methods you suggested, we are nearly there but i've still got some issues

The first one, using * loadSchema* does create typeDefs correctly, but as soon i pass them into buildFederatedSchema function is get this error

TypeError: Cannot read property 'kind' of undefined
    at KnownDirectives (~/Documents/XXXX/graphql-cashback/node_modules/graphql/validation/rules/KnownDirectives.js:48:13)
    at ~/Documents/XXXX/graphql-cashback/node_modules/graphql/validation/validate.js:91:12
    at Array.map (<anonymous>)
    at Object.validateSDL (~/Documents/XXXX/graphql-cashback/node_modules/graphql/validation/validate.js:90:24)
    at Object.buildSchemaFromSDL (~/Documents/XXXX/graphql-cashback/node_modules/apollo-graphql/lib/schema/buildSchemaFromSDL.js:36:31)
    at Object.buildFederatedSchema (~/Documents/XXXX/graphql-cashback/node_modules/@nimbus/cli/node_modules/@apollo/federation/dist/service/buildFederatedSchema.js:45:35)
    at Object.<anonymous> (~/Documents/XXXX/graphql-cashback/node_modules/@nimbus/cli/dist/lib/tasks.js:94:41)
    at Generator.next (<anonymous>)
    at fulfilled (~/Documents/XXXX/graphql-cashback/node_modules/@nimbus/cli/dist/lib/tasks.js:5:58)

While trying using second approach with loadTypedefs it couldn't generate the typeDefs successfully complaining for double declarations which I don't have in my files, here is the error:

There can be only one type named "Subscription".

Field "Subscription.cbcChallenges" can only be defined once.
GraphQLSchemaValidationError: There can be only one type named "DateTime".
There can be only one type named "Subscription".
Field "Subscription.cbcChallenges" can only be defined once.
    at Object.buildSchemaFromSDL (~/Documents/XXXX/graphql-cashback/node_modules/apollo-graphql/lib/schema/buildSchemaFromSDL.js:38:15)
    at Object.buildFederatedSchema (~/Documents/XXXX/graphql-cashback/node_modules/@nimbus/cli/node_modules/@apollo/federation/dist/service/buildFederatedSchema.js:45:35)
    at Object.<anonymous> (~/Documents/XXXX/graphql-cashback/node_modules/@nimbus/cli/dist/lib/tasks.js:94:41)
    at Generator.next (<anonymous>)
    at fulfilled (~/Documents/XXXX/graphql-cashback/node_modules/@nimbus/cli/dist/lib/tasks.js:5:58)

Not sure how to go around this

@fenos Could you share a reproduction repository or CodeSandbox so we can help you better?

@ardatan fair enough, i'm preparing one

@ardatan right, I figured out the first issue using loadSchema. The problem i had above was because printSchemaWithDirectives returns a string and buildFederatedSchema typeDefs needs to be a DocumentNode type.

I wrapped the return value with gql (graphql-tag) and that worked.

While using the second method with loadTypeDefs it's still giving me the same issue even in the Codesanbox that I've prepared for you.

I can use option 1 (loadSchema) for now, but i'd still be curious why it doesn't work with loadTypeDefs

BTW: Thanks for your prompt support! Much appreciated!

@fenos I am not sure how strict is buildFederatedSchema but maybe I mislead you. First one gives you a string and the second one gives you an array of DocumentNode. But you can merge them using mergeTypeDefs.

Yes that was it! mergeTypeDefs made it work.
Thanks a lot again! I did learn quite a lots of things!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Adherentman picture Adherentman  Â·  4Comments

BassT picture BassT  Â·  3Comments

brennantaylor picture brennantaylor  Â·  4Comments

ghost picture ghost  Â·  3Comments

benjaminhon picture benjaminhon  Â·  3Comments