我想知道 graphql 订阅的工作示例

I would like to know a working exsample of graphql subscriptions

最近他们弃用了 subscriptionManager。我想知道如何设置解析器,定义订阅和执行功能。

您需要升级到 Apollo 2.0。由于官方文档尚未更新,我最近做了一个关于如何使用 Apollo 2.0 的 write-up

简而言之,您现在必须在客户端上使用 apollo-linkgraphql 包中的 executesubscribe 现在直接传递给 SubscriptionServer 相反。

您首先需要具有正确版本的正确软件包:

npm install --save apollo-client@beta apollo-cache-inmemory@beta apollo-link@0.7.0 apollo-link-http@0.7.0 apollo-link-ws@0.5.0 graphql-subscriptions subscriptions-transport-ws apollo-server-express express graphql graphql-tools body-parser

如果您是 运行 Meteor,您可能还需要:

meteor add apollo swydo:blaze-apollo swydo:graphql webapp

下面的代码是在Meteor中编写的,但它可以很容易地适应其他服务器类型,比如Express。您还可以下载 working example app.

在客户端上:

import { ApolloClient } from 'apollo-client';
import { ApolloLink } from 'apollo-link';
import { HttpLink } from 'apollo-link-http';
import WebSocketLink from 'apollo-link-ws';
import Cache from 'apollo-cache-inmemory';
import { getOperationAST } from 'graphql';

const httpUri = 'http://localhost:3000/graphql';
const wsUri = 'ws://localhost:3000/subscriptions';

const link = ApolloLink.split(
  operation => {
    const operationAST = getOperationAST(operation.query, operation.operationName);
    return !!operationAST && operationAST.operation === 'subscription';
  },
  new WebSocketLink({
    uri: wsUri,
    options: {
      reconnect: true, //auto-reconnect
      // // carry login state (should use secure websockets (wss) when using this)
      // connectionParams: {
      //   authToken: localStorage.getItem("Meteor.loginToken")
      // }
    }
  }),
  new HttpLink({ uri: httpUri })
);

const cache = new Cache(window.__APOLLO_STATE);

const client = new ApolloClient({
  link,
  cache
});

在服务器上:

import { WebApp } from 'meteor/webapp'; // Meteor-specific
import { execute, subscribe } from 'graphql';
import { SubscriptionServer } from 'subscriptions-transport-ws';
import { createApolloServer, addCurrentUserToContext } from 'meteor/apollo'; // specific to Meteor, but you can always check out the Express implementation
import { makeExecutableSchema } from 'graphql-tools';
import resolvers from './resolvers'; // your custom resolvers
import typeDefs from './schema.graphql'; // your custom schema

// make schema executable
const schema = makeExecutableSchema({
  typeDefs,
  resolvers
});

// any additional context you use for your resolvers, if any
const context = {};

// start a graphql server with Express handling a possible Meteor current user
// if you're not using Meteor, check out https://github.com/apollographql/apollo-server for instructions on how to create a server in pure Node
createApolloServer({ 
  schema,
  context
}, {
  // // enable access to GraphQL API cross-domain (requires NPM "cors" package)
  // configServer: expressServer => expressServer.use(cors())
});

// create subscription server
// non-Meteor implementation here: https://github.com/apollographql/subscriptions-transport-ws
new SubscriptionServer({
  schema,
  execute,
  subscribe,
  // // on connect subscription lifecycle event
  // onConnect: async (connectionParams, webSocket) => {
  //   // if a meteor login token is passed to the connection params from the client, 
  //   // add the current user to the subscription context
  //   const subscriptionContext = connectionParams.authToken
  //     ? await addCurrentUserToContext(context, connectionParams.authToken)
  //     : context;
  //   return subscriptionContext;
  // }
}, {
  server: WebApp.httpServer,
  path: '/subscriptions'
});

resolvers.js

import { withFilter } from 'graphql-subscriptions'; // will narrow down the changes subscriptions listen to
import { PubSub } from 'graphql-subscriptions';
import { People } from '../imports/api/collections'; // Meteor-specific for doing database queries

const pubsub = new PubSub();

const resolvers = {

  Query: {
    person(obj, args, context) {
      const person = People.findOne(args.id);
      if (person) {
        // Mongo stores id as _id, but our GraphQL API calls for id, so make it conform to the API
        person.id = person._id;
        delete person._id;
      }
      return person;
    }
  },

  Mutation: {
    updatePerson(obj, args, context) {
      // You'll probably want to validate the args first in production, and possibly check user credentials using context
      People.update({ _id: args.id }, { $set: { name: args.name, eyeColor: args.eyeColor, occupation: args.occupation } });
      pubsub.publish("personUpdated", { personUpdated: args }); // trigger a change to all subscriptions to this person
      // Note: You must publish the object with the subscription name nested in the object!
      // See: https://github.com/apollographql/graphql-subscriptions/issues/51
      return args;
    }
  },

  Subscription: {
    personUpdated: {
      // See: https://github.com/apollographql/graphql-subscriptions#channels-mapping
      // Take a look at "Channels Mapping" for handling multiple create, update, delete events
      // Also, check out "PubSub Implementations" for using Redis instead of PubSub
      // PubSub is not recommended for production because it won't work if you have multiple servers
      // withFilter makes it so you can only listen to changes to this person instead of all people
      subscribe: withFilter(() => pubsub.asyncIterator('personUpdated'), (payload, args) => {
        return (payload.personUpdated.id===args.id);
      })
    }
  }

};

export default resolvers;

schema.graphql

enum EyeColor {
  brown
  blue
  green
  hazel
}

type Person {
  id: ID
  name: String
  eyeColor: EyeColor
  occupation: String
}

type Query {
  person(id: ID!): Person
}

type Mutation {
  updatePerson(id: ID!, name: String!, eyeColor: EyeColor!, occupation: String!): Person
}

type Subscription {
    personUpdated(id: ID!): Person
}

schema {
    query: Query
    mutation: Mutation
    subscription: Subscription
}

可以在这个媒体中找到关于此的完整文章 post:How to get Apollo 2.0 working with GraphQL + subscriptions

可在此处找到演示如何将 Apollo 2.0 与 GraphQL 服务器 + 订阅一起使用的示例应用程序:meteor-apollo2