Graphql::Client::Dynamicqueryerror Expected Definition to Be Assigned to a Static Constant

Dynamic constant assignment when using Graphql for Shopify API

And here is the solution. Super hard to believe this is a "new" way of accessing data via an API. Its slower, more complicated and much more verbose. I don't get the benefit at all.

  def run_first_query
query = <<-'GRAPHQL'
query($first: Int){
products(first: $first) {
pageInfo {
hasNextPage
}
edges {
cursor
node {
id
title
featuredImage {
originalSrc
}
}
}
}
}
GRAPHQL
first = {
"first": number_of_products_to_return,
}
Kernel.const_set(:ProductQuery, graphql_client.parse(query))
@query_result = graphql_client.query(ProductQuery, variables: first)
end

Dynamic constant assignment

Your problem is that each time you run the method you are assigning a new value to the constant. This is not allowed, as it makes the constant non-constant; even though the contents of the string are the same (for the moment, anyhow), the actual string object itself is different each time the method is called. For example:

def foo
p "bar".object_id
end

foo #=> 15779172
foo #=> 15779112

Perhaps if you explained your use case—why you want to change the value of a constant in a method—we could help you with a better implementation.

Perhaps you'd rather have an instance variable on the class?

class MyClass
class << self
attr_accessor :my_constant
end
def my_method
self.class.my_constant = "blah"
end
end

p MyClass.my_constant #=> nil
MyClass.new.my_method

p MyClass.my_constant #=> "blah"

If you really want to change the value of a constant in a method, and your constant is a String or an Array, you can 'cheat' and use the #replace method to cause the object to take on a new value without actually changing the object:

class MyClass
BAR = "blah"

def cheat(new_bar)
BAR.replace new_bar
end
end

p MyClass::BAR #=> "blah"
MyClass.new.cheat "whee"
p MyClass::BAR #=> "whee"

GraphQL ObjectType with dynamic fields based on arguments

Neither option is really viable:

  1. GraphQL is strongly typed. GraphQL.js doesn't support some kind of any field, and all types defined in your schema must have fields defined. If you look in the docs, fields is a required -- if you try to leave it out, you'll hit an error.

  2. Args are used to resolve queries on a per-request basis. There's no way you can pass them back to your schema. You schema is supposed to be static.

As you suggest, it's possible to accomplish what you're trying to do by rolling your own customer Scalar. I think a simpler solution would be to just use JSON -- you can import a custom scalar for it like this one. Then just have your elements field resolve to a JSON object or array containing the dynamic fields. You could also manipulate the JSON object inside the resolver based on arguments if necessary (if you wanted to limit the fields returned to a subset as defined in the args, for example).

Word of warning: The issue with utilizing JSON, or any custom scalar that includes nested data, is that you're limiting the client's flexibility in requesting what it actually needs. It also results in less helpful errors on the client side -- I'd much rather be told that the field I requested doesn't exist or returned null when I make the request than to find out later down the line the JSON blob I got didn't include a field I expected it to.



Related Topics



Leave a reply



Submit