Add streaming support: GraphQL subscriptions over Server-Sent Events - #21
Merged
Merged
Conversation
Co-authored-by: charles2ke <6725706+charles2ke@users.noreply.github.com>
Copilot created this pull request from a session on behalf of
charles2ke
September 16, 2026 02:44
View session
charles2ke
marked this pull request as ready for review
September 16, 2026 02:45
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved security, backpressure, cleanup, error-handling, and test-coverage issues remain.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds GraphQL subscriptions over Server-Sent Events with shared schema execution and in-process pub/sub.
Changes:
- Adds subscription schema, resolvers, and event publication.
- Implements
/graphql/streamwith heartbeats and disconnect cleanup. - Adds tests, documentation, and dependency updates.
File summaries
| File | Description |
|---|---|
test/streaming.test.js |
Streaming and pub/sub tests |
src/streaming/sseRouter.js |
SSE request handling and GraphQL execution |
src/streaming/pubsub.js |
Bounded in-process async pub/sub |
src/server.js |
Apollo executable schema integration |
src/schema.js |
Subscription schema and executable schema factory |
src/resolvers.js |
Subscription resolvers and event publishing |
src/index.js |
SSE route and shared context wiring |
README.md |
SSE usage documentation |
package.json |
Direct schema dependency |
package-lock.json |
Dependency lockfile updates |
Review details
Suppressed comments (2)
src/resolvers.js:60
- The streaming tests publish directly through
app.pubsub, while the existing GraphQL tests only assert mutation results, so a regression in this new mutation-to-pub/sub bridge would pass. Add an end-to-end assertion that executescreateUser/createPostthrough the GraphQL mutation path and observes the matching SSE frame.
createUser: (_parent, { name, email }, { store, pubsub = defaultPubSub }) => {
const user = store.createUser({ name, email });
pubsub.publish(TOPICS.USER_CREATED, { userCreated: user });
return user;
src/streaming/pubsub.js:44
- With
maxQueueSize: 0(or any negative value), this condition is always true, butshift()on an empty queue is a no-op and the followingpush()still stores every payload. The supposedly bounded queue can therefore grow without limit; reject non-positive sizes or explicitly drop payloads when zero buffering is intended.
if (queue.length >= maxQueueSize) queue.shift();
queue.push(payload);
- Files reviewed: 9/10 changed files
- Comments generated: 5
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: charles2ke <6725706+charles2ke@users.noreply.github.com>
Co-authored-by: charles2ke <6725706+charles2ke@users.noreply.github.com>
…ure, test mutation streaming Co-authored-by: charles2ke <6725706+charles2ke@users.noreply.github.com>
…ket errors Co-authored-by: charles2ke <6725706+charles2ke@users.noreply.github.com>
charles2ke
approved these changes
Sep 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The service had no way to push data to clients — every operation was a one-shot request/response. This adds a
Subscriptionroot type and an SSE transport so clients can stream results over plain HTTP, without a WebSocket upgrade or an external broker.Changes
src/streaming/pubsub.js— in-process pub/sub returning async iterators. Bounded per-subscriber queue (oldest events dropped), cleanup onreturn()/abort. Swappable for a Redis/NATS backend behind the samepublish/subscribecontract.src/schema.js— addsSubscription { userCreated, postCreated(authorId) }and acreateSchema()factory so Apollo Server and the streaming endpoint execute against one schema instance.src/resolvers.js— subscription resolvers (with optional author filtering);createUser/createPostpublish their results.pubsubcomes from context with a module-level default.src/streaming/sseRouter.js—GET|POST /graphql/streamaccepting the usualquery/variables/operationName. Subscriptions emit oneevent: nextper result thenevent: complete; queries and mutations emit a single pair, so one client transport covers all operation types. Includes comment-frame heartbeats andAbortController-based teardown on client disconnect.src/index.js— mounts the router ahead of/graphqland threadspubsubinto both contexts.test/streaming.test.js; README documents the endpoint, frame format, and the single-instance caveat.Note:
@graphql-tools/schemais promoted from a transitive dependency of@apollo/serverto a direct one, sincecreateSchema()now builds the executable schema explicitly.