Я пытаюсь настроить подписки с Apollo 2 и NEXT.js.Я могу заставить клиента подключиться к серверу, и он работает на площадке GraphQL, поэтому неправильная конфигурация должна быть в файле withData или компоненте, который обрабатывает подписку.
При проверке соединения сокета на сетевой панели в Chrome полезная нагрузка подписки не добавляется в виде фрейма, как это происходит на игровой площадке GraphQL.
withData:
import { ApolloLink, Observable } from 'apollo-link';
import { GRAPHQL_ENDPOINT, WS_PATH } from '../config/env';
import { ApolloClient } from 'apollo-client';
import { BatchHttpLink } from 'apollo-link-batch-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { SubscriptionClient } from 'subscriptions-transport-ws';
import { WebSocketLink } from 'apollo-link-ws';
import { createPersistedQueryLink } from 'apollo-link-persisted-queries';
import { onError } from 'apollo-link-error';
import withApollo from 'next-with-apollo';
import { withClientState } from 'apollo-link-state';
function createClient({ headers }) {
const cache = new InMemoryCache();
const request = async (operation) => {
operation.setContext({
http: {
includeExtensions: true,
includeQuery: false
},
headers
});
};
const requestLink = new ApolloLink(
(operation, forward) => new Observable((observer) => {
let handle;
Promise.resolve(operation)
.then(oper => request(oper))
.then(() => {
handle = forward(operation).subscribe({
next: observer.next.bind(observer),
error: observer.error.bind(observer),
complete: observer.complete.bind(observer)
});
})
.catch(observer.error.bind(observer));
return () => {
if (handle) handle.unsubscribe();
};
})
);
return new ApolloClient({
link: ApolloLink.from([
onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
console.log({ graphQLErrors });
}
if (networkError) {
console.log('Logout user');
}
}),
requestLink,
// link,
withClientState({
defaults: {
isConnected: true
},
resolvers: {
Mutation: {
updateNetworkStatus: (_, { isConnected }, { cache }) => {
cache.writeData({ data: { isConnected } });
return null;
}
}
},
cache
}),
createPersistedQueryLink().concat(
new BatchHttpLink({
uri: GRAPHQL_ENDPOINT,
credentials: 'include'
}),
process.browser
? new WebSocketLink({
uri: WS_PATH,
options: {
reconnect: true
}
})
: null
)
]),
cache
});
}
export default withApollo(createClient);
Компонент подписки:
import { CONVERSATION_QUERY } from '../../constants/queries';
import { CONVERSATION_SUBSCRIPTION } from '../../constants/subscriptions';
import PropTypes from 'prop-types';
import { Query } from 'react-apollo';
const Conversation = props => (
<Query
{...props}
query={CONVERSATION_QUERY}
variables={{ input: { _id: props._id } }}
>
{(payload) => {
const more = () => payload.subscribeToMore({
document: CONVERSATION_SUBSCRIPTION,
variables: { input: { conversation: props._id } },
updateQuery: (prev, { subscriptionData }) => {
console.log({ subscriptionData });
if (!subscriptionData.data.messageSent) return prev;
const data = subscriptionData;
console.log({ data });
return Object.assign({}, prev, {});
},
onError(error) {
console.log(error);
},
onSubscriptionData: (data) => {
console.log('onSubscriptionData ', data);
}
});
return props.children({ ...payload, more });
}}
</Query>
);
Conversation.propTypes = {
children: PropTypes.func.isRequired
};
export default Conversation;
Подписка, протестированная на площадке GraphQL:
import gql from 'graphql-tag';
export const CONVERSATION_SUBSCRIPTION = gql`
subscription messageSent($input: messageSentInput) {
messageSent(input: $input) {
_id
users {
_id
profile {
firstName
lastName
jobTitle
company
picture
}
}
messages {
_id
body
createdAt
read
sender {
_id
profile {
firstName
lastName
jobTitle
company
picture
}
}
}
}
}
`;
Затем в componentDidMount выполняется дополнительная функция:
componentDidMount() {
this.props.subscribeToMore();
}
Результат в консоли из журнала в updateQuery:
{"data":{"messageSent":null}}