GraphQL:完成来自 JSON 文件源的查询

GraphQL: fulfill query from JSON file source

我刚刚开始使用 GraphQL,我想要一个使用磁盘上的 JSON 文件作为数据源的解析器。到目前为止我得到的结果导致 GraphQL return null.

我该怎么做,为什么下面的方法不起作用?

var schema = buildSchema(`
type Experiment {
    id: String
    trainData: String
    goldData: String
    gitCommit: String
    employee: String
    datetime: String
}

type Query {
    # Metadata for an individual experiment
    experiment: Experiment
}

schema {
    query: Query
}`);

var root = {
    experiment: () => {
        fs.readFile('./data/experimentExample.json', 'utf8', function(err, data) {  
            if (err) throw err;
            console.log(data);
            return JSON.parse(data);
        });
    }
};  

const app = express();

app.use('/graphql', graphqlHTTP({
  rootValue: root,
  schema: schema,
  graphiql: true
}));

app.listen(4000);
console.log('Running a GraphQL API server at localhost:4000/graphql'); 

您传递给 readFile 的回调函数异步运行,这意味着 return 从中获取值不会执行任何操作 - readFile 调用的函数是内部已完成执行,并在回调完成时 return 编辑了一个值(空)。

根据经验,在处理 GraphQL 时,您应该远离回调——您的解析器应该始终 return 一个值或一个最终会解析为一个值的 Promise。

幸运的是,fs 有一个异步读取文件的方法,所以你可以这样做:

const root =  {
  experiment: () => {
    const file = fs.readFileSync('./data/experimentExample.json', 'utf8')
    return JSON.parse(file)
  }
};
// or even cleaner:
const root =  {
  experiment: () => JSON.parse(fs.readFileSync('./data/experimentExample.json', 'utf8'))
};

再举一个例子,下面是使用 Promise 的方法:

// using Node 8's new promisify for our example
const readFileAsync = require('util').promisify(fs.readFile)

const root =  {
  experiment: () => readFileAsync('./data/experimentExample.json', {encoding: 'utf8'})
    .then(data => JSON.parse(data))
};
// Or with async/await:
const root =  {
  experiment: async () => JSON.parse(await readFileAsync('./data/experimentExample.json', {encoding: 'utf8'}))
};

当然没有必要对 readFile 进行承诺,因为您已经有了可用的异步方法,但这让您了解了如何使用 Promises,而 GraphQL 很乐意与之合作。