profile
viewpoint
Myron Marston myronmarston @square Seattle, WA myronmars.to/n

bblimke/webmock 3347

Library for stubbing and setting expectations on HTTP requests in Ruby.

bendyworks/caravan 43

Example app using Interpol

kylejginavan/factory_data_preloader 33

Preload data created by factory girl (or any other Rails fixtures alternative) so that you can use Rails' built-in test transactions.

myronmarston/email_blacklist 6

Blacklist particular email addresses so ActionMailer doesn't deliver emails to them.

myronmarston/clickatell 2

Ruby interface to the Clickatell SMS Gateway API

myronmarston/column_timestamps 2

Keeps track of when a specific column in an ActiveRecord model changed.

myronmarston/CSharpInterviewPractice 2

Just some practice coding problems for an upcoming interview

cohitre/pollo 1

The Ultimate Polling Engine

myronmarston/addressable 1

Addressable is a replacement for the URI implementation that is part of Ruby's standard library. It more closely conforms to the relevant RFCs and adds support for IRIs and URI templates.

myronmarston/algorithms 1

Just some algorithm implementations

issue commentrmosolgo/graphql-ruby

`GraphQL::TypeKinds::ENUM.scalar?` oddly returns `false`

Another possible idea is scalar_like?

myronmarston

comment created time in a month

issue commentrmosolgo/graphql-ruby

`GraphQL::TypeKinds::ENUM.scalar?` oddly returns `false`

It's unfortunate that the spec is kinda ambiguous about whether enums are type of scalar, or just a type that is scalar-like.

Anyhow, we've worked around this issue in our code base (we're just checking scalar? || enum?). I'm not sure if we'd use .leaf? or not but it sounds like a good solution if you want to add it.

myronmarston

comment created time in a month

issue openedrmosolgo/graphql-ruby

`GraphQL::TypeKinds::ENUM.scalar?` oddly returns `false`

Is your feature request related to a problem? Please describe.

I was surprised to see that GraphQL::TypeKinds::ENUM.scalar? returns false when I expected it to return true. While this is probably intentional, it feels like a bug to me because my understanding of the GraphQL type system is that enums are a kind of scalar type. For example, here's the wording from the GraphQL spec in the scalar section:

Scalar types represent primitive leaf values in a GraphQL type system. GraphQL responses take the form of a hierarchical tree; the leaves on these trees are GraphQL scalars.

It doesn't say "some leaves on these trees are GraphQL scalars" or "most leaves on these trees are GraphQL scalars". It says "The leaves on these trees are GraphQL scalars" which implies (to me, at least) that every leaf type is a scalar type, and enums are a leaf type.

Apart from the GraphQL spec, my informal understanding of "scalar" in a type system is that any type that is an individual value (as opposed to some kind of collection of values, such as a list, map, set, or tuple) is a scalar, so it was quite surprising to me to see that graphql gem considers enums to not be scalars.

Describe the solution you'd like

Ideally GraphQL::TypeKinds::ENUM.scalar? would return true.

Describe alternatives you've considered

I understand there are repercussions to changing this, as clients may currently be using scalar? to distinguish "normal" scalar types from enums. If we get agreement on my suggested change I'm happy to submit a PR making the change.

created time in a month

issue closedrmosolgo/graphql-ruby

Regression in GraphQL 1.10: no way to get access to query args in their original form

Describe the bug

We've built an indexing and search framework on top of graphql-ruby that operates on GraphQL schemas generically, by translating a GraphQL query to an elastic search query to query our indexed data. The framework is designed to work with either camelCase schemas or snake_case schemas (really, it doesn't care; as long as the user of the framework uses the same casing for a field in their GraphQL schema and their ElasticSearch JSON field schema, it'll "just work" without us having to think about it). This all worked great with graphql-1.9, but I've been trying to upgrade to graphql-1.10 and I'm running into problems. Specifically, graphql-1.10 coerces all inputs to ruby keyword-style syntax (e.g. symbols keys instead of strings, snake_case over camelCase, etc). This is causing us a problem because when we get a user of our framework is using a camelCase schema (as most GraphQL schemas are...) our framework is now receiving the field name in snake_case instead of camelCase, which causes the ElasticSearch query to fail to match anything. I've spent a few hours trying to figure out an alternate way to get the original argument hash in whatever casing it started in, and I haven't found a way that works.

I can understand why most users probably prefer getting the query arguments in ruby keyword style syntax, but for those of us who want the argument hash as it was provided in the query, it's frustrating not to have access to it anymore, and I haven't yet found a work around I'm satisfied with.

Can the graphql gem provide access to the original args hash as it was provided in 1.9 using an alternate method or something?

Versions

graphql version: worked as desired in all 1.9.x versions, fails to work as I need it to in 1.10.x

GraphQL schema

See my example script below.

GraphQL query

See my example script below.

Steps to reproduce

Put this script in a file like script/demo_args_coercion_issue.rb:

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem 'graphql', ENV.fetch('VERSION')
end

require 'graphql'
require 'pp'

schema_string = <<~SCHEMA
  input IdFilter {
    anyOf: [ID!]!
  }

  input IntFilter {
    anyOf: [Int!]
    gt: Int
    gte: Int
    lt: Int
    lte: Int
  }

  type Widget {
    id: ID!
    amountCents: Int!
    name: String!
  }

  input WidgetFilter {
    id: IdFilter
    amountCents: IntFilter
  }

  type Query {
    widgets(filter: WidgetFilter): [Widget!]!
  }
SCHEMA

schema = GraphQL::Schema.from_definition(schema_string, default_resolve: -> (parent_type, field, object, args, context) {
  puts "Got :filter arguments: #{args[:filter].to_h.inspect}"
  puts "Got 'filter' arguments: #{args["filter"].to_h.inspect}"
})

query = <<~QUERY
  query {
    widgets(filter: {amountCents: {gt: 100}}) {
      id
    }
  }
QUERY

schema.execute(query)

Then you can run it with VERSION=1.9.19 ruby script/demo_args_coercion_issue.rb and VERSION=1.10.6 ruby script/demo_args_coercion_issue.rb to compare the behavior.

Expected behavior

I expect to continue to get the args in the casing defined by my schema (camelCase, in this example case).

Actual behavior

graphql-1.10.x presents the field name from my query as amount_cents instead of amountCents.

Additional context

Example output from my script above:

$ VERSION=1.9.19 ruby script/demo_args_coercion_issue.rb
Got :filter arguments {"amountCents"=>{"gt"=>100}}
Got 'filter' arguments {"amountCents"=>{"gt"=>100}}
$ VERSION=1.10.6 ruby script/demo_args_coercion_issue.rb
Got :filter arguments: {:amount_cents=>{:gt=>100}}
Got 'filter' arguments: {}

As you can see, on 1.9.x, I could access the arguments with string or symbol keys, and it preserved the casing of amountCents; in 1.10.x, I can only access the arguments using symbol keys, and it converts amountCents to amount_cents, which breaks my logic with no clear work around since my framework doesn't know what the "original" casing of that element in the schema was. (The symbol vs string access doesn't matter to me much compared to the casing issue).

closed time in 2 months

myronmarston

issue commentrmosolgo/graphql-ruby

Regression in GraphQL 1.10: no way to get access to query args in their original form

I've implemented a solution like what @rmosolgo posted above in our codebase, and it's working well, so I'm going to close this issue.

myronmarston

comment created time in 2 months

issue commentrmosolgo/graphql-ruby

Regression in GraphQL 1.10: no way to get access to query args in their original form

Ah, I didn't read the code in detail to see that it uses the arg_defn.name to convert back to the original casing. So yes, that should work! Thanks for writing it up and tolerating my questions :).

Does the code you wrote use any non-public APIs (public in the SemVer sense not public in the ruby public vs private sense)? Would it make sense for the graphql gem to expose a method I could delegate to to do the conversion?

If you think it makes sense to provide a public API to do this conversion, I can contribute that if you'll recommend where it should go and what you'd like it to be called :).

myronmarston

comment created time in 3 months

issue commentrmosolgo/graphql-ruby

Regression in GraphQL 1.10: no way to get access to query args in their original form

I have a work around like that already in place, but it doesn't work in all cases. The users of my framework aren't required to exclusively use camelCase names for everything and there times when it makes sense to insert an underscore to separate two separate parts of one field name, such as when you've denormalized a field from some parent object (e.g. legalEntity_firstName for the firstName field of the legalEntity being denormalized onto an account type).

Ideally I'd be able to get the query arguments in the casing defined in the schema (and passed in the query)...

myronmarston

comment created time in 3 months

issue commentrmosolgo/graphql-ruby

Regression in GraphQL 1.10: no way to get access to query args in their original form

Your example uses Schema.from_definition -- do you need a solution that support .from_definition, or is that just an example?

Our project only uses from_definition, so I absolutely need this to work with from_definition.

(I ask because it's much harder to customize schemas built from definition 😅 .)

What do you mean by "customize schemas"? FWIW we use lots of custom directives to configure how our framework treats the schema...

myronmarston

comment created time in 3 months

issue openedrmosolgo/graphql-ruby

Regression in GraphQL 1.10: no way to get access to query args in their original form

Describe the bug

We've built an indexing and search framework on top of graphql-ruby that operates on GraphQL schemas generically, by translating a GraphQL query to an elastic search query to query our indexed data. The framework is designed to work with either camelCase schemas or snake_case schemas (really, it doesn't care; as long as the user of the framework uses the same casing for a field in their GraphQL schema and their ElasticSearch JSON field schema, it'll "just work" without us having to think about it). This all worked great with graphql-1.9, but I've been trying to upgrade to graphql-1.10 and I'm running into problems. Specifically, graphql-1.10 coerces all inputs to ruby keyword-style syntax (e.g. symbols keys instead of strings, snake_case over camelCase, etc). This is causing us a problem because when we get a user of our framework is using a camelCase schema (as most GraphQL schemas are...) our framework is now receiving the field name in snake_case instead of camelCase, which causes the ElasticSearch query to fail to match anything. I've spent a few hours trying to figure out an alternate way to get the original argument hash in whatever casing it started in, and I haven't found a way that works.

I can understand why most users probably prefer getting the query arguments in ruby keyword style syntax, but for those of us who want the argument hash as it was provided in the query, it's frustrating not to have access to it anymore, and I haven't yet found a work around I'm satisfied with.

Can the graphql gem provide access to the original args hash as it was provided in 1.9 using an alternate method or something?

Versions

graphql version: worked as desired in all 1.9.x versions, fails to work as I need it to in 1.10.x

GraphQL schema

See my example script below.

GraphQL query

See my example script below.

Steps to reproduce

Put this script in a file like script/demo_args_coercion_issue.rb:

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem 'graphql', ENV.fetch('VERSION')
end

require 'graphql'
require 'pp'

schema_string = <<~SCHEMA
  input IdFilter {
    anyOf: [ID!]!
  }

  input IntFilter {
    anyOf: [Int!]
    gt: Int
    gte: Int
    lt: Int
    lte: Int
  }

  type Widget {
    id: ID!
    amountCents: Int!
    name: String!
  }

  input WidgetFilter {
    id: IdFilter
    amountCents: IntFilter
  }

  type Query {
    widgets(filter: WidgetFilter): [Widget!]!
  }
SCHEMA

schema = GraphQL::Schema.from_definition(schema_string, default_resolve: -> (parent_type, field, object, args, context) {
  puts "Got :filter arguments: #{args[:filter].to_h.inspect}"
  puts "Got 'filter' arguments: #{args["filter"].to_h.inspect}"
})

query = <<~QUERY
  query {
    widgets(filter: {amountCents: {gt: 100}}) {
      id
    }
  }
QUERY

schema.execute(query)

Then you can run it with VERSION=1.9.19 ruby script/demo_args_coercion_issue.rb and VERSION=1.10.6 ruby script/demo_args_coercion_issue.rb to compare the behavior.

Expected behavior

I expect to continue to get the args in the casing defined by my schema (camelCase, in this example case).

Actual behavior

graphql-1.10.x presents the field name from my query as amount_cents instead of amountCents.

Additional context

Example output from my script above:

$ VERSION=1.9.19 ruby script/demo_args_coercion_issue.rb
Got :filter arguments {"amountCents"=>{"gt"=>100}}
Got 'filter' arguments {"amountCents"=>{"gt"=>100}}
$ VERSION=1.10.6 ruby script/demo_args_coercion_issue.rb
Got :filter arguments: {:amount_cents=>{:gt=>100}}
Got 'filter' arguments: {}

As you can see, on 1.9.x, I could access the arguments with string or symbol keys, and it preserved the casing of amountCents; in 1.10.x, I can only access the arguments using symbol keys, and it converts amountCents to amount_cents, which breaks my logic with no clear work around since my framework doesn't know what the "original" casing of that element in the schema was. (The symbol vs string access doesn't matter to me much compared to the casing issue).

created time in 3 months

more