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

Add support for dynamic headers #91

Closed
wants to merge 2 commits into from

Conversation

Budry
Copy link

@Budry Budry commented Jun 25, 2018

Motivation (for example):
We want get actual user authorization token from store for each request. Now we must create a new client for each request and is not optimal.
Can be used for others dynamic values which can be modified

import { GraphQLClient } from 'graphql-request'
import store from './store'

const client = new GraphQLClient('my-endpoint', {
  headers: {
    // Now we can get actual token from store for each request
    Authorization: () => store.getIdentity().getToken(),
  },
})

const query = `{
  Movie(title: "Inception") {
    releaseDate
    actors {
      name
    }
  }
}`

client.request(query).then(data => console.log(data))

@stphnnnn
Copy link
Contributor

It seems the most common use case would be for setting auth headers.

The workaround I settled with was to use the setHeader function in my login and logout logic. It would be nice however, not to have to expose graphql-request functions to the wider application and have the headers option take a function.

Are there any plans to merge this PR or any reasons why it might not be desirable?

@sethidden
Copy link
Contributor

sethidden commented Apr 12, 2022

If you really want to do this without this PR (seeing as it's up for a while) you can use a proxy:

  const proxyHandler : ProxyHandler<any> = {
    get(_, key) {
      const customerToken = getCustomerToken();
      const store = getStore();
      const currency = getCurrency();

      return {
        Authorization: `Bearer ${customerToken}`,
        store,
        'Content-Currency': currency,
      }[key] ?? undefined;
    },
    ownKeys() {
      const customerToken = getCustomerToken();
      const store = getStore();
      const currency = getCurrency();
      /*
       * Add key to object only if it'll have a value
       * We don't want to send 'Authorization: undefined' in Network requests - so the key *needs* to be absent
       */
      return [
        ...(!!customerToken ? ['Authorization'] : []),
        ...(!!store ? ['store'] : []),
        ...(!!currency? ['Content-Currency'] : []),
      ];
    },
    getOwnPropertyDescriptor(target, key) {
      return {
        value: this.get(target, key),
        enumerable: true,
        configurable: true,
      };
    },
  };

  const headers = new Proxy({}, proxyHandler); // use like new GraphQLClient(endpoint, { headers: headers } )

The headers in graphql-request are spread before each request - ...headers. So you need to make sure that whenever "headers" is spread, it will spit out only the properties that are actually set.

  1. headers is spread within graphql-request
  2. proxy's ownKeys() is called to see which keys should be spread
  3. for each of the keys returned by ownKeys, the proxy handler's get() method is called

On subsequent reads of headers, the values returned by ownKeys will be different, based on your custom condition. In my case it was getCustomerToken(), getStore(), getCurrency() etc.

@jasonkuhrt
Copy link
Owner

New PR welcome

@sethidden sethidden mentioned this pull request Apr 13, 2022
@jasonkuhrt
Copy link
Owner

Replaced by #341

@jasonkuhrt jasonkuhrt closed this Apr 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants