2017-02-12 22:00:13 +08:00
import ApolloClient , { createNetworkInterface , createBatchingNetworkInterface } from 'apollo-client' ;
2017-10-05 06:24:47 -03:00
import 'cross-fetch/polyfill' ;
2017-02-12 22:00:13 +08:00
import { Meteor } from 'meteor/meteor' ;
2017-09-22 12:24:15 +02:00
import { getSetting , registerSetting } from './settings.js' ;
2017-09-14 10:06:41 +02:00
import { getFragmentMatcher } from './fragment_matcher.js' ;
2018-01-25 15:03:03 -06:00
import { runCallbacks } from './callbacks.js' ;
2017-02-06 14:33:34 +08:00
2018-02-07 10:29:02 +09:00
registerSetting ( 'graphQLendpointURL' , '/graphql' , 'GraphQL endpoint URL' ) ;
2017-09-22 12:24:15 +02:00
2017-02-06 14:33:34 +08:00
const defaultNetworkInterfaceConfig = {
2017-02-12 22:00:13 +08:00
path : '/graphql' , // default graphql server endpoint
2018-10-02 12:25:14 +09:00
opts : { foo : 'bar' } , // additional fetch options like `credentials` or `headers`; note: for some reason when this is empty additional options can't be added
2017-02-12 22:00:13 +08:00
useMeteorAccounts : true , // if true, send an eventual Meteor login token to identify the current user with every request
2017-04-15 12:03:25 +09:00
batchingInterface : true , // use a BatchingNetworkInterface by default instead of a NetworkInterface
2017-02-12 22:00:13 +08:00
batchInterval : 10 , // default batch interval
2017-02-06 14:33:34 +08:00
} ;
const createMeteorNetworkInterface = ( givenConfig = { } ) => {
2017-02-12 22:00:13 +08:00
const config = { ... defaultNetworkInterfaceConfig , ... givenConfig } ;
2017-02-06 14:33:34 +08:00
2018-10-02 12:25:14 +09:00
// console.log('// apollo.js createMeteorNetworkInterface config.headers');
// console.log(config.headers); // note: only defined on server
// console.log('\n\n');
2017-02-06 14:33:34 +08:00
// absoluteUrl adds a '/', so let's remove it first
let path = config . path ;
if ( path [ 0 ] === '/' ) {
path = path . slice ( 1 ) ;
}
2018-02-07 10:29:02 +09:00
const defaultUri = Meteor . absoluteUrl ( path ) ;
const uri = getSetting ( 'graphQLendpointURL' , defaultUri ) ;
2017-02-12 22:00:13 +08:00
// allow the use of a batching network interface; if the options.batchingInterface is not specified, fallback to the standard network interface
const interfaceToUse = config . batchingInterface ? createBatchingNetworkInterface : createNetworkInterface ;
// default interface options
const interfaceOptions = {
2017-02-10 09:54:11 +01:00
uri ,
2017-02-06 14:33:34 +08:00
opts : {
2017-02-12 22:00:13 +08:00
credentials : 'same-origin' , // http://dev.apollodata.com/react/auth.html#Cookie
} ,
} ;
2017-02-06 14:33:34 +08:00
2017-02-12 22:00:13 +08:00
// if a BatchingNetworkInterface is used with a correct batch interval, add it to the options
if ( config . batchingInterface && config . batchInterval ) {
interfaceOptions . batchInterval = config . batchInterval ;
}
2017-02-06 14:33:34 +08:00
2017-02-12 22:00:13 +08:00
// if 'fetch' has been configured to be called with specific opts, add it to the options
if ( Object . keys ( config . opts ) . length > 0 ) {
interfaceOptions . opts = config . opts ;
}
2017-02-06 14:33:34 +08:00
2017-02-12 22:00:13 +08:00
const networkInterface = interfaceToUse ( interfaceOptions ) ;
2017-02-06 14:33:34 +08:00
2017-02-12 22:00:13 +08:00
if ( config . useMeteorAccounts ) {
networkInterface . use ( [ {
2017-04-15 12:03:25 +09:00
applyBatchMiddleware ( request , next ) {
2017-02-12 22:00:13 +08:00
const currentUserToken = Meteor . isClient ? global . localStorage [ 'Meteor.loginToken' ] : config . loginToken ;
2017-02-06 14:33:34 +08:00
2018-10-02 12:25:14 +09:00
if ( Meteor . isServer ) {
// handle server use case separetly or else everything breaks
if ( ! request . options . headers ) {
request . options . headers = new Headers ( ) ;
}
request . options . headers = config . headers ;
// if we're on the server and this request has been originated by a client
// (and not SSR) save the original headers
if ( config . headers && ! config . headers . originalHeaders ) {
request . options . headers . originalHeaders = JSON . stringify ( config . headers ) ;
}
if ( ! currentUserToken ) {
next ( ) ;
return ;
}
request . options . headers . Authorization = currentUserToken ;
next ( ) ;
} else {
// handle client use case separetly or else everything breaks
if ( ! currentUserToken ) {
next ( ) ;
return ;
}
if ( ! request . options . headers ) {
request . options . headers = new Headers ( ) ;
}
request . options . headers . Authorization = currentUserToken ;
2017-02-12 22:00:13 +08:00
next ( ) ;
}
2018-10-02 12:25:14 +09:00
2017-02-12 22:00:13 +08:00
} ,
} ] ) ;
}
2017-02-06 14:33:34 +08:00
return networkInterface ;
} ;
2017-09-14 10:06:41 +02:00
const meteorClientConfig = networkInterfaceConfig => {
return {
ssrMode : Meteor . isServer ,
networkInterface : createMeteorNetworkInterface ( networkInterfaceConfig ) ,
queryDeduplication : true , // http://dev.apollodata.com/core/network.html#query-deduplication
addTypename : true ,
fragmentMatcher : getFragmentMatcher ( ) ,
// Default to using Mongo _id, must use _id for queries.
dataIdFromObject ( result ) {
if ( result . _id && result . _ _typename ) {
const dataId = result . _ _typename + result . _id ;
return dataId ;
}
return null ;
} ,
}
} ;
export const createApolloClient = options => {
2017-10-05 06:24:47 -03:00
2017-09-14 10:06:41 +02:00
runCallbacks ( 'apolloclient.init.before' ) ;
return new ApolloClient ( meteorClientConfig ( options ) ) ;
} ;