Apollo 2.x:订阅解析器未触发?
Posted
技术标签:
【中文标题】Apollo 2.x:订阅解析器未触发?【英文标题】:Apollo 2.x: Subscription Resolver not Firing? 【发布时间】:2018-09-30 10:05:36 【问题描述】:在 SO 上有很多帖子都可以搜索 Apollo Subscription Resolver Never Activates?
,其中包括来自 June 2017 的我。从那时起,我的订阅服务运行良好,持续了好几个月。但那是 Apollo 1.x,现在有了 Apollo 2.x,我也遇到了类似的异常情况。
旧的 SO 帖子似乎无法解决此异常情况。在过去的几天里,我一直在浏览它们,并试图确保我正在做文档和文章所说的所有事情,但它还没有完全奏效。
为了完整起见,我提供了所有相关代码。
服务器设置
import createApolloServer from "meteor/apollo";
import makeExecutableSchema from "graphql-tools";
import merge from "lodash/merge";
import cors from 'cors';
import GoalsSchema from "../../api/goals/Goal.graphql";
import GoalsResolvers from "../../api/goals/resolvers";
import ResolutionsSchema from "../../api/resolutions/Resolutions.graphql";
import ResolutionsResolvers from "../../api/resolutions/resolvers";
import UsersSchema from "../../api/users/User.graphql";
import UsersResolvers from "../../api/users/resolvers";
import createServer from 'http';
import SubscriptionServer from 'subscriptions-transport-ws';
import execute, subscribe from 'graphql';
const typeDefs = [GoalsSchema, ResolutionsSchema, UsersSchema];
//must change this line to get changes in .graphql files recognized. afdkk
const resolvers = merge(GoalsResolvers, ResolutionsResolvers, UsersResolvers);
const schema = makeExecutableSchema(
typeDefs,
resolvers
);
createApolloServer( schema );
const WS_PORT = 3200;
// Create WebSocket listener server
// https://www.apollographql.com/docs/graphql-subscriptions/express.html
const websocketServer = createServer((request, response) =>
response.writeHead(404);
response.end();
);
// Bind it to port and start listening
websocketServer.listen(WS_PORT, () => console.log(
`Websocket Server is now running on ws://localhost:$WS_PORT`
));
const subscriptionServer = SubscriptionServer.create(
schema,
execute,
subscribe,
,
server: websocketServer,
path: '/subscriptions',
,
);
客户端设置
import React from "react";
import Meteor from "meteor/meteor";
import render from "react-dom";
import ApolloProvider from "react-apollo";
import ApolloLink, from from "apollo-link";
import ApolloClient from "apollo-client";
import HttpLink from "apollo-link-http";
import InMemoryCache from "apollo-cache-inmemory";
import onError from 'apollo-link-error';
import split from 'apollo-link';
import WebSocketLink from 'apollo-link-ws';
import getMainDefinition from 'apollo-utilities';
import toIdValue from 'apollo-utilities';
import App from "../../ui/App";
// Create an http link:
const httpLink = new HttpLink(
uri: Meteor.absoluteUrl("graphql"),
credentials: 'same-origin'
)
// Create a WebSocket link:
const wsLink = new WebSocketLink(
uri: `ws://localhost:3200/subscriptions`,
options:
reconnect: true
);
// using the ability to split links, you can send data to each link
// depending on what kind of operation is being sent
const splitLink = split(
// split based on operation type
(query) =>
const kind, operation = getMainDefinition(query);
return kind === 'OperationDefinition' && operation === 'subscription';
,
wsLink,
httpLink,
);
const authLink = new ApolloLink((operation, forward) =>
const token = Accounts._storedLoginToken();
operation.setContext(() => (
headers:
"meteor-login-token": token
));
return forward(operation);
);
const client = new ApolloClient(
link: ApolloLink.from([
onError((graphQLErrors, networkError) =>
if (graphQLErrors)
graphQLErrors.map((message, locations, path) =>
console.log(
`[GraphQL error]: Message: $message, Location: $locations, Path: $path`,
),
);
if (networkError) console.log(`[Network error]: $networkError`);
),
authLink,
splitLink,
]),
cache: new InMemoryCache()
);
const ApolloApp = () => (
<ApolloProvider client=client>
<App/>
</ApolloProvider>
);
Meteor.startup(() =>
render(<ApolloApp/>, document.getElementById("app"));
);
类型
type Resolution
_id: String!
name: String!
goals: [Goal]
completed: Boolean
type Query
resolutions: [Resolution]
getResolutionViaId(resolutionId: String!): Resolution
type Mutation
createResolution(name: String!): Resolution
type Subscription
resolutionWasAdded(userId: String!): Resolution
查询
let CREATE_RESOLUTION = gql`
mutation createResolution($name: String!)
createResolution(name: $name)
__typename
_id
name
...resolutionGoals
completed
$resolutionQueryFragments.resolutionGoals
`;
const RESOLUTION_SUBSCRIBE = gql`
subscription resolutionWasAdded($userId: String!)
resolutionWasAdded(userId: $userId)
__typename
_id
name
...resolutionGoals
completed
$resolutionQueryFragments.resolutionGoals
`;
解析器
Mutation:
createResolution(obj, args, userId)
let name = args.name;
if (userId)
return Promise.resolve()
.then(() =>
const resolutionId = Resolutions.insert(
name,
userId
);
return resolutionId;
)
.then(resolutionId =>
const resAdded = Resolutions.findOne(resolutionId);
return resAdded;
)
.then(resolutionWasAdded =>
pubsub.publish('resolutionWasAdded', resolutionWasAdded: args)
return resolutionWasAdded;
)
.catch((err) =>
console.log(err);
);
throw new Error("Unauthorized");
,
Subscription:
resolutionWasAdded:
subscribe: withFilter(
() => pubsub.asyncIterator("resolutionWasAdded"),
(payload, variables) =>
debugger;
return true;
)
Mutation 解析器中的pubsub.publish...
行运行,但订阅解析器从未激活。
我错过了什么?
更新
我必须修改在我的客户端查询组件中设置订阅的方式。当我发现更多时,我会更新这篇文章。
【问题讨论】:
【参考方案1】:我得到了这个工作。这是调用订阅解析器并处理来自它的响应的代码。
import React, Component from "react";
import gql from "graphql-tag";
import graphql from "react-apollo";
import Mutation from "react-apollo";
import withApollo from "react-apollo";
import GET_RESOLUTIONS_FOR_MUTATION_COMPONENT, CREATE_RESOLUTION from '../../imports/api/resolutions/queries';
import isDuplicateObject from "../api/resolutions/queries";
const ResolutionForm = () =>
let input;
let state =
error: null
;
return (
<Mutation
mutation=CREATE_RESOLUTION
update=(cache, data: createResolution) =>
const resolutions = cache.readQuery(query: GET_RESOLUTIONS_FOR_MUTATION_COMPONENT);
if (!isDuplicateObject(createResolution, resolutions))
cache.writeQuery(
query: GET_RESOLUTIONS_FOR_MUTATION_COMPONENT,
data: resolutions: resolutions.concat([createResolution])
);
>
(createResolution, data) => (
<div>
<form
onSubmit=e =>
e.preventDefault();
createResolution(
variables:
name: input.value
,
optimisticResponse:
__typename: "Mutation",
createResolution:
__typename: "Resolution",
completed: false,
goals: [],
_id: "012345",
name: input.value
);
input.value = "";
>
<input
ref=node =>
input = node;
placeholder="Enter a Resolution"
/>
<button type="submit">Submit</button>
</form>
</div>
)
</Mutation>
);
;
export default withApollo(ResolutionForm);
【讨论】:
以上是关于Apollo 2.x:订阅解析器未触发?的主要内容,如果未能解决你的问题,请参考以下文章