Unofficial Vue2 integration for Apollo
MIT License
ApolloVue~
https://github.com/Akryum/meteor-vue-component
npm install okoala/vue-apollo --save
ApolloClient
. more in the apollo doc.
import { VueApollo } from 'okoala/vue-apollo'
VueApollo.setApolloClientOptions({
shouldBatch: true
})
ApolloClient
:
console.log(VueApollo.client)
options
import ApolloClient from 'apollo-client'
VueApollo.client = new ApolloClient(options)
new Vue({
apollo: {
// Apollo specific options
}
});
this.$apollo.client
apollo-client .
user (root, args, context) {
// id
if (context.user._id === args.id) {
return context.user
}
}
In the data
object, add an attribute for each property you want to feed with the result of an Apollo query.
Put the gql query directly as the value:
apollo: {
// Non-reactive query
data: {
// Simple query that will update the 'hello' vue property
hello: gql`{hello}`
}
}
:
data () {
return {
hello: ''
}
}
schemaresolvers
export const schema = `
type Query {
hello: String
}
schema {
query: Query
}
`
export const resolvers = {
Query: {
hello(root, args, context) {
return "Hello world!"
}
}
}
, apollo doc.
:
<template>
<div class="apollo">
<h3>Hello</h3>
<p>
{{hello}}
</p>
</div>
</template>
You can add variables (read parameters) to your gql
query by declaring query
and variables
in an object:
// Apollo-specific options
apollo: {
// Non-reactive query
data: {
// Query with parameters
ping: {
// gql query
query: gql`query PingMessage($message: String!) {
ping(message: $message)
}`,
// Static parameters
variables: {
message: 'Meow'
}
}
}
}
apollo options:
forceFetch
fragments
, apollo doc.
, forceFetch
:
apollo: {
data: {
// Query with parameters
ping: {
query: gql`query PingMessage($message: String!) {
ping(message: $message)
}`,
variables: {
message: 'Meow'
},
forceFetch: true
}
}
}
data () {
return {
// Initialize your apollo data
ping: ''
}
}
export const schema = `
type Query {
ping(message: String!): String
}
schema {
query: Query
}
`
export const resolvers = {
Query: {
ping(root, { message }, context) {
return `Answering ${message}`
}
}
}
<template>
<div class="apollo">
<h3>Ping</h3>
<p>
{{ping}}
</p>
</div>
</template>
Use a function instead to make the parameters reactive with vue properties:
// Apollo-specific options
apollo: {
// Non-reactive query
data: {
// Query with parameters
ping: {
query: gql`query PingMessage($message: String!) {
ping(message: $message)
}`,
// Reactive parameters
variables() {
// Use vue reactive properties here
return {
message: this.pingInput
}
}
}
}
}
This will re-fetch the query each time a parameter changes, for example:
<template>
<div class="apollo">
<h3>Ping</h3>
<input v-model="pingInput" placeholder="Enter a message" />
<p>
{{ping}}
</p>
</div>
</template>
These are the available advanced options you can use:
update(data) {return ...}
to customize the value that is set in the vue property, for example if the field names don't matchresult(data)
is a hook called when a result is receivederror(errors, type)
is a hook called when there are errors, type
value can either be 'sending'
or 'execution'
loadingKey
will update the component data property you pass as the value. You should initialize this property to 0
in the component data()
hook. When the query is loading, this property will be incremented by 1 and as soon as it no longer is, the property will be decremented by 1. That way, the property can represent a counter of currently loading queries.watchLoading(isLoading, countModifier)
is a hook called when the loading state of the query changes. The countModifier
parameter is either equal to 1
when the query is now loading, or -1
when the query is no longer loading.// Apollo-specific options
apollo: {
// Non-reactive query
data: {
// Advanced query with parameters
// The 'variables' method is watched by vue
pingMessage: {
query: gql`query PingMessage($message: String!) {
ping(message: $message)
}`,
// Reactive parameters
variables() {
// Use vue reactive properties here
return {
message: this.pingInput
}
},
// We use a custom update callback because
// the field names don't match
// By default, the 'pingMessage' attribute
// would be used on the 'data' result object
// Here we know the result is in the 'ping' attribute
// considering the way the apollo server works
update(data) {
console.log(data)
// The returned value will update
// the vue property 'pingMessage'
return data.ping
},
// Optional result hook
result(data) {
console.log("We got some result!")
},
// Error handling
error(errors, type) {
console.error(`We've got ${errors.length} errors of type '${type}'`)
},
// Loading state
// loadingKey is the name of the data property
// that will be incremented when the query is loading
// and decremented when it no longer is.
loadingKey: 'loadingQueriesCount',
// watchLoading will be called whenever the loading state changes
watchLoading(isLoading, countModifier) {
// isLoading is a boolean
// countModifier is either 1 or -1
}
}
}
}
For now, the reactivity in apollo is quite limited, since you can only do polling.
For more info, see the apollo doc.
Add your queries in a watch
object instead of data
:
// Apollo-specific options
apollo: {
// Reactive query
watch: {
// 'tags' data property on vue instance
tags: {
query: gql`{
tags {
id,
label
}
}`,
pollInterval: 300 // ms
}
}
}
You can use the following apollo options:
forceFetch
returnPartialData
pollInterval
fragments
See the apollo doc for more details.
You can also use the advanced options detailed above, like result
or watchLoading
.
Here is how the server-side looks like:
export const schema = `
type Tag {
id: Int
label: String
}
type Query {
tags: [Tag]
}
schema {
query: Query
}
`;
// Fake word generator
import casual from 'casual';
// Let's generate some tags
var id = 0;
var tags = [];
for (let i = 0; i < 42; i++) {
addTag(casual.word);
}
function addTag(label) {
let t = {
id: id++,
label
};
tags.push(t);
return t;
}
export const resolvers = {
Query: {
tags(root, args, context) {
return tags;
}
}
};
Mutations are queries that changes your data state on your apollo server. For more info, visit the apollo doc.
methods: {
addTag() {
// Mutate the tags data
// You can also use this.$apollo.client.mutate
this.$apollo.mutate({
mutation: gql`mutation AddTag($label: String!) {
addTag(label: $label) {
id,
label
}
}`,
// Parameters
variables: {
label: this.tagLabel
}
}).then((data) => {
// Result
console.log(data);
this.tagLabel = '';
}).catch((error) => {
// Error
console.error(error);
});
}
}
Server-side:
export const schema = `
type Tag {
id: Int
label: String
}
type Query {
tags: [Tag]
}
type Mutation {
addTag(label: String!): Tag
}
schema {
query: Query
mutation: Mutation
}
`;
// Fake word generator
import faker from 'faker';
// Let's generate some tags
var id = 0;
var tags = [];
for (let i = 0; i < 42; i++) {
addTag(faker.random.word());
}
function addTag(label) {
let t = {
id: id++,
label
};
tags.push(t);
return t;
}
export const resolvers = {
Query: {
tags(root, args, context) {
return tags;
}
},
Mutation: {
addTag(root, { label }, context) {
console.log(`adding tag '${label}'`);
return addTag(label);
}
}
};