Skip to content
This repository has been archived by the owner on Apr 14, 2023. It is now read-only.

Apollo-link-context has no effect on apollo-link-ws #446

Open
kirill-konshin opened this issue Jan 29, 2018 · 6 comments
Open

Apollo-link-context has no effect on apollo-link-ws #446

kirill-konshin opened this issue Jan 29, 2018 · 6 comments
Labels

Comments

@kirill-konshin
Copy link

kirill-konshin commented Jan 29, 2018

I was trying to add context information with headers (like in example https://www.apollographql.com/docs/react/recipes/authentication.html) but in my case I have WS link instead of HTTP.

const authLink = setContext((req, {headers}) => ({
    headers: {
        ...headers,
        authorization: '...'
    }
}));

const client = new ApolloClient({
    link: authLink.concat(wsLink),
    cache: new InMemoryCache()
});

Context is not delivered to server, I checked it frames section in Network tab and in onOperation:

new SubscriptionServer({
  execute,
  subscribe,
  schema,
  onOperation: (message, params, webSocket) => {
    console.log('onOperation', {message, params});
    return params;
  }
}, {
  server: ws,
  path: '/subscriptions',
});

Context is equal to {}.

Moreover, on client I get the following error when using WS:

bluebird.js:1546 Warning: a promise was created in a handler but was not returned from it, see http://goo.gl/rRqMUw

Everything works well with HTTP though.

@kirill-konshin
Copy link
Author

I have traced the execution: WebSocketLink.request(operation) -> SubscriptionClient.request(operation), and the problem is that operation contain getContext getter:

{
  extensions: {},
  operationName: "Xxx"
  query: {kind: "Document", definitions: Array(4), loc: {…}}
  variables: {},
  getContext(),
  setContext()
}

Which is never called in SubscriptionClient.

@raeesaa
Copy link

raeesaa commented Jul 5, 2018

Any updates on this?

@tsirlucas
Copy link

tsirlucas commented Aug 2, 2018

Any updates?

------------ EDIT:

For googlers, I ended up using the following:

const wsLink = new WebSocketLink({
      uri: `ws://localhost:3004/graphql`,
      options: {
        reconnect: true,
        connectionParams: () => ({
          authorization: Cookie.get('token'),
        }),
      },
    });

Works just like you were setting http headers on graphql playground:

screenshot at aug 02 18-53-45

@sulliwane
Copy link

sulliwane commented Jan 17, 2019

could someone confirm that once the websocket channel has been opened (with Authorization header = token AAA), each subsequent request using the websocket link will always be identified as AAA token.

Or is there a way to send a different Authorization header on each request (other than re-opening another ws channel)?

I'd like to understand what's happening on a low level protocol for ws.

Thank you for you reply!

const wsClient = new SubscriptionClient(
  graphqlEndpoint,
  {
    reconnect: true,
    connectionParams: () => ({
      headers: {
        'Authorization': 'mytokenAAA',
      },
    }),
  },
  ws,
);
const link = new WebSocketLink(wsClient);

makePromise(execute(link, options)); // that's using token AAA
// how to make another query (execute) using token BBB without creating another link ?

@tsujp
Copy link

tsujp commented May 31, 2019

Any update on dynamically pulling JWT tokens for wsLink? I'm getting all kinds of errors or non-response when I try and mirror setups for httpLink.

@cowlicks
Copy link

@hito you should be able to set using middleware of the SubscriptionClient. See my gist here: https://gist.github.com/cowlicks/71e766164647f224bf15f086ea34fa52

const subscriptionMiddleware = {
  applyMiddleware: function(options, next) {
    // Get the current context
    const context = options.getContext();
    // set it on the `options` which will be passed to the websocket with Apollo 
    // Server it becomes: `ApolloServer({contetx: ({payload}) => (returns options)
    options.authorization = context.authorization;
    next()
  },
};

const server = new ApolloServer({
  context: ({connection, payload, req}) => {
    // whatever you return here can be accessed from the middleware of the SubscriptionMiddleware with
    // applyMiddleware: (options, next) => options.getContext()
    return {authorization: payload.authorization};
  },
});

const link = new WebSocketLink({
    uri: WS_URL,
    webSocketImpl: WebSocket,
    options: {
        reconnect: true,
    }
});

link.subscriptionClient.use([subscriptionMiddleware]);

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

No branches or pull requests

7 participants