# Souscriptions

# Installation

Pour l'implĂ©mentation serveur, vous ppuvez jeter un Ɠil Ă  cet exemple simple (opens new window).

Pour activer la souscription par websockets, vous devez configurer un peu plus de choses :

npm install --save apollo-link-ws apollo-utilities
import Vue from 'vue'
import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
// Nouveaux imports
import { split } from 'apollo-link'
import { WebSocketLink } from 'apollo-link-ws'
import { getMainDefinition } from 'apollo-utilities'

import VueApollo from 'vue-apollo'

const httpLink = new HttpLink({
  // Vous devez utiliser un URL absolu
  uri: 'http://localhost:3020/graphql',
})

// Création du lien de souscription websocket
const wsLink = new WebSocketLink({
  uri: 'ws://localhost:3000/subscriptions',
  options: {
    reconnect: true,
  },
})

// Grùce à la possibilité de scinder les liens, vous pouvez envoyer de la donnée
// à chaque lien, en fonction du type d'opération à envoyer
const link = split(
  // Scission en fonction du type d'opération
  ({ query }) => {
    const definition = getMainDefinition(query)
    return definition.kind === 'OperationDefinition' &&
      definition.operation === 'subscription'
  },
  wsLink,
  httpLink
)

// Création du client Apollo
const apolloClient = new ApolloClient({
  link,
  cache: new InMemoryCache(),
  connectToDevTools: true,
})

// Installation du plugin Vue comme précédemment
Vue.use(VueApollo)

# Souscriptions supplémentaires

Si vous souhaitez mettre Ă  jour une requĂȘte intelligente depuis une souscription, la meilleure façon est d'utiliser la mĂ©thode de requĂȘte intelligente subscribeToMore. Cela crĂ©e des souscriptions intelligentes liĂ©es Ă  votre requĂȘte intelligente. Ajoutez simplement subscribeToMore Ă  votre requĂȘte intelligente :

apollo: {
  tags: {
    query: TAGS_QUERY,
    subscribeToMore: {
      document: gql`subscription name($param: String!) {
        itemAdded(param: $param) {
          id
          label
        }
      }`,
      // Variables passées à la souscription
      // Comme nous utilisons une fonction, elles sont réactives
      variables () {
        return {
          param: this.param,
        }
      },
      // Mutation du résultat précédent
      updateQuery: (previousResult, { subscriptionData }) => {
        // On retourne le nouveau résultat depuis le précédent,
        // avec la nouvelle donnée
      },
    }
  }
}

TIP

Notez qu'il est possible de passer un tableau de souscriptions Ă  subscribeToMore pour souscrire Ă  plusieurs souscriptions dans une requĂȘte.

# Utilisation alternative

Vous pouvez accĂ©der aux requĂȘtes que vous avez dĂ©finies dans l'option apollo avec this.$apollo.queries.<name>, ce qui ressemblerait Ă  ceci :

this.$apollo.queries.tags.subscribeToMore({
  // Document GraphQL
  document: gql`subscription name($param: String!) {
    itemAdded(param: $param) {
      id
      label
    }
  }`,
  // Variables passées à la souscription
  variables: {
    param: '42',
  },
  // Mutation du résultat précédent
  updateQuery: (previousResult, { subscriptionData }) => {
    // On retourne le nouveau résultat depuis le précédent
    // avec la nouvelle donnée
  },
})

Si la requĂȘte concernĂ©e est arrĂȘtĂ©e, la souscription est automatiquement dĂ©truite.

Voici un exemple :

// Souscription au document GraphQL
const TAG_ADDED = gql`subscription tags($type: String!) {
  tagAdded(type: $type) {
    id
    label
    type
  }
}`

// Libellés SubscribeToMore
// Nous avons plusieurs types de libellés
// avec une souscription 'channl' pour chaque
this.$watch(() => this.type, (type, oldType) => {
  if (type !== oldType || !this.tagsSub) {
    // Nous devons nous désinscrire avant de souscrire à nouveau
    if (this.tagsSub) {
      this.tagsSub.unsubscribe()
    }
    // Souscription dans la requĂȘte
    this.tagsSub = this.$apollo.queries.tags.subscribeToMore({
      document: TAG_ADDED,
      variables: {
        type,
      },
      // Mutation du résultat précédent
      updateQuery: (previousResult, { subscriptionData }) => {
        // Si nous avons déjà ajouté le libellé, on ne fait rien
        // Cela peut ĂȘtre causĂ© par `updateQuery` dans notre mutation addTag
        if (previousResult.tags.find(tag => tag.id === subscriptionData.data.tagAdded.id)) {
          return previousResult
        }

        return {
          tags: [
            ...previousResult.tags,
            // Ajout du nouveau libellé
            subscriptionData.data.tagAdded,
          ],
        }
      },
    })
  }
}, {
  immediate: true,
})

# Abstraction simple

WARNING

Si vous souhaitez mettre Ă  jour une requĂȘte avec le rĂ©sultat d'une souscription, utilisez subscribeToMore. Les mĂ©thodes ci-dessous s'appliquent dans le cas d'une notification.

Vous pouvez déclarer des souscriptions intelligentes dans l'option apollo avec le mot-clé $subscribe :

apollo: {
  // Souscriptions
  $subscribe: {
    // Lorsqu'un libellé est ajouté
    tagAdded: {
      query: gql`subscription tags($type: String!) {
        tagAdded(type: $type) {
          id
          label
          type
        }
      }`,
      // Variables réactives
      variables () {
        // Le fonctionnement est le mĂȘme que pour des requĂȘtes classiques
        // et souscrit Ă  nouveau avec les bonnes variables
        // chaque fois qu'un valeur change
        return {
          type: this.type,
        }
      },
      // Hook de résultat
      // N'oubliez pas de décomposer `data`
      result ({ data }) {
        console.log(data.tagAdded)
      },
    },
  },
},

Vous pouvez accéder à la souscription avec this.$apollo.subscriptions.<name>.

TIP

Comme pour les requĂȘtes, vous pouvez dĂ©clarer la souscription avec une fonction, et vous pouvez dĂ©clarer l'option query avec une fonction rĂ©active.

Lorsqu'un serveur supporte les requĂȘtes en temps rĂ©el et utilise les souscriptions pour les mettre Ă  jour, comme Hasura (opens new window), vous pouvez utiliser de simples souscriptions pour les requĂȘtes rĂ©actives :

data () {
  return {
    tags: [],
  };
},
apollo: {
  $subscribe: {
    tags: {
      query: gql`subscription {
        tags {
          id
          label
          type
        }
      }`,
      result ({ data }) {
        this.tags = data.tags;
      },
    },
  },
},

# Sauter la souscription

Si la souscription est sautée, elle est désactivée et ne sera plus mise à jour. Vous pouvez utiliser l'options skip :

// Options spécifiques à Apollo
apollo: {
  // Souscriptions
  $subscribe: {
    // Lorsqu'un libellé est ajouté
    tags: {
      query: gql`subscription tags($type: String!) {
        tagAdded(type: $type) {
          id
          label
          type
        }
      }`,
      // Variables réactives
      variables () {
        return {
          type: this.type,
        }
      },
      // Hook de résultat
      result (data) {
        // Mise Ă  jour de l'Ă©tat local
        this.tags.push(data.tagAdded)
      },
      // On saute la souscription
      // Skip the subscription
      skip () {
        return this.skipSubscription
      }
    },
  },
},

Ici, skip est appelé automatiquement dÚs que la propriété skipSubscription du composant change.

Vous pouvez aussi accéder à la souscription directemnt et assigner la propriété skip :

this.$apollo.subscriptions.tags.skip = true

# Ajouter des souscription intelligentes manuellement

Vous pouvez ajouter manellement une souscription intelligente avec la méthode $apollo.addSmartSubscription(key, options) :

created () {
  this.$apollo.addSmartSubscription('tagAdded', {
    // MĂȘmes options que pour '$subscribe' ci-dessus
  })
}

TIP

En interne, cette méthode est appelée pour chaque entrée de l'objet $subscribe dans l'option apollo du composant.

# Souscription Apollo standard

Utilisez la méthode $apollo.subscribe() pour souscrire à une souscription GraphQL qui sera automatiquement détruite lors que le composant le sera également. Cela ne crée pas de souscription intelligente.

mounted () {
  const subQuery = gql`subscription tags($type: String!) {
    tagAdded(type: $type) {
      id
      label
      type
    }
  }`

  const observer = this.$apollo.subscribe({
    query: subQuery,
    variables: {
      type: 'City',
    },
  })

  observer.subscribe({
    next (data) {
      console.log(data)
    },
    error (error) {
      console.error(error)
    },
  })
},
DerniĂšre mise Ă  jour: 11/02/2021 Ă  11:08:30