GraphQL 是一种用于构建 API 的查询语言,它可以通过单个请求获取多个资源,并且可以根据客户端的需求灵活地返回数据。在 GraphQL 应用中,Subscriptions 是一种强大的实时数据推送机制,可以让客户端实时获取数据更新,而不必轮询服务器。
在本文中,我们将介绍如何在 GraphQL 应用中使用 Subscriptions,包括如何定义和使用 Subscriptions,以及如何在客户端和服务器端实现实时数据推送。
Subscriptions 的定义和使用
Subscriptions 是一种 GraphQL 查询类型,它允许客户端订阅服务器端的实时数据更新。与查询和变异不同,Subscriptions 是一种持久连接,可以在客户端和服务器端之间保持打开状态,以便在数据更新时立即推送数据。
定义 Subscriptions 的语法与定义查询和变异的语法类似,例如:
subscription { newPost { id title content } }
这个 Subscriptions 查询将订阅服务器端的 newPost
事件,并在每次新的帖子发布时返回帖子的 id
、title
和 content
。
在客户端中,可以使用 subscribe
函数来订阅 Subscriptions,例如:
// javascriptcn.com 代码示例 const subscription = gql` subscription { newPost { id title content } } `; const observer = client.subscribe({ query: subscription }); observer.subscribe({ next(data) { console.log(data); }, error(error) { console.error(error); } });
在这个示例中,我们使用 gql
函数定义了 Subscriptions 查询,并使用 client.subscribe
函数订阅了这个查询。然后,我们使用 observer.subscribe
函数来监听数据更新,并在每次更新时打印数据到控制台。
实现实时数据推送
在 GraphQL 应用中,实现实时数据推送需要在服务器端和客户端之间建立 WebSocket 连接,并在数据更新时使用 WebSocket 推送数据。
在服务器端,可以使用 GraphQL Subscriptions 库来实现 Subscriptions 功能。例如,以下是一个使用 GraphQL Subscriptions 实现实时数据推送的示例:
// javascriptcn.com 代码示例 const { ApolloServer, PubSub } = require('apollo-server'); const { GraphQLScalarType } = require('graphql'); const { Kind } = require('graphql/language'); const pubsub = new PubSub(); const NEW_POST = 'NEW_POST'; const typeDefs = ` scalar Date type Post { id: ID! title: String! content: String! createdAt: Date! } type Query { allPosts: [Post!]! } type Mutation { createPost(title: String!, content: String!): Post! } type Subscription { newPost: Post! } `; const resolvers = { Date: new GraphQLScalarType({ name: 'Date', description: 'Date custom scalar type', parseValue(value) { return new Date(value); }, serialize(value) { return value.getTime(); }, parseLiteral(ast) { if (ast.kind === Kind.INT) { return parseInt(ast.value, 10); } return null; } }), Query: { allPosts() { // Return all posts } }, Mutation: { createPost(_, { title, content }) { const post = { id: '1', title, content, createdAt: new Date() }; pubsub.publish(NEW_POST, { newPost: post }); return post; } }, Subscription: { newPost: { subscribe: () => pubsub.asyncIterator([NEW_POST]) } } }; const server = new ApolloServer({ typeDefs, resolvers, subscriptions: { path: '/subscriptions' } }); server.listen().then(({ url, subscriptionsUrl }) => { console.log(`Server ready at ${url}`); console.log(`Subscriptions ready at ${subscriptionsUrl}`); });
在这个示例中,我们使用 PubSub
类来创建一个实例,然后定义了一个 NEW_POST
常量来表示新帖子事件。然后,我们定义了一个 Subscription
类型的 Subscriptions,它将订阅 newPost
事件,并在每次新的帖子发布时返回帖子对象。在 Mutation
类型的 createPost
操作中,我们在发布新帖子时使用 pubsub.publish
函数将数据推送到客户端。
在客户端中,我们需要使用 WebSocket 来建立连接,并在数据更新时使用 WebSocket 推送数据。以下是一个使用 Apollo Client 和 WebSocket 实现实时数据推送的示例:
// javascriptcn.com 代码示例 import { ApolloClient, InMemoryCache, gql, split } from '@apollo/client'; import { WebSocketLink } from '@apollo/client/link/ws'; import { getMainDefinition } from '@apollo/client/utilities'; const wsLink = new WebSocketLink({ uri: 'ws://localhost:4000/subscriptions', options: { reconnect: true } }); const httpLink = createHttpLink({ uri: 'http://localhost:4000/graphql' }); const splitLink = split( ({ query }) => { const definition = getMainDefinition(query); return definition.kind === 'OperationDefinition' && definition.operation === 'subscription'; }, wsLink, httpLink ); const client = new ApolloClient({ link: splitLink, cache: new InMemoryCache() }); const subscription = gql` subscription { newPost { id title content } } `; const observer = client.subscribe({ query: subscription }); observer.subscribe({ next(data) { console.log(data); }, error(error) { console.error(error); } });
在这个示例中,我们使用 WebSocketLink
类创建一个 WebSocket 连接,然后使用 split
函数将 HTTP 和 WebSocket 连接分离。在订阅 Subscriptions 时,我们使用 client.subscribe
函数订阅 Subscriptions 查询,并在每次更新时打印数据到控制台。
总结
在本文中,我们介绍了如何在 GraphQL 应用中使用 Subscriptions,包括如何定义和使用 Subscriptions,以及如何在客户端和服务器端实现实时数据推送。通过使用 Subscriptions,我们可以让客户端实时获取数据更新,提高应用的实时性和用户体验。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65754bbcd2f5e1655de74526