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

Discussion: New API for this package

Open robrichard opened this issue 5 years ago • 6 comments

I think the current API for this package is limiting in several use cases:

  • arguments
  • supporting the same field queried multiple times via aliases
  • fields queried on different inline fragment types (for interfaces and unions)

I'm opening up this issue to start a discussion on a new API to support these cases that is flexible enough to expand in the future. Please comment suggestions or any additional requirements that need to be supported.

robrichard avatar Mar 04 '19 17:03 robrichard

I tried working on a new API this last weekend. I haven't yet come up with a useful API that takes into account aliases, arguments, named fragments (derived from FragmentSpread and FragmentDefinition), inline fragments, interfaces, unions, and sub-fields of objects or lists of objects.

One attempt used aliases as keys of an object. Unfortunately, I didn't find this too useful on the server-side since the server isn't going to know what aliases the client will be sending. I still have to traverse the tree to find the field information. When I am trying to identify the columns (aka projections) and associated data models to include, I don't care much about the alias.

I can post some of the structures here if it helps. I am hesitant to do it here because it may just obscure this discussion. Maybe we can post them in a Gist or something.

After a lot of trial-and-error, each field in the tree can have four pieces of information for each alias/type pair that could potentially be associated. The four pieces are the alias, args, the interface or concrete type of the containing object, and sub-fields for object or list fields.

I can provide some concrete examples for the above. Let me know if you would like them posted here.

dhurlburtusa avatar Mar 04 '19 18:03 dhurlburtusa

I think we're mostly on the same page. I think we need a structured class object with methods to access selections as iterables.

I don't think we should expose the alias used by the client, since that should not change what results the GraphQL server returns, but we do need to make sure that all selections and args are available.


query {
    pet(id: "foo") {
        fullName: name(type: "full")
        name
        ... on Cat {
            breed
        }
        ... on Dog {
            breed
            group
        }
    }
}


const field = new GraphQLField(info); // info from pet resolver

field.hasSelection('name') // true
field.hasSelection('fullName') // false, aliases don't count

const nameSelections = field.getSelections('name') // returns `GraphQLField`s for `name` and `fullName` selection

// field.getSelections() is an iterable of GraphQLField objects
for (const selection of field.getSelections()) {
    console.log(selection.name, selection.type);

    // selection.getArgs() is an iterable
    for (const arg of selection.getArgs()) {
        console.log('args:', arg.name, arg.value);
    }
}

/* logs

name, Pet
args: type, full
name, Pet
breed, Cat
breed, Dog
group, Dog

*/

This is just a really rough draft that I haven't put a ton of thought into. We'll need to find a balance between being easy to use and exposing all of the necessary data.

robrichard avatar Mar 04 '19 19:03 robrichard

That is along the lines of what I have started. I have a class, GraphQlResolveInfoInspector, where you can pass in the resolveInfo into the constructor. I have a method named isSelected that takes a dot separated or an array of field names. I'll need to update it to return an iterable of some type of object such as the GraphQlFields. I have a couple other methods but I am not sure if they'll be useful.

dhurlburtusa avatar Mar 05 '19 00:03 dhurlburtusa

FWIW here are a few things I've encountered that don't work with the arguments feature:

  • arguments sent as variables my_query(search: $search)
  • arguments of type object my_query(params: { a: 1 })
  • default argument values (defined in schema) input my_input { size: Int = 1 }

dan-kwiat avatar Mar 14 '19 14:03 dan-kwiat

graphql-parse-resolve-info seems to support aliased fields.

dandv avatar Jan 22 '20 22:01 dandv

graphql-parse-resolve-info looks like it solves all the issues mentioned in the original post. I recommend using that going forward.

robrichard avatar Jan 22 '20 22:01 robrichard