GraphQL subscriptions:实时数据更新

GraphQL Subscriptions 是 GraphQL 规范的一部分,它允许客户端订阅服务器上的实时数据变化。当服务器端的数据发生变化时,订阅的客户端会收到实时更新。

以 Hasura 为例,Hasura 是一个流行的 GraphQL 引擎,支持实时数据流。

Hasura实时数据流

首先,你需要在 Hasura 控制台上启用 GraphQL Subscriptions 功能,并创建一个订阅。假设我们有一个 messages 表,并且想要在有新消息时通知客户端:

graphql 复制代码
subscription NewMessage {
  messages(where: { created_at: { _gt: NOW() } }) {
    id
    content
    user {
      name
    }
  }
}

这个订阅会监听 messages 表中创建时间大于当前时间的消息。

在客户端,你可以使用 Apollo Client 或其他 GraphQL 客户端库来处理订阅。以下是一个使用 Apollo Client 的示例:

javascript 复制代码
import { useSubscription } from '@apollo/client';
import gql from 'graphql-tag';

const NEW_MESSAGE_SUBSCRIPTION = gql`
  subscription NewMessage {
    messages(where: { created_at: { _gt: NOW() } }) {
      id
      content
      user {
        name
      }
    }
  }
`;

function MessageFeed() {
  useSubscription(NEW_MESSAGE_SUBSCRIPTION, {
    onSubscriptionData: ({ subscriptionData }) => {
      console.log('New message:', subscriptionData.data.messages);
      // 更新 UI 或存储新消息
    },
    errorPolicy: 'all', // 处理错误
  });

  // 渲染 UI 逻辑
  ...
}

useSubscription 是 Apollo Client 提供的 Hook,它会处理订阅的生命周期。当有新的订阅数据到来时,onSubscriptionData 回调会被调用,你可以在这里处理新数据,比如更新 UI。

注意,为了使订阅工作,你需要配置 Apollo Client 以连接到 Hasura 的 WebSocket endpoint,通常以 /v1/graphql 结尾,例如:

javascript 复制代码
import { ApolloClient, InMemoryCache, createHttpLink, split } from '@apollo/client';
import { getMainDefinition } from '@apollo/client/utilities';
import { WebSocketLink } from '@apollo/client/link/ws';

const httpLink = createHttpLink({
  uri: 'http://localhost:8080/v1/graphql',
});

const wsLink = new WebSocketLink({
  uri: 'ws://localhost:8080/v1/graphql',
  options: {
    reconnect: true,
  },
});

const link = split(
  // 使用 `getMainDefinition` 来区分普通查询和订阅
  ({ query }) => {
    const definition = getMainDefinition(query);
    return (
      definition.kind === 'OperationDefinition' &&
      definition.operation === 'subscription'
    );
  },
  wsLink,
  httpLink,
);

const client = new ApolloClient({
  link,
  cache: new InMemoryCache(),
});

这样,客户端就可以接收来自 Hasura 的实时消息更新了。请注意,实际部署时,你需要替换 localhost 和端口号为你的 Hasura 实例的实际地址和端口。

自定义 Subscription 服务端

如果你不使用像 Hasura 这样的现成解决方案,而是在自己的服务器上实现 GraphQL Subscriptions,你可能需要使用 GraphQL 框架,如 Apollo Server 或 GraphQL Yoga,来设置 WebSocket 连接。

安装必要的依赖

首先,确保安装了 apollo-server-expresssubscriptions-transport-ws

bash 复制代码
npm install apollo-server-express subscriptions-transport-ws graphql

设置服务器

接下来,创建一个简单的 Apollo Server,并配置 Subscription:

javascript 复制代码
const { ApolloServer, gql } = require('apollo-server-express');
const { createServer } = require('http');
const { SubscriptionServer } = require('subscriptions-transport-ws');
const express = require('express');

// 定义 GraphQL Schema
const typeDefs = gql`
  type Query {
    hello: String
  }
  
  type Subscription {
    newMessage: Message
  }

  type Message {
    id: ID!
    content: String!
    createdAt: String!
  }
`;

// 实现 resolver
const messages = [];
let nextMessageId = 1;

const resolvers = {
  Query: {
    hello: () => 'Hello world!',
  },
  Subscription: {
    newMessage: {
      subscribe: () => pubsub.asyncIterator('NEW_MESSAGE'),
    },
  },
};

// 使用 PubSub 发布订阅模式
const { PubSub } = require('graphql-subscriptions');
const pubsub = new PubSub();

// 模拟新消息的发布
setInterval(() => {
  const content = `Message ${nextMessageId}`;
  messages.push({ id: nextMessageId++, content, createdAt: new Date().toISOString() });
  pubsub.publish('NEW_MESSAGE', { newMessage: messages[messages.length - 1] });
}, 5000);

const server = new ApolloServer({ typeDefs, resolvers });

const app = express();
server.applyMiddleware({ app });

const httpServer = createServer(app);
server.installSubscriptionHandlers(httpServer);

httpServer.listen({ port: 4000 }, () =>
  console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`)
);

// 设置 SubscriptionServer
new SubscriptionServer({
  execute,
  subscribe,
  schema,
  onConnect: (connectionParams, webSocket, context) => {
    console.log('Client connected!');
    return context; // 可以在此处添加认证逻辑
  },
  onDisconnect: (webSocket, context) => {
    console.log('Client disconnected!');
  },
}, {
  server: httpServer,
  path: server.subscriptionsPath,
});

这段代码创建了一个简单的 Apollo Server,它提供了一个查询 hello 和一个订阅 newMessage。服务器每5秒模拟一次新消息,并通过 pubsub.publish 发布到 NEW_MESSAGE 主题,所有订阅该主题的客户端都会收到更新。

客户端连接

客户端连接到 WebSocket 端点的方式与之前使用 Apollo Client 的示例相似,只需确保连接到正确的 WebSocket 地址(通常是 /graphql 后面加上 subscriptions 路径,具体取决于你的服务器配置)。

通过这种方式,你可以实现在自定义服务器上从零开始搭建 GraphQL Subscriptions,为应用程序提供实时数据更新功能。

相关推荐
糕冷小美n4 小时前
elementuivue2表格不覆盖整个表格添加固定属性
前端·javascript·elementui
小哥不太逍遥5 小时前
Technical Report 2024
java·服务器·前端
沐墨染5 小时前
黑词分析与可疑对话挖掘组件的设计与实现
前端·elementui·数据挖掘·数据分析·vue·visual studio code
anOnion5 小时前
构建无障碍组件之Disclosure Pattern
前端·html·交互设计
threerocks5 小时前
前端将死,Agent 永生
前端·人工智能·ai编程
问道飞鱼6 小时前
【前端知识】Vite用法从入门到实战
前端·vite·项目构建
爱上妖精的尾巴6 小时前
8-10 WPS JSA 正则表达式:贪婪匹配
服务器·前端·javascript·正则表达式·wps·jsa
shadow fish7 小时前
react学习记录(三)
javascript·学习·react.js
小疙瘩7 小时前
element-ui 中 el-upload 多文件一次性上传的实现
javascript·vue.js·ui
Aliex_git7 小时前
浏览器 API 兼容性解决方案
前端·笔记·学习