Build real-time features with GraphQL subscriptions using WebSocket connections and efficient data broadcasting.
# GraphQL Subscriptions for Google Antigravity
GraphQL subscriptions enable real-time data updates over WebSocket connections. This guide covers subscription implementation optimized for Google Antigravity development.
## Apollo Server Subscription Setup
Configure Apollo Server with subscriptions:
```typescript
// lib/graphql/server.ts
import { ApolloServer } from "@apollo/server";
import { expressMiddleware } from "@apollo/server/express4";
import { ApolloServerPluginDrainHttpServer } from "@apollo/server/plugin/drainHttpServer";
import { makeExecutableSchema } from "@graphql-tools/schema";
import { WebSocketServer } from "ws";
import { useServer } from "graphql-ws/lib/use/ws";
import { PubSub } from "graphql-subscriptions";
import express from "express";
import { createServer } from "http";
export const pubsub = new PubSub();
const typeDefs = `#graphql
type Message {
id: ID!
content: String!
author: User!
createdAt: String!
}
type User {
id: ID!
name: String!
avatar: String
}
type Query {
messages(channelId: ID!): [Message!]!
}
type Mutation {
sendMessage(channelId: ID!, content: String!): Message!
}
type Subscription {
messageAdded(channelId: ID!): Message!
userTyping(channelId: ID!): User!
}
`;
const resolvers = {
Query: {
messages: async (_, { channelId }, { db }) => {
return db.message.findMany({
where: { channelId },
include: { author: true },
orderBy: { createdAt: "desc" },
take: 50,
});
},
},
Mutation: {
sendMessage: async (_, { channelId, content }, { db, user }) => {
const message = await db.message.create({
data: {
content,
channelId,
authorId: user.id,
},
include: { author: true },
});
pubsub.publish(`MESSAGE_ADDED_${channelId}`, {
messageAdded: message,
});
return message;
},
},
Subscription: {
messageAdded: {
subscribe: (_, { channelId }) => {
return pubsub.asyncIterator(`MESSAGE_ADDED_${channelId}`);
},
},
userTyping: {
subscribe: (_, { channelId }) => {
return pubsub.asyncIterator(`USER_TYPING_${channelId}`);
},
},
},
};
export async function createGraphQLServer() {
const app = express();
const httpServer = createServer(app);
const schema = makeExecutableSchema({ typeDefs, resolvers });
// WebSocket server for subscriptions
const wsServer = new WebSocketServer({
server: httpServer,
path: "/graphql",
});
const serverCleanup = useServer(
{
schema,
context: async (ctx) => {
const token = ctx.connectionParams?.authorization as string;
const user = await validateToken(token);
return { user };
},
},
wsServer
);
const server = new ApolloServer({
schema,
plugins: [
ApolloServerPluginDrainHttpServer({ httpServer }),
{
async serverWillStart() {
return {
async drainServer() {
await serverCleanup.dispose();
},
};
},
},
],
});
await server.start();
app.use("/graphql", expressMiddleware(server));
return httpServer;
}
```
## Redis PubSub for Scalability
Use Redis for multi-instance pub/sub:
```typescript
// lib/graphql/redis-pubsub.ts
import { RedisPubSub } from "graphql-redis-subscriptions";
import Redis from "ioredis";
const options = {
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT || "6379"),
password: process.env.REDIS_PASSWORD,
retryStrategy: (times: number) => Math.min(times * 50, 2000),
};
export const pubsub = new RedisPubSub({
publisher: new Redis(options),
subscriber: new Redis(options),
});
// With filtering support
export const EVENTS = {
MESSAGE_ADDED: "MESSAGE_ADDED",
USER_TYPING: "USER_TYPING",
PRESENCE_CHANGED: "PRESENCE_CHANGED",
};
// Subscription with filtering
const resolvers = {
Subscription: {
messageAdded: {
subscribe: withFilter(
() => pubsub.asyncIterator(EVENTS.MESSAGE_ADDED),
(payload, variables) => {
return payload.messageAdded.channelId === variables.channelId;
}
),
},
},
};
```
## Client-Side Subscription Hook
Implement React hooks for subscriptions:
```typescript
// hooks/useSubscription.ts
import { useSubscription, gql } from "@apollo/client";
const MESSAGE_SUBSCRIPTION = gql`
subscription OnMessageAdded($channelId: ID!) {
messageAdded(channelId: $channelId) {
id
content
author {
id
name
avatar
}
createdAt
}
}
`;
export function useMessageSubscription(channelId: string) {
const { data, loading, error } = useSubscription(MESSAGE_SUBSCRIPTION, {
variables: { channelId },
onSubscriptionData: ({ subscriptionData }) => {
const newMessage = subscriptionData.data?.messageAdded;
if (newMessage) {
// Update cache or state
console.log("New message:", newMessage);
}
},
});
return { newMessage: data?.messageAdded, loading, error };
}
// Chat component using subscription
function ChatRoom({ channelId }: { channelId: string }) {
const [messages, setMessages] = useState<Message[]>([]);
useMessageSubscription(channelId);
// Subscription automatically updates Apollo cache
const { data } = useQuery(GET_MESSAGES, {
variables: { channelId },
});
return (
<div className="flex flex-col h-full">
<div className="flex-1 overflow-y-auto">
{data?.messages.map((message) => (
<MessageBubble key={message.id} message={message} />
))}
</div>
<MessageInput channelId={channelId} />
</div>
);
}
```
## Best Practices
When implementing GraphQL subscriptions in Antigravity projects, use Redis PubSub for horizontal scaling, implement proper authentication for WebSocket connections, handle reconnection gracefully, use subscription filtering to reduce payload, clean up subscriptions on component unmount, monitor subscription connections for memory leaks, and implement rate limiting on subscription events.This GraphQL prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their graphql implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For GraphQL projects, consider mentioning your framework version, coding style, and any specific libraries you're using.