Closed gengjiawen closed 7 years ago
Good question; we faced this use case, too.
You can pass a custom GraphQLClient
instance for endpoints to completely customize how data is fetched. In your situation, I'd suggest to extend HttpGraphQLClient
:
class AuthForwardingGraphQLClient extends HttpGraphQLClient {
protected async getHeaders(document: DocumentNode, variables?: { [name: string]: any }, context?: any, introspect?: boolean): Promise<{ [index: string]: string }> {
const headers = await super.getHeaders(document, context, introspect);
return {
...headers,
Authentication: getAuthTokenFromGraphQLContext(context)
};
}
}
const schema: GraphQLSchema = await weaveSchemas({
endpoints: [{
namespace: 'library',
client: new AuthForwardingGraphQLClient('http://example.com/graphql')
}]
});
Then, you somehow need to implement getAuthTokenFromGraphQLContext
. How this is done depends on your GraphQL server implementation. If you use express-graphql, the express Request object is passed as context, by default. Then, something like this would do the job:
function getAuthTokenFromGraphQLContext(context: any) {
if (!context) {
return undefined;
}
return context.header('Authentication');
}
There is one pitfall: When you call weaveSchemas
, the endpoints are already called with an introspection query. At this time, there is no context. If you need an authentication token for introspection queries, you need to provide it thorugh a different manner, e.g. by configuration. Use the introspect
argument to getHeaders
to distinguish those initial introspection queries from normal queries by users.
I followed your advice , but I still can't make it work, this is the demo code https://github.com/gengjiawen/schema-stitching-demo/tree/feature/pass_header, can you take a look when you have free time ? Thanks.
Sorry, I confused Authentication
and Authorization
. Also, express seems to convert the header names to lower case for some reason. I tested it locally and it at least dumped the correct token, though I did not test it with a real auth token. See this pull request in your project for the changes.
I only now realized you wrote Origin. Do you mean the HTTP Origin header? I assumed you meant authorization because you wrote token. If you want to forward the origin, just replace the header name.
thanks, I will give it a try tomorrow.
It works like as expected now, thanks. But why when i first running, I got log looks like this in the sample https://github.com/gengjiawen/schema-stitching-demo/tree/feature/pass_header? looks like the context not passed when get schema.
pass undefined
pass undefined
not valid undefined
not valid undefined
I see, that's because that time express-graphql is not used. Thanks for your great patience and help.
For anyone want to pass all the original headers, you can do something like this:
Notice to remove content-length
from original header, or you will get timeout exception. This is found by @FX-HAO
class AuthForwardingGraphQLClient extends HttpGraphQLClient {
protected async getHeaders(document: DocumentNode, variables?: { [name: string]: any }, context?: any, introspect?: boolean): Promise<{ [index: string]: string }> {
const headers = await super.getHeaders(document, context, introspect);
console.log('headers', headers)
if (context) {
console.log('context headers', context.headers)
delete context.headers['content-length']
return context.headers
} else {
return headers
}
}
}
Hey Yogu, I was just working on this exact scenario last week and came up with pretty much the same solution you suggested. It was very easy to take a look at your code to see how it could be extended. You guys did a great job with the design and API!
I need to pass the token to the server in my situation.