How to load a .graphql file using `apollo-server`?
Asked Answered
F

6

35

I am currently loading the GraphQL schema using a separate .graphql file, but it is encapsulated within strings:

schema.graphql

const schema = `
  type CourseType {
    _id: String!
    name: String!
  }

  type Query {
    courseType(_id: String): CourseType
    courseTypes: [CourseType]!
  }
`

module.exports = schema

Then using it for the apollo-server:

index.js

const { ApolloServer, makeExecutableSchema } = require('apollo-server')
const typeDefs = require('./schema.graphql')

const resolvers = { ... }

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

const server = new ApolloServer({
  schema: schema
})

server.listen().then(({ url }) => {
  console.log(`Server ready at ${url}.`)
})

Is there any way to simply load a .graphql that looks as such? schema.graphql

type CourseType {
  _id: String!
  name: String!
}

type Query {
  courseType(_id: String): CourseType
  courseTypes: [CourseType]!
}

Then it would be parsed in the index.js? I noticed that graphql-yoga supports this, but was wondering if apollo-server does. I cannot find it anywhere in the docs. I can't get fs.readFile to work either.

Fastback answered 9/6, 2020 at 19:59 Comment(1)
P
44

If you define your type definitions inside a .graphql file, you can read it in one of several ways:

1.) Read the file yourself:

const { readFileSync } = require('fs')

// we must convert the file Buffer to a UTF-8 string
const typeDefs = readFileSync(require.resolve('./type-defs.graphql')).toString('utf-8')

2.) Utilize a library like graphql-tools to do it for you:

const { loadDocuments } = require('@graphql-tools/load');
const { GraphQLFileLoader } = require('@graphql-tools/graphql-file-loader');

// this can also be a glob pattern to match multiple files!
const typeDefs = await loadDocuments('./type-defs.graphql', { 
    file, 
    loaders: [
        new GraphQLFileLoader()
    ]
})

3.) Use a babel plugin or a webpack loader

import typeDefs from './type-defs.graphql'
Pictor answered 9/6, 2020 at 21:33 Comment(8)
This is amazing! No way there's an equivalent GraphQLFileLoader method from apollo-server?Fastback
Maybe in a future version.Pictor
It should be noted that readFileSync only returns a string if you specify an encoding, eg: const typeDefs = readFileSync('./schema.graphql', 'utf-8'). If you do not include an encoding, it returns as a Buffer which ApolloServer's constructor does not understand.Scathing
thank you for noting about 'utf-8' in readFileSync, I would have missed thatBotnick
@DanielRearden I am getting this error when loading a subgraph schema in a federated graph ts Unknown directive "@key". Cannot extend type "Membership" because it is not defined. Unknown directive "@key". Unknown directive "@external". Unknown type "Query". Brashy
@Hazem Alabiad I used the 1st option from this answer and wrapped it within gql for the federated subgraph. const typeDefs = gql(readFileSync(require.resolve('./schema.graphql')).toString('utf-8'));Aaronaaronic
@DanielRearden where is the file variable coming from in the 2nd example ie in the graphql-tools exampleGogh
@DanielRearden did you get this working with Apollo Server-I tried the graphql-tools method with Apollo server, but getting this error: " Unable to find any GraphQL type definitions for the following pointers" - wondering if you need to do anything extra to get it working with Apollo ServerGogh
R
2

Back in the day I wrote a teeny-tiny .graphql loader myself. It is very small, very simple, and the only thing you have to do is import it before you try to import any .graphql files. I have used it ever since even though I am sure that there are some 3rd party loaders available. Here's the code:

// graphql-loader.js

const oldJSHook = require.extensions[".js"];

const loader = (module, filename) => {
  const oldJSCompile = module._compile;
  module._compile = function (code, file) {
    code = `module.exports = \`\r${code}\`;`;
    module._compile = oldJSCompile;
    module._compile(code, file);
  };
  oldJSHook(module, filename);
};

require.extensions[".graphql"] = loader;
require.extensions[".gql"] = loader;

And then in your app:

// index.js

import "./graphql-loader"; // (or require("./graphql-loader") if you prefer)

That's it, you can then import typeDefs from "./type-defs.graphql" wherever you want.

The loader works by wrapping the text in your .graphql file inside a template string and compiling it as a simple JS module:

module.exports = ` ...your gql schema... `;
Riffraff answered 10/6, 2020 at 12:40 Comment(0)
F
1

This worked for me:

const { gql } = require('apollo-server');
const fs = require('fs');
const path = require('path');

//function that imports .graphql files
const importGraphQL = (file) =>{
  return fs.readFileSync(path.join(__dirname, file),"utf-8");
}

const gqlWrapper = (...files)=>{
  return gql`${files}`;
}


const enums = importGraphQL('./enums.graphql');
const schema = importGraphQL('./schema.graphql');

module.exports = gqlWrapper(enums,schema);

Forecast answered 10/12, 2020 at 5:56 Comment(0)
T
1

I use this helper:

import { readFileSync } from "fs";
const requireGQL = (file) =>
  gql`${readFileSync(require.resolve(file)).toString("utf-8")}`;

Throw that at the top of your file and you can just:

const client = new ApolloClient({ uri: 'https://myendpoint.com/graphql' });
const { data } = await client.query({ query: requireGQL("./myquery.gql") });
Tomasatomasina answered 23/7, 2022 at 16:38 Comment(0)
W
1

For anyone who is looking for the Apollo documentation for this question here it is: https://www.apollographql.com/docs/apollo-server/workflow/generate-types

It describes using readFileSync like many answers here, but I was having trouble finding where they actually describe this method. Here's the snippet as well:

// ...other imports

import { readFileSync } from 'fs';


// Note: this uses a path relative to the project's

// root directory, which is the current working directory

// if the server is executed using `npm run`.

const typeDefs = readFileSync('./schema.graphql', { encoding: 'utf-8' });


const server = new ApolloServer<MyContext>({

  typeDefs,

  resolvers,

});


// ... start our server
Wilhelmstrasse answered 4/10, 2023 at 3:29 Comment(0)
F
0

Figured it out using fs (thanks to Tal Z):

index.js

const fs = require('fs')
const mongoUtil = require('./mongoUtil')
const { ApolloServer, makeExecutableSchema } = require('apollo-server')

function readContent (file, callback) {
  fs.readFile(file, 'utf8', (err, content) => {
    if (err) return callback(err)
    callback(null, content)
  })
}

mongoUtil.connectToServer((error) => {
  if (error) {
    console.error('Error connecting to MongoDB.', error.stack)
    process.exit(1)
  }

  console.log('Connected to database.')

  const Query = require('./resolvers/Query')

  const resolvers = {
    Query
  }

  readContent('./schema.graphql', (error, content) => {
    if (error) throw error

    const schema = makeExecutableSchema({
      typeDefs: content,
      resolvers
    })

    const server = new ApolloServer({
      schema: schema
    })

    server.listen().then(({ url }) => {
      console.log(`Server ready at ${url}.`)
    })
  })
})

schema.graphql

type CourseType {
  _id: String!
  name: String!
}

type Query {
  courseType(_id: String): CourseType
  courseTypes: [CourseType]!
}
Fastback answered 9/6, 2020 at 20:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.