代码之家  ›  专栏  ›  技术社区  ›  VikR

阿波罗2号。x: 订阅解析程序未启动?

  •  0
  • VikR  · 技术社区  · 7 年前

    上有许多帖子,因此可以在上搜索 Apollo Subscription Resolver Never Activates? ,包括我的 June 2017 .从那以后,我的订阅工作一直很好,好几个月了。但那是阿波罗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"));
    });
    

    类型

    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... 在中,变异解析程序运行,但订阅解析程序从未激活。

    我错过了什么?

    使现代化

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

    1 回复  |  直到 7 年前
        1
  •  1
  •   VikR    7 年前

    我让它工作了。下面是调用订阅解析器并处理其响应的代码。

    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);