Node.js微服务中Promise.all调用apolloFetch返回空查询错误求助
Fixing Empty Query Error with Promise.all & apolloFetch in Node.js Microservices
Let's break down the issues in your code that are causing the empty query error and fix them step by step:
Key Problems in Your Current Code
- Premature
resolve()call: You're callingresolve(results)before setting up and executing yourPromise.allbatch. Onceresolve()is invoked, your GraphQL resolver's promise is marked as fulfilled, and any subsequent code runs independently—this can lead to incomplete execution or context issues that break your apolloFetch calls. - Incorrect apolloFetch parameter format: You're passing
{p}to apolloFetch, which creates an object with apkey instead of the requiredquerykey. The remote GraphQL service can't find your query content, hence the empty query error. - Redundant JSON serialization/deserialization: Converting
resultsto a string and back to JSON is unnecessary—resultsis already an array of objects from your database query.
Corrected Code
Here's the fixed version with explanations of critical changes:
const uri = "dsc.xxx.yyyy.com/abc/def/graphql"; const apolloFetch = CreateApolloFetch({uri}); const QryAllBooks = { type: new GraphQLList(BookType), args: {}, resolve() { return new Promise((resolve, reject) => { const sql = singleLineString` select distinct t.bookid,t.bookname,t.country from books_tbl t where t.ship_status = 'Not Shipped' `; pool.query(sql, (err, results) => { if (err) { // Early return to avoid executing further code on error return reject(err); } // Map results directly to apolloFetch promises (no redundant JSON conversion) const promises = results.map(book => { const bookId = book.bookid; const mutationQuery = `mutation updateShipping { updateShipping (id: ${bookId}, input:{ status: "Shipped" }) { bookid bookname } }`; // Pass query using the required "query" key return apolloFetch({ query: mutationQuery }); }); // Wait for all mutations to complete before resolving the resolver Promise.all(promises) .then(() => { console.log("All shipping status updates completed!"); resolve(results); // Resolve with original results after mutations succeed }) .catch((e) => { FunctionLogError(29, "Error", e); reject(e); // Ensure errors are propagated to the resolver }); }); }); } }; module.exports = { QryAllBooks, BookType };
Additional Optimizations
1. Use Async/Await for Cleaner Code
If your Node.js environment supports async/await (Node 8+), rewrite the resolver to avoid promise nesting:
const QryAllBooks = { type: new GraphQLList(BookType), args: {}, async resolve() { try { // Wrap pool.query in a promise for async/await compatibility const results = await new Promise((resolveQuery, rejectQuery) => { const sql = singleLineString` select distinct t.bookid,t.bookname,t.country from books_tbl t where t.ship_status = 'Not Shipped' `; pool.query(sql, (err, res) => { if (err) rejectQuery(err); else resolveQuery(res); }); }); const promises = results.map(book => { const mutationQuery = `mutation updateShipping { updateShipping (id: ${book.bookid}, input:{ status: "Shipped" }) { bookid bookname } }`; return apolloFetch({ query: mutationQuery }); }); await Promise.all(promises); console.log("All shipping status updates completed!"); return results; } catch (e) { FunctionLogError(29, "Error", e); throw e; // Throw error to let GraphQL handle it } } };
2. Avoid GraphQL Injection Risks with Variables
Directly interpolating bookId into your mutation string carries a small injection risk. Instead, use GraphQL variables for safer parameter passing:
const promises = results.map(book => { const mutationQuery = ` mutation updateShipping($bookId: ID!, $status: String!) { updateShipping(id: $bookId, input:{ status: $status }) { bookid bookname } } `; return apolloFetch({ query: mutationQuery, variables: { bookId: book.bookid, status: "Shipped" } }); });
This follows GraphQL best practices and eliminates any potential injection vulnerabilities.
内容的提问来源于stack exchange,提问作者Roger Dodger
相关产品推荐
相关产品推荐

