apollographql / apollographql/graphql-subscriptions

Internal error occurred during message handling. Please check your implementation. Error: Subscription field must return Async Iterable. Received: undefined.

Open
#273 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
1.6k
Forks
129
PR merge metrics
No merged PRs in 30d

Description

+app.js
const express = require("express")
const { createHandler } = require("graphql-http/lib/use/express")
const { ruruHTML } = require("ruru/server")
const dotenv = require("dotenv");
const schema=require('./schema/index')
const cors = require('cors');
const { WebSocketServer } = require('ws');
const {createServer}=require('http')
const { execute, subscribe } = require('graphql');
const { useServer } = require('graphql-ws/lib/use/ws');

const app = express();
// This `app` is the returned value from `express()`.
const httpServer = createServer(app);

app.use(express.json());
app.use(cors());

dotenv.config({ path: "./config.env" });


// Serve the GraphiQL IDE.
app.get("/", (_req, res) => {
res.type("html")
res.end(ruruHTML({ endpoint: "/graphql" }))
})
// Create and use the GraphQL handler.
app.all(
"/graphql",
createHandler({
schema: schema,

})
)

// Create WebSocket server for subscriptions
const wsServer = new WebSocketServer({
server: httpServer, // Correctly use the 'server' option
path: '/subscriptions',
});

useServer({ schema, execute, subscribe }, wsServer);

module.exports = {
app,
httpServer

};

+resolver
// dyanmicResolver.js
const pool = require('../database/config')
const { publishUserAdded } = require('../subscription/subscriptionHandler'); // Adjust path as per your file structure

const dyanmicResolver = {
Query: {
users: async () => {
const client = await pool.connect();
try {
const res = await client.query('SELECT * FROM users');
return res.rows;
}catch(err){
console.log("faile to fetch users",err)
}
finally {
client.release();
}
},
authors: async () => {
const client = await pool.connect();
try {
const res = await client.query('SELECT * FROM author');
return res.rows;
} catch(err){
console.log("failed to fetch authors",err)
}
finally {
client.release();
}
},
books: async () => {
const client = await pool.connect();
try {
const res = await client.query('SELECT * FROM book');
return res.rows;
} catch(err){
console.log("failed to fetch book",err)
}
finally {
client.release();
}
},

},
Mutation: {
insertUser: async (_, { username, email }) => {
const client = await pool.connect();
try {
const query = 'INSERT INTO users (username, email) VALUES ($1, $2) RETURNING *';
const values = [ username, email];
const res = await client.query(query, values);
const newUser = res.rows[0];


// Publish subscription event
await publishUserAdded(newUser);
console.log("user add",USER_ADDED)
return newUser;
}catch(err){
console.log("failed to insert users",err)
}
finally {
client.release();
}
},

updateUser: async (_, { id, username, email }) => {
const client = await pool.connect();
try {
const query = 'UPDATE users SET username = $2, email = $3 WHERE id = $1 RETURNING *';
const values = [id, username, email];
const res = await client.query(query, values);
return res.rows[0];
}catch(err){
console.log("failed to update users",err)
}
finally {
client.release();
}
},

deleteUser: async (_, { id }) => {
const client = await pool.connect();
try {
const query = 'DELETE FROM users WHERE id = $1 RETURNING *';
const values = [id];
const res = await client.query(query, values);
return res.rows[0];
} catch(err){
console.log("failed to delete user",err)
}
finally {
client.release();
}
},

},


};

module.exports = dyanmicResolver;

+ subscriptionHandler.js
nst { PostgresPubSub } = require('graphql-postgres-subscriptions');
const dotenv = require('dotenv');

dotenv.config({ path: "../config.env" });

const pubsub = new PostgresPubSub({
connectionString: process.env.DATABASE_URL, // Make sure this environment variable is set correctly
});

const USER_ADDED_TOPIC = 'userAdded';

// Subscription resolver
const Subscription = {
userAdded: {
subscribe: () => pubsub.asyncIterator(USER_ADDED_TOPIC),

},
};

// Helper function to publish events
async function publishUserAdded(newUser) {
try {
await pubsub.publish(USER_ADDED_TOPIC, { userAdded: newUser });
} catch (err) {
console.error('Error publishing userAdded event:', err);
}
}

module.exports = {
Subscription,
publishUserAdded,
};

+client vue3 calling graphql

const USER_ADDED_SUBSCRIPTION = gql`
subscription {
userAdded {
id
username
email
}
}
`;

const subscribeToNewUsers = () => {
try {
apolloClient.subscribe({
query: USER_ADDED_SUBSCRIPTION,
}).subscribe({
next({ data }) {
users.value = [...users.value, data.userAdded];
},
error(err) {
console.error('Subscription error', err);
error.value = err; // Update error message
}
});
} catch (err) {
console.log("failed to subscribe", err);
error.value = err
}

};

onMounted(async () => {
try {
const { data } = await apolloClient.query({
query: GET_USERS,
});
users.value = data.users;
loading.value = false;

subscribeToNewUsers(); // Start subscription after initial data load
} catch (e) {
console.error("Query error", e);
error.value = e.message; // Handle query error
loading.value = false;
}
});

when i run test in client vue3 cli it say Error: Socket closed with event 4500 Subscription field must return Async Iterable. Received: undefined.

```[tasklist]
### Tasks
```

Contributor guide

Open the contributing guide

Research direction

Start by inspecting schema/index and how the exported Subscription resolver from subscriptionHandler.js is incorporated into the schema used by app.js. Then run the Vue 3 subscription against the /subscriptions WebSocket endpoint and verify that userAdded returns an async iterable and delivers the published user event.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js, postgresql
Domain
api, backend, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.