GraphQL批量查询图书数据:如何用GraphQLList遍历ISBN数组
如何在GraphQL中实现批量图书查询(对接Amazon/Itunes API)
看起来你已经有了单本图书查询的基础,要实现批量查询其实只需要调整几个关键地方:参数类型改为数组、批量处理API请求,以及调整返回结构匹配你的需求。我来一步步给你修改示例:
1. 调整RootQuery:支持接收ID数组并批量返回数据
首先要把id参数的类型从单个字符串改成字符串数组,这里就用到了你提到的GraphQLList。同时,我们需要在resolve函数里遍历每个ID,并行发起API请求,最后整理成你期望的响应格式。
修改后的RootQuery.js代码:
const graphql = require('graphql'); const { GraphQLObjectType, GraphQLString, GraphQLList } = graphql; const BookType = require('../types/book'); const RootQuery = new GraphQLObjectType({ name:'RootQuery', fields: () => ({ book: { // 自定义类型匹配你需要的对象结构(book1、book2...) type: new GraphQLObjectType({ name: 'BookBatchResult', fields: () => ({}) }), args:{ id : { type: new GraphQLList(GraphQLString) } // 用GraphQLList接收ID数组 }, async resolve (parentValue, args) { // 遍历每个ID,创建获取单本图书数据的Promise const bookTasks = args.id.map(async (bookId) => { // 仅返回ID,BookType里的itunes/amazon字段会自动触发对应resolve return { id: bookId }; }); // 等待所有请求完成 const books = await Promise.all(bookTasks); // 转换为你需要的book1、book2格式 const result = {}; books.forEach((book, index) => { result[`book${index + 1}`] = book; }); return result; } } }) }); module.exports = RootQuery;
2. 修复BookType的异步处理逻辑
你的BookType里的resolve函数没有处理异步操作,而调用Amazon/Itunes API肯定是异步的,所以必须改成async/await确保数据正确返回,同时处理无数据的情况:
修改后的BookType.js代码:
const graphql = require('graphql'); const { GraphQLObjectType, GraphQLString } = graphql; const itunes = require('../connections/itunes'); const ItunesType = require('./itunes'); const amazon = require('../connections/amazon'); const AmazonType = require('./amazon'); const BookType = new GraphQLObjectType({ name:'book', fields: () => ({ id: { type: GraphQLString }, itunes: { type: ItunesType, async resolve(parentValue){ try { const data = await itunes.getMetadataItunes(parentValue.id); // API返回空时返回"不可用"提示 return data || { title: "Niet beschikbaar" }; } catch (err) { // 捕获错误,返回统一提示 return { title: "Niet beschikbaar" }; } } }, amazon: { type: AmazonType, async resolve(parentValue) { try { const data = await amazon.getMetadataAmazon(parentValue.id); return data || { title: "Niet beschikbaar" }; } catch (err) { return { title: "Niet beschikbaar" }; } } } }) }); module.exports = BookType;
3. 可选:改用数组返回(更符合GraphQL规范)
其实GraphQL更推荐返回数组格式,因为它的结构更灵活,前端处理起来也更简单。如果改成数组返回,你只需要把RootQuery里的返回类型改成new GraphQLList(BookType),resolve直接返回await Promise.all(bookTasks)即可:
修改后的RootQuery片段:
book: { type: new GraphQLList(BookType), // 返回BookType数组 args:{ id : { type: new GraphQLList(GraphQLString) } }, async resolve (parentValue, args) { const bookTasks = args.id.map(async (bookId) => { return { id: bookId }; }); return await Promise.all(bookTasks); } }
对应的响应会变成:
{ "data": { "book": [ { "amazon": { "title": "De Moord op Commendatore" }, "itunes": { "title": "Niet beschikbaar" } }, { "amazon": { "title": "Origin" }, "itunes": { "title": "Origin" } } ] } }
前端可以用一行代码把数组转成你想要的对象格式:
const bookObj = books.reduce((acc, book, idx) => ({...acc, [`book${idx+1}`]: book}), {})
关键知识点总结
- GraphQLList的使用:在RootQuery的
args里给id字段指定new GraphQLList(GraphQLString),就能接收ID数组了。 - 异步处理:所有API请求必须用
async/await或Promise处理,否则GraphQL无法获取异步返回的数据。 - 错误处理:在resolve里加上try/catch,避免单个API请求失败导致整个批量查询崩溃。
内容的提问来源于stack exchange,提问作者Elvira
相关产品推荐
相关产品推荐

