4

I know relay can inject a network layer when bootstrapping like below:

Relay.injectNetworkLayer(
  new Relay.DefaultNetworkLayer('http://example.com/graphql', {
    headers: {
      Authorization: 'Basic SSdsbCBmaW5kIHNvbWV0aGluZyB0byBwdXQgaGVyZQ==',
    },
  })
);

But how about if I need to tell what the header is later(like after signing in)?

Ron
  • 6,037
  • 4
  • 33
  • 52

3 Answers3

4

I found a simple trick. You can pass in headers object and update its pointer value.

const headers = {
    Authorization: '',
};

Relay.injectNetworkLayer(
  new Relay.DefaultNetworkLayer('http://example.com/graphql', {
    headers: headers,
  })
);

// To update the authorization, set the field.

headers.Authorization = 'Basic SSdsbCBmaW5kIHNvbWV0aGluZyB0byBwdXQgaGVyZQ=='
massanishi
  • 2,044
  • 1
  • 15
  • 9
  • Very handy! How might you go about updating the value from another file? – Alec Jan 18 '17 at 17:11
  • 1
    You can export `headers` variable you used in Relay DefaultNetworkLayer, and set the Authorization anywhere. It's the `headers.Authorization =` part, except you do that in different files. – massanishi Jan 21 '17 at 20:05
3

Great question. I imagine you're setting the network layer in your base component file. You could create a function wrapping the Relay.injectNetworkLayer call that updates the Auth header when you need to.

When loading the app, you could do something like this:

export function setNetworkLayer() {
  return new Promise((resolve, reject) => {

      var options = {};
      if (localStorage.authToken) {
        options.headers = {
          Authorization: 'Basic ' + localStorage.authToken
        }
      }
      else {
        options.headers = {};
      }
      Relay.injectNetworkLayer(
        new Relay.DefaultNetworkLayer('http://example.com/graphql', options)
      );
      resolve(options);
    });
  })
}

And if you wanted to update the network layer, you'd do something like this:

loginUser().then((res) => {
    localStorage.authToken = res.token;
    setNetworkLayer();
    return;
})
vince
  • 1,904
  • 1
  • 12
  • 17
  • This means delay injectNetworkLayer. But how about if I want to setup networkLayer with empty header(anonymous) first, after signing in setup networkLayer with valid token? – Ron Jun 14 '16 at 22:26
  • What you can do is call setNetworkLayer in your first render() function for your app. If there's no authToken detected in localStorage, then it will set the options variable as an empty object, and set the DefaultNetworkLayer with an empty header. And whenever you need to reset the network layer, you can overwrite the localStorage.authToken variable and call setNetworkLayer() again. – vince Jun 14 '16 at 22:36
  • I tried to call injectNetworkLayer twice, and got warning as: "RelayNetworkLayer: Call received to injectImplementation(), but a layer was already injected.". What's more, the new call doesn't take effect, nor did the first call stop working. – Ron Jun 14 '16 at 23:14
  • Looks like that's a warning that will be resolved in the next release: https://github.com/facebook/relay/issues/1111. For now, try re-rendering the DOM.render() when needed to load the app initially with the network layer auth token from localStorage like so: http://mgiroux.me/2016/token-auth-in-relay-app-using-rails/ – vince Jun 15 '16 at 00:10
  • 1
    Actually the issue above is talking about: injectNetworkLayer will cause the warning, even at the very first time in app. So the 0.9 release introduced injectDefaultNetworkLayer which is used only internally to set the default layer to be '/graphql'. However, what the problem we are facing now is we cannot call injectNetworkLayer twice in app. – Ron Jun 15 '16 at 00:26
2

I asked the question in github relay repo, they recommend me to use this react-relay-network-layer library to solve the problem. I believe it will be the best option to solve the problem.

Ron
  • 6,037
  • 4
  • 33
  • 52