graphql-client icon indicating copy to clipboard operation
graphql-client copied to clipboard

Adding Custom Header to GraphQLHttpClient

Open aschattopadhyay opened this issue 3 years ago • 4 comments

Hi there:

I have got a GraphQL Client instance which is tying to call a GraphQL API endpoint. My code looks like below:

`var graphQLClient = new GraphQLHttpClient("https://abc.com/graphql", new NewtonsoftJsonSerializer());

var raceRequest = new GraphQLRequest { Query = @" query ($input: GetRaceResultsInput, $before: String, $after: String, $first: Int, $last: Int) { getRaceResults(before: $before, after: $after, first: $first, last: $last, input: $input) { edges { cursor node { raceId horses { horseId } } } } }" };

var graphQLResponse = await graphQLClient.SendQueryAsync<RaceResult>(raceRequest);`

RaceResult is of the format: public class RaceResult { public string Result { get; set; } }

When the SendQueryAsync is excuted, I get the following error:

System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception. System.ComponentModel.Win32Exception (0x80090326): The message received was unexpected or badly formatted.

My request header in postman has got custom key value pair like x-developer-secret and I get the desired result. Is there anyway to add customer header before calling the API? I tried the following:

graphQLClient.HttpClient.DefaultRequestHeaders.Add("Authorization", $"bearer abcsecret");

However it didn't work. Any help would be appreciated.

Thanks

aschattopadhyay avatar Apr 25 '21 14:04 aschattopadhyay

Well... you added an Authorization header... But I suppose you'd need to add a x-developer-secret header instead?

rose-a avatar Apr 28 '21 21:04 rose-a

In his example, aschattopadhyay added Authorization to whole HttpClient:

Please note that maybe this is not what you want:

This solution (adding to HttpClient.DefaultRequestHeaders) is heavily dependent on how you get yout HttpClient instance and what you want to do:

  • This works when you have HttpClient as "transient" but thats bad idea because Socket Exhaustion
  • This is ok when you are doing queries only on behalf of one specific user (ie you have ApiKey or DeviceKey and are sending requests to (lets say) google calendar as app).
  • This is broken when you have long-living HttpClient (ie HttpClientFactory or GraphQLHttpClient as singleton) and you are doing request on behalf of multiple users (not in single request of course, for example one microservice calling other & setting user becouse of role management: multiple requests will race which Authorization is really send. May work at 99% of cases, i dont know)

(My use case is point 3)

I think (i am not collaborator, i just goes and looks in source code because there AFAIK isnt any documentation) the right solution is extend and override HttpRequestMessage ToHttpRequestMessage

something like

public class GraphQLHttpRequestWithHeadersSupport : GraphQLHttpRequest
{
  public override HttpRequestMessage ToHttpRequestMessage(GraphQLHttpClientOptions options, IGraphQLJsonSerializer serializer)
  {
    var r = base.ToHttpRequestMessage(options, serializer);
    r.Headers = SET YOUR REQUEST SPECIFIC HEADERS
  }
}


var graphQLClient = new GraphQLHttpClient("https://abc.com/graphql", new NewtonsoftJsonSerializer());
var raceRequest = new GraphQLHttpRequestWithHeadersSupport {Query = @"your query"};
var graphQLResponse = await graphQLClient.SendQueryAsync(raceRequest);

This HttpRequestMessage is used in client.SendAsyn() so you are not setting DefaultRequestHeaders and everything should work.

Pretty much #330

kondelik avatar Aug 13 '21 08:08 kondelik

something like

public class GraphQLHttpRequestWithHeadersSupport : GraphQLHttpRequest
...

This HttpRequestMessage is used in client.SendAsyn() so you are not setting DefaultRequestHeaders and everything should work.

Good suggestion. I ended up making the Authorization Header customizable.

public class GraphQLHttpRequestWithAuthSupport : GraphQLHttpRequest {
	public AuthenticationHeaderValue? Authentication { get; set; }

	public override HttpRequestMessage ToHttpRequestMessage(GraphQLHttpClientOptions options, IGraphQLJsonSerializer serializer) {
		var r = base.ToHttpRequestMessage(options, serializer);
		r.Headers.Authorization = Authentication;
		return r;
	}
}

Usage:

var getTokenRequest = new GraphQLHttpRequestWithAuthSupport  {
        Query = @"{ myQuery }",
	Authentication = new AuthenticationHeaderValue(@"Bearer", @"xyz")
};

RevZero avatar May 17 '22 08:05 RevZero

Should really be part of the doc, it's very difficult to guess that just to add a JWT in Authorization for ex

glb-cblin avatar Feb 07 '24 13:02 glb-cblin