如何使用Apollo GraphQL进行订阅?

时间:2017-06-09 17:55:04

标签: websocket publish-subscribe graphql apollo react-apollo

我将发布大量代码用于上下文。我还没有看过显示客户端和服务器的教程,所以我试图把它们拼凑起来。

代码

客户端

网络接口

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”立即被点击,虽然我不知道为什么。目前还没有“公布”任何内容。 subscriptionData出现为:

{
  data: {
    branchUpdated: null
  }
}

在服务器上,我可以看到原因。在我的resolverMap中,Subscription.branchUpdated.resolve会立即被点击。 payload可能是undefined,可能是因为我尚未发布任何内容Subscription.branchUpdated.subscribe永远不会被执行。

当我向我的“分支”发布更新时,没有任何反应。即使我已调用branchUpdated,也无法调用subscribepubSub.publish。没有任何东西返回给客户。

所以我的问题是:

  1. 在我实际发布内容之前,如何订阅而不是
  2. 更重要的是,当我 发布内容时,如何让他们 点火?

1 个答案:

答案 0 :(得分:0)

终于明白了。有一些问题。

  1. graphql@0.9.6没有{subscribe},您至少需要v0.10
  2. 这是我的实施特有的问题,但我的withFilter错了。 branch.id是一个缓冲区 - 我需要使用.equals来比较它们
  3. 我更新了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};
            }
        });
    }