Graphql 阿波罗2.x:订阅解析程序没有启动?

Graphql 阿波罗2.x:订阅解析程序没有启动?,graphql,apollo,apollo-client,apollo-server,graphql-subscriptions,Graphql,Apollo,Apollo Client,Apollo Server,Graphql Subscriptions,网站上有很多帖子,所以搜索到的阿波罗订阅解析器永远不会激活?,包括我的一篇。从那以后,我的订阅工作一直很好,好几个月了。但那是阿波罗1.x,现在是阿波罗2.x,我有一个类似的异常 旧的SO帖子似乎无法解决这个异常。在过去的几天里,我一直在浏览这些文档,并试图确保我做到了文档和文章所说的一切,但它还没有完全起作用 为了完整性,我提供了所有相关的代码 服务器设置 import { createApolloServer } from "meteor/apollo"; import { makeExec

网站上有很多帖子,所以搜索到的阿波罗订阅解析器永远不会激活?,包括我的一篇。从那以后,我的订阅工作一直很好,好几个月了。但那是阿波罗1.x,现在是阿波罗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"));
});
客户端设置

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;
                })
        }
    }
}
变异解析程序中的行
pubsub.publish…
运行,但订阅解析程序从未激活

我错过了什么

更新


我必须修改如何在客户端查询组件中设置订阅。当我发现更多信息后,我会更新这篇文章。

我已经做好了准备。下面是调用订阅解析器并处理其响应的代码

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);
import React,{Component}来自“React”;
从“graphql标签”导入gql;
从“react apollo”导入{graphql};
从“反应阿波罗”中导入{突变};
从“react apollo”导入{withApollo};
从“../../imports/api/RESOLUTIONS/querys”导入{GET_RESOLUTIONS}对于_组件,创建_RESOLUTION};
从“./api/resolutions/querys”导入{isDuplicateObject}”;
常量解析形式=()=>{
让输入;
让状态={
错误:null
};
返回(
{
const{resolutions}=cache.readQuery({query:GET\u resolutions\u FOR\u MUTATION\u COMPONENT});
如果(!isDuplicateObject(createResolution,resolutions)){
cache.writeQuery({
查询:获取\u组件的\u分辨率\u,
数据:{resolutions:resolutions.concat([createResolution])}
});
}
}}
>
{(createResolution,{data})=>(
{
e、 预防默认值();
创建分辨率({
变量:{
名称:input.value
},
乐观回应:{
__typename:“突变”,
创建分辨率:{
__类型名称:“决议”,
已完成:错误,
目标:[],
_id:“012345”,
名称:input.value
}
}
});
input.value=“”;
}}
>
{
输入=节点;
}}
占位符=“输入分辨率”
/>
提交
)}
);
};
使用阿波罗导出默认值(决议表);