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

Dynamically set headers when calling Client#parse #210

Open
wandy-dev opened this issue Jun 20, 2019 · 7 comments
Open

Dynamically set headers when calling Client#parse #210

wandy-dev opened this issue Jun 20, 2019 · 7 comments

Comments

@wandy-dev
Copy link

wandy-dev commented Jun 20, 2019

This is related to #192 but I think it warrants it's own issue.

Our api has the schema behind authorization as well. So this example for setting up a query in the readme would also require context as an argument.

HeroNameQuery = SWAPI::Client.parse <<-'GRAPHQL'
  query {
    hero {
      name
    }
  }
GRAPHQL

But if we look at the source code for the parse method we can see that there is no such option.

def parse(str, filename = nil, lineno = nil)

Is there any way to pass headers when defining queries? It seems to me that either every method implemented by lib/graphql/client.rb needs to have the context argument, or there needs to be a way to set it dynamically when the class gets initialized.

If there isn't currently a way to pass headers through the parse method, I'm going to have to write a wrapper that functions a bit differently from the one in the readme.

@ericyd
Copy link

ericyd commented Aug 1, 2019

You can set up your client to accept headers like this

HTTP = GraphQL::Client::HTTP.new(url) do
  def headers(context)
    token = context[:access_token]
    {
      "Authorization": "token #{token}",
      "Accept-Encoding": "gzip"
    }
  end
end
SCHEMA = GraphQL::Client.load_schema(HTTP)
CLIENT = GraphQL::Client.new(schema: SCHEMA, execute: HTTP)

We do this for all our authenticated APIs and it works great. Let me know if that doesn't answer your question though, I might be misunderstanding.

@ericyd
Copy link

ericyd commented Aug 1, 2019

Of course, I just saw an identical answer on #192 which you referenced 😂 sorry about that. I don't think I'm understanding the issue

@wandy-dev wandy-dev changed the title Dynamically set headers in the when calling Client#parse Dynamically set headers when calling Client#parse Aug 5, 2019
@wandy-dev
Copy link
Author

wandy-dev commented Aug 5, 2019

Yeah this is definitely a weird one. I think it's related to how the ruby object model loads classes/modules, but I'm not sure about that.

I'll throw up a server with steps to reproduce. It seems like a simple config memoization will do the trick.

Thanks for getting back to me on this one.

@wandy-dev
Copy link
Author

wandy-dev commented Sep 19, 2019

@ericyd So maybe "throwing up a server" was a little ambitious on my part. So I'll just copy the errors I'm getting.

[1] pry(main)> require "graphql/client"
=> false
[2] pry(main)> require "graphql/client/http"
=> true
[3] pry(main)> module GROUNDFLOOR_GRAPHQL
[3] pry(main)*   API_URL = "#{ENV['GF_API_URL']}graphql_api/v1"
[3] pry(main)*
[3] pry(main)*   HTTP = GraphQL::Client::HTTP.new(API_URL) do
[3] pry(main)*     def headers(context)
[3] pry(main)*       jwt = context[:jwt]
[3] pry(main)*       {
[3] pry(main)*       "Authorization": "Bearer #{jwt}",
[3] pry(main)*       'Content-Type': 'application/vnd.api+json',
[3] pry(main)*       'Accept': 'application/vnd.api+json'
[3] pry(main)*       }
[3] pry(main)*     end
[3] pry(main)*   end
[3] pry(main)*   SCHEMA = GraphQL::Client.load_schema(HTTP)
[3] pry(main)*   CLIENT = GraphQL::Client.new(schema: SCHEMA, execute: HTTP)
[3] pry(main)* end
D, [2019-09-19T10:20:00.176360 #14035] DEBUG -- : [httplog] Connecting: localhost:5000
D, [2019-09-19T10:20:00.183468 #14035] DEBUG -- : [httplog] Sending: POST http://localhost:5000/graphql_api/v1
D, [2019-09-19T10:20:00.183544 #14035] DEBUG -- : [httplog] Header: accept-encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
D, [2019-09-19T10:20:00.183597 #14035] DEBUG -- : [httplog] Header: accept: application/json
D, [2019-09-19T10:20:00.183651 #14035] DEBUG -- : [httplog] Header: user-agent: Ruby
D, [2019-09-19T10:20:00.183707 #14035] DEBUG -- : [httplog] Header: content-type: application/json
D, [2019-09-19T10:20:00.183764 #14035] DEBUG -- : [httplog] Header: authorization: Bearer
D, [2019-09-19T10:20:00.183820 #14035] DEBUG -- : [httplog] Header: content-type: application/vnd.api+json
D, [2019-09-19T10:20:00.183913 #14035] DEBUG -- : [httplog] Header: accept: application/vnd.api+json
D, [2019-09-19T10:20:00.183968 #14035] DEBUG -- : [httplog] Header: connection: close
D, [2019-09-19T10:20:00.184021 #14035] DEBUG -- : [httplog] Header: host: localhost:5000
D, [2019-09-19T10:20:00.184071 #14035] DEBUG -- : [httplog] Header: content-length: 1451
D, [2019-09-19T10:20:00.184155 #14035] DEBUG -- : [httplog] Data: {"query":"query IntrospectionQuery {\n  __schema {\n    queryType {\n      name\n    }\n    mutationType {\n      name\n    }\n    subscriptionType {\n      name\n    }\n    types {\n      ...FullType\n    }\n    directives {\n      name\n      description\n      locations\n      args {\n        ...InputValue\n      }\n    }\n  }\n}\n\nfragment FullType on __Type {\n  kind\n  name\n  description\n  fields(includeDeprecated: true) {\n    name\n    description\n    args {\n      ...InputValue\n    }\n    type {\n      ...TypeRef\n    }\n    isDeprecated\n    deprecationReason\n  }\n  inputFields {\n    ...InputValue\n  }\n  interfaces {\n    ...TypeRef\n  }\n  enumValues(includeDeprecated: true) {\n    name\n    description\n    isDeprecated\n    deprecationReason\n  }\n  possibleTypes {\n    ...TypeRef\n  }\n}\n\nfragment InputValue on __InputValue {\n  name\n  description\n  type {\n    ...TypeRef\n  }\n  defaultValue\n}\n\nfragment TypeRef on __Type {\n  kind\n  name\n
ofType {\n    kind\n    name\n    ofType {\n      kind\n      name\n      ofType {\n        kind\n        name\n        ofType {\n          kind\n          name\n          ofType {\n            kind\n            name\n            ofType {\n              kind\n
           name\n              ofType {\n                kind\n                name\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n}","operationName":"IntrospectionQuery"}
D, [2019-09-19T10:20:00.184232 #14035] DEBUG -- : [httplog] Status: 401
D, [2019-09-19T10:20:00.184311 #14035] DEBUG -- : [httplog] Benchmark: 0.00584 seconds
D, [2019-09-19T10:20:00.184370 #14035] DEBUG -- : [httplog] Header: content-type: application/vnd.api+json
D, [2019-09-19T10:20:00.184424 #14035] DEBUG -- : [httplog] Header: access-control-allow-origin: http://localhost:3000
D, [2019-09-19T10:20:00.184477 #14035] DEBUG -- : [httplog] Header: connection: close
D, [2019-09-19T10:20:00.184529 #14035] DEBUG -- : [httplog] Header: content-length: 69
D, [2019-09-19T10:20:00.184616 #14035] DEBUG -- : [httplog] Response:
{"errors":[{"status":"401","detail":"Invalid authorization header"}]}
KeyError: key not found: "data"
from /home/andy/Repos/webdev/groundfloor_rails/vendor/bundle/ruby/2.4.0/gems/graphql-1.9.12/lib/graphql/schema/loader.rb:16:in `fetch'

In order to retrieve the schema, I need to be able to pass a JWT at the initialization of the client. Also when defining queries using the client. The initialization query can't be preformed unless a jwt is passed.

Is there any way to fix this, or should I perhaps look at another gem?

@ericyd
Copy link

ericyd commented Sep 20, 2019

Thanks for the STR @wandy-dev , that makes the issue more clear.

I'll be honest, I'm not really a contributor to this repo, the author solved a problem for me so I was trying to address some low hanging fruit in the issues as a thank you.

My gut instinct on how to solve this is to load a static schema rather than populating it with an introspection query, which is what the load_schema method will do if its passed an instance of GraphQL::Client::HTTP.

An example of how to do this is shown in the README under Configuration: https://github.com/github/graphql-client#configuration
In short, you would change

SCHEMA = GraphQL::Client.load_schema(HTTP)

to

SCHEMA = GraphQL::Client.load_schema("path/to/schema.json")

I think your post demonstrates an interesting issue though and bears further investigation. I imagine there is a way to solve this but have not dived deep enough into the code to figure it out right now.

@msaspence
Copy link

msaspence commented Oct 16, 2019

Try:

GraphQL::Client.load_schema(GraphQL::Client.dump_schema(HTTP, nil, context: { access_token: token }))

@wandy-dev
Copy link
Author

wandy-dev commented Mar 25, 2021

So obviously this is no longer a priority for me. I'm no longer at the organization that I needed to raise this issue for.

If you would like to close it that's fine by me.

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

No branches or pull requests

3 participants