Graphql-ruby: KeyError: key not found: "data"

Created on 12 Nov 2018  路  6Comments  路  Source: rmosolgo/graphql-ruby

I am trying to access an internal graphQL schema bet kept hitting the error above. So, I tried accessing the free SWAPI API just to be sure I was implementing the client properly. I am still getting these errors however:

KeyError: key not found: "data" from /Users/me/.rvm/gems/ruby-2.4.0/gems/graphql-1.8.11/lib/graphql/schema/loader.rb:16:infetch'`

And my client implementation:

module YetiAPI

  HttpAdapter = GraphQL::Client::HTTP.new("http://graphql.org/swapi-graphql/") do
    def headers(context)
      {
        "User-Agent" => "Ruby"
      }
    end
  end

  Schema = GraphQL::Client.load_schema(HttpAdapter)
  Client = GraphQL::Client.new(schema: Schema, execute: HttpAdapter)
end

I'm not sure if there is something I'm doing wrong, though I was previously access these APIs with a similar setup just fine (a couple months ago).

Gemfile.lock

```GEM
remote: https://rubygems.org/
specs:
activesupport (5.2.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
coderay (1.1.2)
concurrent-ruby (1.1.3)
diff-lcs (1.3)
graphql (1.8.11)
graphql-client (0.14.0)
activesupport (>= 3.0, < 6.0)
graphql (~> 1.6)
httparty (0.16.2)
multi_xml (>= 0.5.2)
i18n (1.1.1)
concurrent-ruby (~> 1.0)
method_source (0.9.1)
mini_portile2 (2.3.0)
minitest (5.11.3)
multi_xml (0.6.0)
nokogiri (1.8.5)
mini_portile2 (~> 2.3.0)
pry (0.12.0)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
rspec (3.2.0)
rspec-core (~> 3.2.0)
rspec-expectations (~> 3.2.0)
rspec-mocks (~> 3.2.0)
rspec-core (3.2.3)
rspec-support (~> 3.2.0)
rspec-expectations (3.2.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.2.0)
rspec-mocks (3.2.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.2.0)
rspec-support (3.2.2)
thread_safe (0.3.6)
tzinfo (1.2.5)
thread_safe (~> 0.1)

PLATFORMS
ruby

DEPENDENCIES
graphql-client
httparty (~> 0.16.2)
nokogiri (~> 1.8.3)
pry
rspec (~> 3.2.0)

BUNDLED WITH
1.16.1```

Most helpful comment

OK, I found the problem. When inspecting the instrospection_result, I am getting:

{"errors"=>[{"message"=>"403 Forbidden"}]}

Basically, the problem is the Authorization headers I require, have a key that is dynamically created based on a Secret key and some JS hashing functions (crypto.js). It ends up looking like this:

AUTH_HEADER = "HMAC-SHA256, Credential=#{ACCESS_KEY}, SingedHeaders=host;x-date, Signature=#{HMAC_DIGEST}"

HMAC_DIGEST is the one dynamically created.

I use it within the initialization as such:

```module MY_API
include HTTParty

URI = "my_api_uri"

ACCESS_KEY = "EEGHMT247LYTLL2AS4F6YKV3HI8STF8KIS52W09ZRY3YZEWV"
HMAC_DIGEST = "185aa2c0edb953342be683958de0b937afc4cb0073c46d35185a6cc97b8b5d49"

AUTH_HEADER = "HMAC-SHA256, Credential=#{ACCESS_KEY}, SingedHeaders=host;x-date, Signature=#{HMAC_DIGEST}"
REQUEST_TIME = Time.new

HttpAdapter = GraphQL::Client::HTTP.new(URI) do

def headers(context)

  {
    "Content-Type": "application/json",
    "Authorization": AUTH_HEADER,
    "X-Date": REQUEST_TIME

  }
end

end

Schema = GraphQL::Client.load_schema(HttpAdapter)
Client = GraphQL::Client.new(schema: Schema, execute: HttpAdapter)
end
```

I think I am going to have to create helper functions that hash the secret key and store within the module, or look for alternative solution since I do know how to do this with JS.

I'm going to close this issue probably. Thank you @rmosolgo for all the guidance!

All 6 comments

same problem

It sounds like it's getting an error response from SWAPI, in that case there's no data field. Can you see the response from SWAPI?

Not from SWAPI specifically. I'm just using it so I don't expose private endpoints etc. But, if you go to the https://graphql.org/swapi-graphql/ client, you can test out the API data, and they are giving back a response.

Here is a testing query that currently gives me JSON response.

``query allPlanets { allPlanets { planets { name terrains id gravity } } }

Yet, using the gem no longer sees the data. Let me know if there's any more debugging I can do on my own

I recommend:

  • Adding pry to your gemfile, or gem install pry if you aren't using a Gemfile
  • Using bundle open graphql to open GraphQL-Ruby's source
  • Finding the line where this error is raised inside graphql-ruby

    • Adding a binding.pry right _before_ the line where the error is raised

  • Trigger the error somehow
  • When the binding.pry call opens a debugger, inspect the hash where .fetch("data") is called
  • Inspect the "errors" key of that hash: it's probably populated with some kind of an error

The real _fix_ would probably be to add some error handling to graphql-client or graphql-ruby, but for some quick debugging, that might get you unstuck! Feel free to share what you find.

@rmosolgo So, this is the full error when running from RSpec:

/Users/EdwardMcCarthy/.rvm/gems/ruby-2.4.0/gems/graphql-1.8.11/lib/graphql/schema/loader.rb:16:in `fetch': key not found: "data" (KeyError) from /Users/EdwardMcCarthy/.rvm/gems/ruby-2.4.0/gems/graphql-1.8.11/lib/graphql/schema/loader.rb:16:in `load' from /Users/EdwardMcCarthy/.rvm/gems/ruby-2.4.0/gems/graphql-client-0.14.0/lib/graphql/client.rb:52:in `load_schema' from /Users/EdwardMcCarthy/.rvm/gems/ruby-2.4.0/gems/graphql-client-0.14.0/lib/graphql/client.rb:61:in `load_schema'

Let me try what you suggested above. Apologies for the delay in response

OK, I found the problem. When inspecting the instrospection_result, I am getting:

{"errors"=>[{"message"=>"403 Forbidden"}]}

Basically, the problem is the Authorization headers I require, have a key that is dynamically created based on a Secret key and some JS hashing functions (crypto.js). It ends up looking like this:

AUTH_HEADER = "HMAC-SHA256, Credential=#{ACCESS_KEY}, SingedHeaders=host;x-date, Signature=#{HMAC_DIGEST}"

HMAC_DIGEST is the one dynamically created.

I use it within the initialization as such:

```module MY_API
include HTTParty

URI = "my_api_uri"

ACCESS_KEY = "EEGHMT247LYTLL2AS4F6YKV3HI8STF8KIS52W09ZRY3YZEWV"
HMAC_DIGEST = "185aa2c0edb953342be683958de0b937afc4cb0073c46d35185a6cc97b8b5d49"

AUTH_HEADER = "HMAC-SHA256, Credential=#{ACCESS_KEY}, SingedHeaders=host;x-date, Signature=#{HMAC_DIGEST}"
REQUEST_TIME = Time.new

HttpAdapter = GraphQL::Client::HTTP.new(URI) do

def headers(context)

  {
    "Content-Type": "application/json",
    "Authorization": AUTH_HEADER,
    "X-Date": REQUEST_TIME

  }
end

end

Schema = GraphQL::Client.load_schema(HttpAdapter)
Client = GraphQL::Client.new(schema: Schema, execute: HttpAdapter)
end
```

I think I am going to have to create helper functions that hash the secret key and store within the module, or look for alternative solution since I do know how to do this with JS.

I'm going to close this issue probably. Thank you @rmosolgo for all the guidance!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rmosolgo picture rmosolgo  路  4Comments

theodorton picture theodorton  路  3Comments

gastonmorixe picture gastonmorixe  路  3Comments

jturkel picture jturkel  路  3Comments

jtippett picture jtippett  路  3Comments