如何使用 Apollo GraphQL 获取订阅?
How to get subscriptions working with Apollo GraphQL?
我要 post 编写大量上下文代码。我还没有看到同时显示客户端和服务器的教程,所以我正在尝试将它们拼凑在一起。
代码
客户
网络接口
const subscriptionClient = new SubscriptionClient(`ws://localhost:8031/`, {
reconnect: true
});
const networkInterface = createNetworkInterface({
uri: 'http://localhost:8030/graphql'
});
const subscriptionInterface = addGraphQLSubscriptions(networkInterface, subscriptionClient);
const apolloClient = new ApolloClient({
networkInterface: subscriptionInterface
});
组件
const SUBSCRIPTION_QUERY = gql`
subscription onBranchUpdated($id: UUID!) {
branchUpdated(id: $id) {
browser
crawlId
startDate
endDate
baseUrl
totalPages
currentPage
}
}
`;
class BranchPage extends React.PureComponent {
render() {
*snip*
}
componentDidMount() {
this.props.data.subscribeToMore({
document: SUBSCRIPTION_QUERY,
variables: {
id: this.props.match.params.id,
},
updateQuery: (prevResult, {subscriptionData}) => {
log('updateQuery',prevResult,subscriptionData);
}
});
}
}
export default graphql(gql`
query getBranch($id: UUID!) {
branch(id: $id) {
id
browser
crawlId
startDate
endDate
baseUrl
totalPages
currentPage
}
}
`, {
options: ({match: {params}}) => ({
variables: {
id: params.id,
}
})
})(BranchPage);
服务器
graphql.schema.graphqls
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
type Branch {
id: UUID!
*snip*
}
type Subscription {
branchUpdated(id: UUID!): Branch
}
解析器
const resolverMap = {
Query: {
async branch(obj, {id}, context, info) {
*snip*
return branch;
},
},
Mutation: {
async updateBranch(_, req) {
let {id, ...updates} = req;
let branch = await db::queryOne("select * from Branches where id=?", [id]);
updates = getUpdates(req);
Object.assign(branch, updates);
await db::mutate("update Branches set ? where id=?", [updates, id]);
pubSub.publish(topics.BRANCH_UPDATED, {branchUpdated: branch});
return branch;
},
},
Subscription: {
branchUpdated: {
resolve: (payload, args, context, info) => {
log('RESSSSSSSSSSSSSSSSoLVE',payload,args);
return payload;
},
subscribe: withFilter(() => pubSub.asyncIterator(topics.BRANCH_UPDATED), (payload, variables) => {
log('FILTERRRRRRRRRRRRRRRRRRRRRRR');
return payload.branchUpdated.id === variables.id;
}),
},
},
};
发布订阅
import { PubSub } from 'graphql-subscriptions';
const pubSub = new PubSub();
export default pubSub;
WebSocket 服务器
const wsServer = createServer((request, response) => {
response.writeHead(404);
response.end();
});
wsServer.listen(WS_PORT, () => {
console.log(`Websocket server: http://localhost:${WS_PORT}`)
});
const subscriptionServer = SubscriptionServer.create(
{
schema,
execute,
subscribe,
},
{
server: wsServer,
path: '/',
}
);
问题
当我使用此组件加载页面时,它使用网络接口加载数据并正确呈现。之后,我希望组件通过 websocket 订阅更新以保持最新。这就是我遇到的问题。
在 Chrome 开发工具中,我可以看到 "updateQuery" 立即被击中,尽管我不确定为什么。此时什么都没有'published'。 subscriptionData
结果为:
{
data: {
branchUpdated: null
}
}
在服务器上,我可以看到原因。在我的resolverMap
中,Subscription.branchUpdated.resolve
立即被击中。 payload
是 undefined
,可能又是因为 我还没有发布任何东西。 Subscription.branchUpdated.subscribe
永远不会执行。
当我 发布我的 "branch" 更新时,没有任何反应。 branchUpdated
和 subscribe
都没有被调用,即使我调用了 pubSub.publish
。没有任何东西返回给客户。
所以我的问题是:
- 如何让我的订阅不触发,直到我真正发布了一些东西
- 更重要的是,当我实际 做 发布内容时,如何让它们 触发?
终于想通了。有一些问题。
graphql@0.9.6
没有 {subscribe}
,您至少需要 v0.10
- 这是我的实施特有的问题,但我的
withFilter
是错误的。 branch.id
是一个缓冲区——我需要使用 .equals
来比较它们
我更新了componentDidMount
:
componentDidMount() {
this.props.data.subscribeToMore({
document: SUBSCRIPTION_QUERY,
variables: {
id: this.props.match.params.id,
},
updateQuery: (prevResult, {subscriptionData}) => {
log('updateQuery',prevResult,subscriptionData.data.branchUpdated);
return {branch: subscriptionData.data.branchUpdated};
}
});
}
我要 post 编写大量上下文代码。我还没有看到同时显示客户端和服务器的教程,所以我正在尝试将它们拼凑在一起。
代码
客户
网络接口
const subscriptionClient = new SubscriptionClient(`ws://localhost:8031/`, {
reconnect: true
});
const networkInterface = createNetworkInterface({
uri: 'http://localhost:8030/graphql'
});
const subscriptionInterface = addGraphQLSubscriptions(networkInterface, subscriptionClient);
const apolloClient = new ApolloClient({
networkInterface: subscriptionInterface
});
组件
const SUBSCRIPTION_QUERY = gql`
subscription onBranchUpdated($id: UUID!) {
branchUpdated(id: $id) {
browser
crawlId
startDate
endDate
baseUrl
totalPages
currentPage
}
}
`;
class BranchPage extends React.PureComponent {
render() {
*snip*
}
componentDidMount() {
this.props.data.subscribeToMore({
document: SUBSCRIPTION_QUERY,
variables: {
id: this.props.match.params.id,
},
updateQuery: (prevResult, {subscriptionData}) => {
log('updateQuery',prevResult,subscriptionData);
}
});
}
}
export default graphql(gql`
query getBranch($id: UUID!) {
branch(id: $id) {
id
browser
crawlId
startDate
endDate
baseUrl
totalPages
currentPage
}
}
`, {
options: ({match: {params}}) => ({
variables: {
id: params.id,
}
})
})(BranchPage);
服务器
graphql.schema.graphqls
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
type Branch {
id: UUID!
*snip*
}
type Subscription {
branchUpdated(id: UUID!): Branch
}
解析器
const resolverMap = {
Query: {
async branch(obj, {id}, context, info) {
*snip*
return branch;
},
},
Mutation: {
async updateBranch(_, req) {
let {id, ...updates} = req;
let branch = await db::queryOne("select * from Branches where id=?", [id]);
updates = getUpdates(req);
Object.assign(branch, updates);
await db::mutate("update Branches set ? where id=?", [updates, id]);
pubSub.publish(topics.BRANCH_UPDATED, {branchUpdated: branch});
return branch;
},
},
Subscription: {
branchUpdated: {
resolve: (payload, args, context, info) => {
log('RESSSSSSSSSSSSSSSSoLVE',payload,args);
return payload;
},
subscribe: withFilter(() => pubSub.asyncIterator(topics.BRANCH_UPDATED), (payload, variables) => {
log('FILTERRRRRRRRRRRRRRRRRRRRRRR');
return payload.branchUpdated.id === variables.id;
}),
},
},
};
发布订阅
import { PubSub } from 'graphql-subscriptions';
const pubSub = new PubSub();
export default pubSub;
WebSocket 服务器
const wsServer = createServer((request, response) => {
response.writeHead(404);
response.end();
});
wsServer.listen(WS_PORT, () => {
console.log(`Websocket server: http://localhost:${WS_PORT}`)
});
const subscriptionServer = SubscriptionServer.create(
{
schema,
execute,
subscribe,
},
{
server: wsServer,
path: '/',
}
);
问题
当我使用此组件加载页面时,它使用网络接口加载数据并正确呈现。之后,我希望组件通过 websocket 订阅更新以保持最新。这就是我遇到的问题。
在 Chrome 开发工具中,我可以看到 "updateQuery" 立即被击中,尽管我不确定为什么。此时什么都没有'published'。 subscriptionData
结果为:
{
data: {
branchUpdated: null
}
}
在服务器上,我可以看到原因。在我的resolverMap
中,Subscription.branchUpdated.resolve
立即被击中。 payload
是 undefined
,可能又是因为 我还没有发布任何东西。 Subscription.branchUpdated.subscribe
永远不会执行。
当我 发布我的 "branch" 更新时,没有任何反应。 branchUpdated
和 subscribe
都没有被调用,即使我调用了 pubSub.publish
。没有任何东西返回给客户。
所以我的问题是:
- 如何让我的订阅不触发,直到我真正发布了一些东西
- 更重要的是,当我实际 做 发布内容时,如何让它们 触发?
终于想通了。有一些问题。
graphql@0.9.6
没有{subscribe}
,您至少需要 v0.10- 这是我的实施特有的问题,但我的
withFilter
是错误的。branch.id
是一个缓冲区——我需要使用.equals
来比较它们 我更新了
componentDidMount
:componentDidMount() { this.props.data.subscribeToMore({ document: SUBSCRIPTION_QUERY, variables: { id: this.props.match.params.id, }, updateQuery: (prevResult, {subscriptionData}) => { log('updateQuery',prevResult,subscriptionData.data.branchUpdated); return {branch: subscriptionData.data.branchUpdated}; } }); }