akryum:vue-apollo

v0.0.2Published 9 years ago

This package has not had recent updates. Please investigate it's current state before committing to using it in your project.

Apollo in Vue

Integrates apollo in your vue components with declarative queries.

TODO npm package for use in non-meteor project

Installation

meteor add akryum:vue-apollo

Usage

Set the environment variable APOLLO_CLIENT_URL to the URL of your apollo serveur (default is /graphql).

To declare apollo queries in your Vue component, add an apollo object :

1new Vue({
2    apollo: {
3        // Apollo specific options
4    }
5});

You can access the apollo-client instance with this.$apollo.client in all your vue components.

In your apollo server resolvers, you can access the current Meteor user like this:

1user(root, args, context) {
2  // Only return data if the fetched id matches the current user, for security
3  if (context.user._id === args.id) {
4    return context.user;
5  }
6}

Queries

In the data object, add an attribute for each property you want to feed with the result of an Apollo query.

Simple query

Put the gql query directly as the value:

1apollo: {
2  // Non-reactive query
3  data: {
4    // Simple query that will update the 'hello' vue property
5    hello: gql`{hello}`
6  }
7}

You don't need to call registerGqlTag, it's already done by the package so you can use gql everywhere in your app.

Don't forget to initialize your property in your vue component:

1data () {
2  return {
3    // Initialize your apollo data
4    hello: ''
5  }
6}

Server-side, add the corresponding schema and resolver:

1export const schema = `
2type Query {
3  hello: String
4}
5
6schema {
7  query: Query
8}
9`;
10
11export const resolvers = {
12  Query: {
13    hello(root, args, context) {
14      return "Hello world!";
15    }
16  }
17};

For more info, visit the apollo doc.

You can then use your property as usual in your vue component:

1<template>
2  <div class="apollo">
3    <h3>Hello</h3>
4    <p>
5      {{hello}}
6    </p>
7  </div>
8</template>

Query with parameters

You can add variables (read parameters) to your gql query:

1// Apollo-specific options
2apollo: {
3  // Non-reactive query
4  data: {
5    // Query with parameters
6    ping: {
7      // gql query
8      query: gql`query PingMessage($message: String!) {
9        ping(message: $message)
10      }`,
11      // Static parameters
12      variables: {
13        message: 'Meow'
14      }
15    }
16  }
17}

Don't forget to initialize your property in your vue component:

1data () {
2  return {
3    // Initialize your apollo data
4    ping: ''
5  }
6}

Server-side, add the corresponding schema and resolver:

1export const schema = `
2type Query {
3  ping(message: String!): String
4}
5
6schema {
7  query: Query
8}
9`;
10
11export const resolvers = {
12  Query: {
13    ping(root, { message }, context) {
14      return `Answering ${message}`;
15    }
16  }
17};

And then use it in your vue component:

1<template>
2  <div class="apollo">
3    <h3>Ping</h3>
4    <p>
5      {{ping}}
6    </p>
7  </div>
8</template>

Reactive parameters

Use a function instead to make the parameters reactive with vue properties:

1// Apollo-specific options
2apollo: {
3  // Non-reactive query
4  data: {
5    // Query with parameters
6    ping: {
7      query: gql`query PingMessage($message: String!) {
8        ping(message: $message)
9      }`,
10      // Reactive parameters
11      variables() {
12        // Use vue reactive properties here
13        return {
14            message: this.pingInput
15        }
16      }
17    }
18  }
19}

This will re-fetch the query each time a parameter changes, for example:

1<template>
2  <div class="apollo">
3    <h3>Ping</h3>
4    <input v-model="pingInput" placeholder="Enter a message" />
5    <p>
6      {{ping}}
7    </p>
8  </div>
9</template>

Advanced options

Available advanced options:

  • forceFetch: true see the apollo doc
  • update(data) {return ...} to customize the value that is set in the vue property, for example if the field names don't match
  • result(data) is a hook called when a result is received
  • error(errors, type) is a hook called when there are errors, type value can either be 'sending' or 'execution'
1// Apollo-specific options
2apollo: {
3  // Non-reactive query
4  data: {
5    // Advanced query with parameters
6    // The 'variables' method is watched by vue
7    pingMessage: {
8      query: gql`query PingMessage($message: String!) {
9        ping(message: $message)
10      }`,
11      // Reactive parameters
12      variables() {
13        // Use vue reactive properties here
14        return {
15            message: this.pingInput
16        }
17      },
18      // We use a custom update callback because
19      // the field names don't match
20      // By default, the 'pingMessage' attribute
21      // would be used on the 'data' result object
22      // Here we know the result is in the 'ping' attribute
23      // considering the way the apollo server works
24      update(data) {
25        console.log(data);
26        // The returned value will update
27        // the vue property 'pingMessage'
28        return data.ping;
29      },
30      // Optional result hook
31      result(data) {
32        console.log("We got some result!");
33      },
34      // Error handling
35      error(errors, type) {
36        console.error(`We've got ${errors.length} errors of type '${type}'`);
37      }
38    }
39  }
40}

Reactive Queries

For now, the reactivity in apollo is quite limited and unstable. You can only do polling and it is currently broken (but should be fixed soon, see https://github.com/apollostack/apollo-client/pull/262).

For more info, see the apollo doc.

Add your queries in a watch object instead of data:

1// Apollo-specific options
2apollo: {
3  // Reactive query
4  watch: {
5    // 'tags' data property on vue instance
6    tags: {
7      query: gql`{
8        tags {
9          id,
10          label
11        }
12      }`,
13      pollInterval: 300
14    }
15  }
16}

And server-side:

1export const schema = `
2type Tag {
3  id: Int
4  label: String
5}
6
7type Query {
8  tags: [Tag]
9}
10
11schema {
12  query: Query
13}
14`;
15
16// Fake word generator
17import casual from 'casual';
18
19// Let's generate some tags
20var id = 0;
21var tags = [];
22for (let i = 0; i < 42; i++) {
23  addTag(casual.word);
24}
25
26function addTag(label) {
27  let t = {
28    id: id++,
29    label
30  };
31  tags.push(t);
32  return t;
33}
34
35export const resolvers = {
36  Query: {
37    tags(root, args, context) {
38      return tags;
39    }
40  }
41};

Mutations

Mutations are queries that changes your data state on your apollo server. For more info, visit the apollo doc.

1methods: {
2  addTag() {
3    // Mutate the tags data
4    // You can also use this.$apollo.client.mutate
5    this.$apollo.mutate({
6      mutation: gql`mutation AddTag($label: String!) {
7        addTag(label: $label) {
8          id,
9          label
10        }
11      }`,
12      // Parameters
13      variables: {
14        label: this.tagLabel
15      }
16    }).then((data) => {
17      // Result
18      console.log(data);
19      this.tagLabel = '';
20    }).catch((error) => {
21      // Error
22      console.error(error);
23    });
24  }
25}

Server-side:

1export const schema = `
2type Tag {
3  id: Int
4  label: String
5}
6
7type Query {
8  tags: [Tag]
9}
10
11type Mutation {
12  addTag(label: String!): Tag
13}
14
15schema {
16  query: Query
17  mutation: Mutation
18}
19`;
20
21// Fake word generator
22import casual from 'casual';
23
24// Let's generate some tags
25var id = 0;
26var tags = [];
27for (let i = 0; i < 42; i++) {
28  addTag(casual.word);
29}
30
31function addTag(label) {
32  let t = {
33    id: id++,
34    label
35  };
36  tags.push(t);
37  return t;
38}
39
40export const resolvers = {
41  Query: {
42    tags(root, args, context) {
43      return tags;
44    }
45  },
46  Mutation: {
47    addTag(root, { label }, context) {
48      console.log(`adding tag '${label}'`);
49      return addTag(label);
50    }
51  }
52};

LICENCE ISC - Created by Guillaume CHAU (@Akryum)