Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apollo client with options (specifically Fetch authorization) #5

Open
bjunc opened this issue Jul 3, 2017 · 5 comments
Open

Apollo client with options (specifically Fetch authorization) #5

bjunc opened this issue Jul 3, 2017 · 5 comments
Labels

Comments

@bjunc
Copy link

bjunc commented Jul 3, 2017

Echoing the sentiment that making Apollo requests within the component is not a practice that scales to larger applications (likely using Vuex, or some other state management).

One thing I noticed about your example though, is that it instantiates the Apollo client without the ability for main.js to pass options into the client.

Curious to hear your take on this, but my solution was to make the client globally accessible:

// main.js

let user = window.__INITIAL_STATE__.user;

// Create the apollo client
const apolloClient = new ApolloClient({
   networkInterface: createNetworkInterface({
      uri:           '/graphql',
      transportBatching:   true,
      opts: { headers: { Authorization: 'Bearer ' + user.token } } 
   }),
   connectToDevTools: true
}); 

// Make apollo client globally accessible via Vue.$apollo
Object.defineProperty(Vue, '$apollo', {
   get () { return  apolloClient; }
});
// /store/index.js

export default new Vuex.Store({
   actions: {
      fetchFooBar (context) {
         Vue.$apollo.query({ ... });
      }
   }
});

Thoughts?

@PierBover
Copy link
Owner

PierBover commented Jul 3, 2017

In a real project, configuration would not really come from main.js but from your environment configuration so you can switch between dev and production automatically.

In this particular project this would be done here because I used the template webpack-simple for simplicity's sake.

https://github.com/PierBover/vuex-apollo-example-project/blob/master/webpack.config.js#L55-L58

When using Vue CLI with the webpack template, you have separate configs for each environment.

Then webpack creates the vars on your application using DefinePlugin , and you can finally in your code do something like process.env.API_URL to dynamically get the URL of your API.

@bjunc
Copy link
Author

bjunc commented Jul 3, 2017

Maybe I should have been more specific. Using the DefinePlugin is well and good for things that are environment specific, but per the example above, the Apollo network interface is created with an Authentication header passing the user token. That's not environment specific, but rather specific to the page request. Even if the overall network interface options are set via the DefinePlugin (eg. uri), you'd still need a way to pass the user token. How would you recommend doing this?

@PierBover
Copy link
Owner

It really depends on how you are doing auth.

I've been doing auth via REST for GraphQL projects. Once I have the token I init Apollo Client. This worked for me since all my endpoints are private, but it would not work as a general approach since many APIs have public and private endpoints.

As per the docs it's possible to use different middlewares:
http://dev.apollodata.com/core/network.html

Maybe the solution is to use networkInterface.use([...]); and add a new middleware once you have the token.

@bjunc
Copy link
Author

bjunc commented Jul 6, 2017

Right, but doesn't that put us right back at my original post? How would you structure your imports to pass necessary vars to your apollo client (networkInterface)? Differently than I did above? Any thoughts on making the apollo client globally accessible as I did above (eg. Vue.$apollo)?

@PierBover
Copy link
Owner

How would you structure your imports to pass necessary vars to your apollo client (networkInterface)?

Personally I would just create an Apollo module with an init() method which instantiates Apollo with a config object.

Something like this:

let apolloClient;

export default {
    init(config){
        // init Apollo here
        apolloClient = new ApolloClient(...)
    },
    apolloClient
}

(This is of course a simplification)

Any thoughts on making the apollo client globally accessible as I did above (eg. Vue.$apollo)?

With Vue.$apollo you'd be making Apollo globally accessible to Vue which is the view layer. Apollo is in the data / network layer and your view layer (Vue components) should only communicate with the store (Vuex) and not with Apollo directly.

Again, just use import yourApolloModule from '../path/etc/yourApolloModule.js' whenever you need it (probably from your store, main.js, and your auth module).

You can resolve paths automatically (no need to use ../path/etc/) by configuring resolve modules in Webpack. If you are using Vue CLI with Webpack template check the file webpack.base.conf.js.

  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      '@': resolve('src'),
	  vue: 'vue/dist/vue.js'
    },
	modules: [ path.resolve('./src/components'), path.resolve('./src'), 'node_modules']
  },

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants