关于vue和apollo-client的结合(一)

基础版

1、先来看看最基础的配置

import {ApolloClient} from 'apollo-client'
import {createHttpLink} from 'apollo-link-http'
import {InMemoryCache} from 'apollo-cache-inmemory'
import {ApolloLink} from 'apollo-link'
import vue from 'vue'

const httpLink = createHttpLink({
  uri: 'https://www.baidu.com/graphql'  //配置api调用连接
})

const middlewareLink = new ApolloLink((operation, forward) => {
  operation.setContext({
    headers: {
      'access-token': sessionStorage.getItem('access-token') || null
    }
  })  //request拦截器

  return forward(operation).map(response => {
    return response
  })  //response拦截器,但是此处并不能对错误响应进行拦截
})

const authLink = middlewareLink.concat(httpLink)

const defaultOptions = {
  watchQuery: {
    fetchPolicy: 'network-only',
    errorPolicy: 'ignore'
  },
  query: {
    fetchPolicy: 'network-only',
    errorPolicy: 'all'
  }
}

const apollo = new ApolloClient({
  link: authLink,
  cache: new InMemoryCache(),
  connectToDevTools: true,
  defaultOptions: defaultOptions
})

export default apollo

2、如果在请求需要带入cookie, 需要配置credentials参数

const httpLink = createHttpLink({
  uri: 'https://www.baidu.com/graphql',
  credentials: 'include'
})

升级版

1、加入错误响应拦截器

npm install apollo-link-error --save
const errorLink = onError(({networkError, response}) => {
  let errorMsg = ''
  if (!!response && response.errors !== undefined && response.errors.length) {
    errorMsg = !response.errors[0].message ? '服务器错误' : response.errors[0].message
  }
  if (!!networkError) {
    errorMsg = networkError.message
    if (networkError.result !== undefined) {
      errorMsg = networkError.result.success === false ? networkError.result.message : networkError.result.error
    }
  }
  if (!!errorMsg) {
    vue.prototype.$alert(errorMsg) //用vue的ale
  }
})

2、在前端apollo-client默认是不支持联合查询的。如果我们的graphql中存在如下的语法

...on A{
       name
 }
...on B{
      name
}

浏览器中就会报错

You are using the simple (heuristic) fragment matcher, but your queries contain union or interface types.
Apollo Client will not be able to able to accurately map fragments.To make this error go away, 
use the IntrospectionFragmentMatcher as described in the docs: 
https://www.apollographql.com/docs/react/recipes/fragment-matching.html

解决方法如下,加入如下配置

const fragmentMatcher = new IntrospectionFragmentMatcher({
  introspectionQueryResultData: {
    __schema: {
      types: [
        {
          kind: 'INTERFACE',
          name: 'Document',
          possibleTypes: [
            {name: 'MyInterface1'},
            {name: 'SomeInterface2'}
          ]
        }
      ]
    }
  }
})

最终版

完整配置

import {ApolloClient} from 'apollo-client'
import {createHttpLink} from 'apollo-link-http'
import {InMemoryCache, IntrospectionFragmentMatcher} from 'apollo-cache-inmemory'
import {ApolloLink} from 'apollo-link'
import {onError} from 'apollo-link-error'
import vue from 'vue'

const httpLink = createHttpLink({
  uri: 'https://www.baidu.com/graphql',
  credentials: 'include'
})

const middlewareLink = new ApolloLink((operation, forward) => {
  operation.setContext({
    headers: {
      'access-token': sessionStorage.getItem('access-token') || null
    }
  })

  return forward(operation).map(response => {
    return response
  })
})

const errorLink = onError(({networkError, response}) => {
  let errorMsg = ''
  if (!!response && response.errors !== undefined && response.errors.length) {
    errorMsg = !response.errors[0].message ? '服务器错误' : response.errors[0].message
  }
  if (!!networkError) {
    errorMsg = networkError.message
    if (networkError.result !== undefined) {
      errorMsg = networkError.result.success === false ? networkError.result.message : networkError.result.error
    }
  }
  if (!!errorMsg) {
    vue.prototype.$alert(errorMsg)
  }
})

const authLink = middlewareLink.concat(httpLink)

const defaultOptions = {
  watchQuery: {
    fetchPolicy: 'network-only',
    errorPolicy: 'ignore'
  },
  query: {
    fetchPolicy: 'network-only',
    errorPolicy: 'all'
  }
}

const fragmentMatcher = new IntrospectionFragmentMatcher({
  introspectionQueryResultData: {
    __schema: {
      types: [
        {
          kind: 'INTERFACE',
          name: 'Document',
          possibleTypes: [
            {name: 'MyInterface1'},
            {name: 'SomeInterface2'}
          ]
        }
      ]
    }
  }
})

const apollo = new ApolloClient({
  link: errorLink.concat(authLink),
  cache: new InMemoryCache({fragmentMatcher}),
  connectToDevTools: true,
  defaultOptions: defaultOptions
})

export default apollo

推荐阅读更多精彩内容