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,为应用程序提供实时数据更新功能。

相关推荐
化作繁星28 分钟前
vue3项目图片压缩+rem+自动重启等plugin使用与打包配置
前端·vue·vite
u0104058361 小时前
构建可扩展的Java Web应用架构
java·前端·架构
swimxu1 小时前
npm 淘宝镜像证书过期,错误信息 Could not retrieve https://npm.taobao.org/mirrors/node/latest
前端·npm·node.js
qq_332394202 小时前
pnpm的坑
前端·vue·pnpm
雾岛听风来2 小时前
前端开发 如何高效落地 Design Token
前端
不如吃茶去2 小时前
一文搞懂React Hooks闭包问题
前端·javascript·react.js
alwn2 小时前
新知识get,vue3是如何实现在style中使用响应式变量?
前端
来之梦2 小时前
uniapp中 uni.previewImage用法
前端·javascript·uni-app
野猪佩奇0072 小时前
uni-app使用ucharts地图,自定义Tooltip鼠标悬浮显示内容并且根据@getIndex点击事件获取点击的地区下标和地区名
前端·javascript·vue.js·uni-app·echarts·ucharts
生活、追梦者2 小时前
html+css+JavaScript 实现两个输入框的反转动画
javascript·css·html