Loading GraphQL Schemas from Different Sources
These utils are useful for scanning, loading and building a GraphQL schema from any input.
You can specify a GraphQL endpoint, local introspection JSON file, code file that export
s a
GraphQLSchema, AST string and .graphql
files (with support for glob
expression).
All found schema files can be merged into a complete schema. There is support for #import
syntax
(formerly known as graphql-import
).
The user is given the option of implementing their own loader (implement the interface
SchemaLoader
).
The schema loading until is using loaders, and implemented using chain-of-responsibility pattern.
Specifying the loader is not necessary. The user needs only provide the inputs. The utils will detect it automatically.
For notes on typescript, refer to loaders
Schema and document loading doesn’t work non Node.js environments, and if you are using a bundler like webpack, rollup or Vite, you cannot use dynamic loaders.
Load typeDefs
/DocumentNode
and resolvers
from Files
const { loadFiles } = require('@graphql-tools/load-files')
const { createYoga, createSchema } = require('graphql-yoga')
const { createServer } = require('http')
async function main() {
const schema = createSchema({
typeDefs: await loadFiles('src/typeDefs/**/*.graphql'),
resolvers: await loadFiles('src/resolvers/**/*.{js,ts}')
})
const yoga = createYoga({
schema
})
const server = createServer(yoga)
server.listen(4000, () => {
console.log('Server is running on http://localhost:4000')
})
}
main().catch(error => {
console.error(error)
process.exit(1)
})
loadFiles
doesn’t support #import
syntax. See below if you need that.
Load GraphQLSchema
by Using Different Loaders from Different Sources
const { loadSchema } = require('@graphql-tools/load')
const { UrlLoader } = require('@graphql-tools/url-loader')
const { JsonFileLoader } = require('@graphql-tools/json-file-loader')
const { GraphQLFileLoader } = require('@graphql-tools/graphql-file-loader')
async function main() {
// Load from string w/ no loaders
const schema1 = await loadSchema('type A { foo: String }')
// Load from endpoint
const schema2 = await loadSchema('http://localhost:3000/graphql', { loaders: [new UrlLoader()] })
// Load from local json file
const schema3 = await loadSchema('./schema.json', { loaders: [new JsonFileLoader()] })
// Load from a single schema file
const schema4 = await loadSchema('schema.graphql', { loaders: [new GraphQLFileLoader()] })
// Load from multiple files using glob
const schema5 = await loadSchema('./src/**/*.graphql', { loaders: [new GraphQLFileLoader()] })
}
main()
Using #import
Expression
Assume the following directory structure:
.
├── schema.graphql
├── posts.graphql
└── comments.graphql
#import Post from "posts.graphql"
type Query {
posts: [Post]
}
#import Comment from 'comments.graphql'
type Post {
comments: [Comment]
id: ID!
text: String!
tags: [String]
}
type Comment {
id: ID!
text: String!
}
Running loadSchema
produces the following output:
type Query {
posts: [Post]
}
type Post {
comments: [Comment]
id: ID!
text: String!
tags: [String]
}
type Comment {
id: ID!
text: String!
}
Binding to HTTP Server
You can extend the loaded schema with resolvers
import { createServer } from 'http'
import { join } from 'node:path'
import { createYoga } from 'graphql-yoga'
import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader'
import { loadSchema } from '@graphql-tools/load'
import { addResolversToSchema } from '@graphql-tools/schema'
async function main() {
// Load schema from the file
const schema = await loadSchema(join(__dirname, './schema.graphql'), {
loaders: [new GraphQLFileLoader()]
})
// Write some resolvers
const resolvers = {}
// Add resolvers to the schema
const schemaWithResolvers = addResolversToSchema({ schema, resolvers })
const yoga = createYoga({
schema: schemaWithResolvers
})
const server = createServer(yoga)
server.listen(4000, () => {
console.log('Server is running on http://localhost:4000')
})
}
main().catch(error => {
console.error(error)
process.exit(1)
})
Loaders
There are a lot of loaders that load your schemas and documents from different sources. You need to
provide those loaders under loaders
parameter like below:
Watch Episode #22 of
graphql.wtf
for
a quick introduction to file loaders:
GraphQLFileLoader
This loader loads your GraphQLSchema from .graphql
files like below:
import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader'
import { loadSchema } from '@graphql-tools/load'
import { addResolversToSchema } from '@graphql-tools/schema'
// schema is `GraphQLSchema` instance
const schema = await loadSchema('schema.graphql', {
// load from a single schema file
loaders: [new GraphQLFileLoader()]
})
// You can add resolvers to that schema
const schemaWithResolvers = addResolversToSchema({
schema,
resolvers: {
Query: {
// ...
}
}
})
This loader also supports glob pattern;
import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader'
import { loadSchema } from '@graphql-tools/load'
const schema = await loadSchema('graphql/**/*.graphql', {
// load files and merge them into a single schema object
loaders: [new GraphQLFileLoader()]
})
If you use loadDocuments
, it gives you an array of document source objects;
import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader'
import { loadDocuments } from '@graphql-tools/load'
const documents = await loadDocuments('graphql/**/*.graphql', {
// load files and merge them into a single schema object
loaders: [new GraphQLFileLoader()]
})
This loader only supports Node environment because it relies on File System of your platform.
JsonFileLoader
This loader handles schema introspection and document nodes in .json
files.
Introspection is handled in the example below:
import { JsonFileLoader } from '@graphql-tools/json-file-loader'
import { loadSchema } from '@graphql-tools/load'
import { addMocksToSchema } from '@graphql-tools/mock'
const schema = await loadSchema('schema-introspection.json', {
loaders: [new JsonFileLoader()]
})
// Mocked non-executable schema generated from an introspection
const mockedSchema = addMocksToSchema({ schema })
This loader handles json
files if they represent DocumentNode
, and returns an array of document
sources.
import { JsonFileLoader } from '@graphql-tools/json-file-loader'
import { loadDocuments } from '@graphql-tools/load'
const documents = await loadDocuments('**/*-document.json', {
loaders: [new JsonFileLoader()]
})
This loader only supports Node environment because it relies on File System of your platform.
CodeFileLoader
This loader extracts GraphQL SDL string, exported GraphQLSchema
and DocumentNode
from TypeScript
and JavaScript code files. Let’s say you have the following code file;
const ME_QUERY = gql`
query Me {
me {
id
name
username
age
}
}
`
And the following code will extract Me
query operation from that code file without executing it
using GraphQL Tag Pluck. It understands /* GraphQL */
magic comment and
gql
literals. You can configure GraphQL Tag Pluck using pluckConfig
.
import { CodeFileLoader } from '@graphql-tools/code-file-loader'
import { loadDocuments } from '@graphql-tools/load'
const documents = await loadDocuments('./src/**/graphql/*.ts', {
loaders: [new CodeFileLoader()],
pluckConfig: {
// ...
}
})
You can also load your schema from code files like below:
import { GraphQLSchema } from 'graphql'
// typeDefs.ts
export const typeDefs = /* GraphQL */ `
type Query {
foo: String
}
`
// or schema.ts
export const schema = new GraphQLSchema(/* ... */)
This loader only supports Node.js environment because it relies on File System of your platform.
Note: If you are using typescript and path aliases, you may also need tsconfig-paths. Further reading can be found at the GitHub issue.
UrlLoader
This loader generates (a fully executable remote schema using @graphql-tools/wrap) from a URL endpoint.
import { loadSchema } from '@graphql-tools/load'
import { UrlLoader } from '@graphql-tools/url-loader'
const schema = await loadSchema('http://localhost:3000/graphql', {
loaders: [new UrlLoader()]
})
You can provide custom headers, HTTP method and custom W3C fetch method.
import { loadSchema } from '@graphql-tools/load'
import { UrlLoader } from '@graphql-tools/url-loader'
const schema = await loadSchema('http://localhost:3000/graphql', {
loaders: [new UrlLoader()],
headers: {
Accept: 'application/json'
},
method: 'POST',
fetch: myFetch
})
In browser this remote schema can be called using vanilla GraphQL-js and act like a simple GraphQL client.
import { graphql } from 'graphql'
import { loadSchema } from '@graphql-tools/load'
import { UrlLoader } from '@graphql-tools/url-loader'
const schema = await loadSchema('http://localhost:3000/graphql', {
loaders: [new UrlLoader()]
})
const response = await graphql(
schema,
/* GraphQL */ `
{
foo {
bar {
baz
}
}
}
`
)
console.log(response)