# ApolloQuery

Vous pouvez utiliser le composant ApolloQuery (ou apollo-query) pour avoir des requĂȘtes Apollo observĂ©es directement dans vos templates. AprĂšs avoir lu cette page, consultez la rĂ©fĂ©rence API pour connaĂźtre toutes les options disponibles.

# Le gabarit étiqueté gql

C'est la mĂ©thode recommandĂ©e pour utiliser le composant ApolloQuery. Il utilise la mĂȘme syntaxe avec le gabarit Ă©tiquetĂ© gql que dans les autres exemples :

<template>
  <ApolloQuery
    :query="gql => gql`
      query MyHelloQuery ($name: String!) {
        hello (name: $name)
      }
    `"
    :variables="{ name }"
  >
    <!-- TODO -->
  </ApolloQuery>
</template>

Nous passons une fonction Ă  la prop query qui prent le gabarit gql en argument, afin de pouvoir le document GraphQL directement.

L'exemple ci-dessus passe Ă©galement variables Ă  la requĂȘte en utilisant la prop du mĂȘme nom.

Dans le slot par dĂ©faut d'ApolloQuery, vous pouvez accĂ©der Ă  de la donnĂ©e concernant la requĂȘte observĂ©e, comme par exemple l'object result :

<template v-slot="{ result: { loading, error, data } }">
  <!-- Chargement -->
  <div v-if="loading" class="loading apollo">Chargement...</div>

  <!-- Erreur -->
  <div v-else-if="error" class="error apollo">Une erreur est survenue.</div>

  <!-- RĂ©sultat -->
  <div v-else-if="data" class="result apollo">{{ data.hello }}</div>

  <!-- Pas de résultat -->
  <div v-else class="no-result apollo">Pas de résultat :(</div>
</template>

Voici un exemple complet :

<script>
export default {
  data () {
    return {
      name: 'Anne'
    }
  }
}
</script>

<template>
  <div>
    <input v-model="name" placeholder="Renseignez votre nom">

    <ApolloQuery
      :query="gql => gql`
        query MyHelloQuery ($name: String!) {
          hello (name: $name)
        }
      `"
      :variables="{ name }"
    >
      <template v-slot="{ result: { loading, error, data } }">
        <!-- Chargement -->
        <div v-if="loading" class="loading apollo">Chargement...</div>

        <!-- Erreur -->
        <div v-else-if="error" class="error apollo">Une erreur est survenue.</div>

        <!-- RĂ©sultat -->
        <div v-else-if="data" class="result apollo">{{ data.hello }}</div>

        <!-- Pas de résultat -->
        <div v-else class="no-result apollo">No result :(</div>
      </template>
    </ApolloQuery>
  </div>
</template>

# Mise en place du gabarit étiqueté

Si vous n'utilisez pas vue-cli-plugin-apollo (opens new window) (v0.20.0+), vous devez configurer vue-loader (opens new window) pour transpiler le gabarit étiqueté. vue-loader utilise Bublé (opens new window) sous le capot pour transpiler le code dans les templates des composants. Nous devons ajouter la transformation dangerousTaggedTemplateString à Bublé pour que gql fonctionne. Par exemple, avec Vue CLI :

// vue.config.js

module.exports = {
  chainWebpack: config => {
    config.module
      .rule('vue')
      .use('vue-loader')
        .loader('vue-loader')
        .tap(options => {
          options.transpileOptions = {
            transforms: {
              dangerousTaggedTemplateString: true,
            },
          }
          return options
        })
  }
}

Dans une configuration Webpack de base, ça ressemblerait à ça :

module.exports = {
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: [
          {
            loader: 'vue-loader',
            options: {
              transpileOptions: {
                transforms: {
                  dangerousTaggedTemplateString: true
                }
              }
            }
          }
        ]
      },

      /* D'autres rĂšgles... */
    ]
  }
}

# RequĂȘter avec des fichiers gql

Une façon alternative d'utiliser le composant est de crĂ©er des fichirs .gql sĂ©parĂ©s. Ces fichiers doivent ĂȘtre prĂ©-trasnformĂ©s avec graphql-tag (opens new window).

<template>
  <ApolloQuery
    :query="require('../graphql/HelloWorld.gql')"
    :variables="{ name }"
  >
    <template v-slot="{ result: { loading, error, data } }">
      <!-- Chargement -->
      <div v-if="loading" class="loading apollo">Chargement...</div>

      <!-- Erreur -->
      <div v-else-if="error" class="error apollo">Une erreur est survenue.</div>

      <!-- RĂ©sultat -->
      <div v-else-if="data" class="result apollo">{{ data.hello }}</div>

      <!-- Pas de résultat -->
      <div v-else class="no-result apollo">Pas de résultat :(</div>
    </template>
  </ApolloQuery>
</template>

# OpĂ©rations de requĂȘte

Vous pouvez accĂ©der Ă  l'object de requĂȘte intelligent avec le prop de slot query. Voici un composant d'exemple qui pagine des donnĂ©es en utilisant fetchMore :

<template>
  <ApolloQuery
    :query="/* requĂȘte */"
    :variables="{
      limit: $options.pageSize
    }"
    v-slot="{ result: { loading, error, data }, query }"
  >
    <!-- Affichage des données -->
    <button v-if="hasMore" @click="loadMore(query)">Charger plus</button>
  </ApolloQuery>
</template>

<script>
export default {
  pageSize: 10,

  data: {
    return {
      page: 1,
      hasMore: true
    }
  },

  methods: {
    async loadMore (query) {
      await query.fetchMore({
        variables: {
          offset: this.page++ * this.$options.pageSize
        },
        updateQuery: (prev, { fetchMoreResult }) => {
          if (!fetchMoreResult || fetchMoreResult.product.length === 0) {
            this.hasMore = false
            return prev
          }
          return Object.assign({}, prev, {
            product: [...prev.product, ...fetchMoreResult.product]
          })
        }
      })
    }
  }
}
</script>

Consultez la rĂ©fĂ©rence API pour connaĂźtre toutes les mĂ©thodes de requĂȘte intelligentes.

# Utiliser des fragments

Les fragments sont intĂ©ressants pour partager des morceaux de documents GraphQL dans d'autres documents pour rĂ©cupĂ©rer la mĂȘme donnĂ©e de façon uniforme, et Ă©viter de dupliquer du code.

Imaginons que nous avons une requĂȘte GetMessages avec un champ messages qui est un tableau d'objets Message :

query GetMessages {
  messages {
    id
    user {
      id
      name
    }
    text
    created
  }
}

Nous voulons extraire tous les champs de messages qui ont le type Message dans un fragment, pour pouvoir les réutiliser ailleurs.

D'abord, importez le gabarit gql dans le composant :

import gql from 'graphql-tag'

Puis, dans la définition du composant, déclarez un nouvel objet fragments :

export default {
  fragments: {
    /** TODO */
  }
}

Voici à quoi le fragment message, qui est appliqué au type Message, ressemble :

fragment message on Message {
  id
  user {
    id
    name
  }
  text
  created
}

Nous pouvons utiliser le gabarit gql comme avec les requĂȘtes :

export default {
  fragments: {
    message: gql`
      fragment message on Message {
        id
        user {
          id
          name
        }
        text
        created
      }
    `
  }
}

Dans notre composant, nous pouvons maintenant accĂ©der au fragment grĂące Ă  this.$options.fragments.message. Pour utiliser ce fragmnt dans notre requĂȘte GetMessages, nous devons utiliser la syntaxe de dĂ©composition de GraphQL (...), ainsi que d'ajouter le fragment avec la requĂȘte :

gql`
  query GetMessages {
    messages {
      ...message
    }
  }
  ${$options.fragments.message}
`

Cela produira le document GraphQL (que vous pouvez essayer dans l'environnement de test de GraphQL de votre API) :

query GetMessages {
  messages {
    ...message
  }
}
fragment message on Message {
  id
  user {
    id
    name
  }
  text
  created
}

Que se passe-t-il ici ? GraphQL trouve l'opĂ©rateur ... oĂč l'on sĂ©lectionne des champs dans le champ messages Ă  l'intĂ©rieur de notre requĂȘte. L'opĂ©rateur ... est suivi par le nom du fragment, message, qui est ensuite recherchĂ© dans tout le document GraphQL. Nous avons correctement dĂ©fini le fragment, que nous trouvons juste aprĂšs la requĂȘte. Enfin, GraphQL copie tout le contenu du fragment et remplace ...message avec.

On obtient la requĂȘte finale :

query GetMessages {
  messages {
    id
    user {
      id
      name
    }
    text
    created
  }
}
fragment message on Message {
  id
  user {
    id
    name
  }
  text
  created
}

Voici le composant d'exemple complet :

<!-- MessageList.vue -->
<script>
import gql from 'graphql-tag'

export default {
  fragments: {
    message: gql`
      fragment message on Message {
        id
        user {
          id
          name
        }
        text
        created
      }
    `
  }
}
</script>

<template>
  <ApolloQuery
    :query="gql => gql`
      query GetMessages {
        messages {
          ...message
        }
      }
      ${$options.fragments.message}
    `"
  >
    <!-- Contenu... -->
  </ApolloQuery>
</template>

# RĂ©utiliser le fragment

Nous pouvons désormais récupérer le fragment message dans d'autres composants :

<!-- MessageForm.vue -->
<script>
import gql from 'graphql-tag'
import MessageList from './MessageList.vue'

export default {
  methods: {
    async sendMessage () {
      await this.$apollo.mutate({
        mutation: gql`
          mutation SendMessage ($input: SendMessageInput!) {
            addMessage (input: $input) {
              newMessage {
                ...message
              }
            }
          }
          ${MessageList.fragments.message}
        `,
        variables: {
          /* Variables */
        },
        /* Autres options */
      })
    }
  }
}
</script>
DerniĂšre mise Ă  jour: 11/02/2021 Ă  11:08:30