Git Product home page Git Product logo

graphql-java's Introduction

GraphQL Java

Discuss and ask questions in our Discussions: https://github.com/graphql-java/graphql-java/discussions

This is a GraphQL Java implementation.

Latest build in Maven central: https://repo1.maven.org/maven2/com/graphql-java/graphql-java/

Build Latest Release Latest Snapshot MIT licensed

Documentation

The GraphQL Java book, from the maintainers: GraphQL with Java and Spring

See our tutorial for beginners: Getting started with GraphQL Java and Spring Boot

For further details, please see the documentation: https://www.graphql-java.com/documentation/getting-started

If you're looking to learn more, we (the maintainers) have written a book! GraphQL with Java and Spring includes everything you need to know to build a production ready GraphQL service. The book is available on Leanpub and Amazon.

Please take a look at our list of releases if you want to learn more about new releases and the changelog.

Code of Conduct

Please note that this project is released with a Contributor Code of Conduct. By contributing to this project (commenting or opening PR/Issues etc) you are agreeing to follow this conduct, so please take the time to read it.

License

Copyright (c) 2015, Andreas Marek and Contributors

Supported by

YourKit

YourKit supports this project by providing the YourKit Java Profiler.

graphql-java's People

Contributors

andimarek avatar bbakerman avatar danielkwinsor avatar dependabot[bot] avatar dfa1 avatar dh94 avatar dminkovsky avatar dondonz avatar dugenkui03 avatar exbe avatar felipe-gdr avatar felipe-gdr-atlassian avatar fkorotkov avatar gkesler avatar gnawf avatar grrttedwards avatar guidorota avatar jbellenger avatar jord1e avatar juliano-prado avatar kaqqao avatar kilink avatar larskrogjensen avatar markphilpot avatar mrdon-atlassian avatar osi avatar russellyou avatar rusticflare avatar simeonleatherland avatar tinnou avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphql-java's Issues

DataFetcher isn't invoked on nested objects

Given schema

    public static GraphQLObjectType PersonType = newObject()
            .name("PersonType")
            .field(newFieldDefinition()
                    .name("id")
                    .type(GraphQLString)
                    .build())
            .field(newFieldDefinition()
                    .name("firstName")
                    .type(GraphQLString)
                    .build())
            .field(newFieldDefinition()
                    .name("email")
                    .type(GraphQLString)
                    .build())
            .build();

    private static GraphQLObjectType ProfileType = newObject()
            .name("Profile")
            .field(
                    newFieldDefinition()
                            .name("person")
                            .argument(newArgument().name("id").type(GraphQLID).build())
                            .type(PersonType)
                            .dataFetcher(new DataFetcher() {
                                @Override
                                public Object get(DataFetchingEnvironment environment) {
                                    Person person1 = new Person();
                                    person1.setFirstName("one name");
                                    return person1;
                                }
                            })
                            .build()
            )
            .field(
                    newFieldDefinition()
                            .name("people")
                            .argument(newArgument().name("firstName").type(GraphQLString).build())
                            .argument(newArgument().name("offset").type(GraphQLInt).build())
                            .argument(newArgument().name("limit").type(GraphQLInt).build())
                            .type(new GraphQLList(PersonType))
                            .dataFetcher(new DataFetcher() {
                                @Override
                                public Object get(DataFetchingEnvironment environment) {
                                    Person person1 = new Person();
                                    person1.setFirstName("one name");

                                    Person person2 = new Person();
                                    person2.setFirstName("two name");
                                    return Lists.newArrayList(person1, person2);
                                }
                            })
                            .build()
            )
            .build();

    private static GraphQLObjectType RootType = newObject()
            .name("Query")
            .field(
                    newFieldDefinition()
                            .name("profiles")
                            .type(ProfileType)
                            .build()
            )
            .build();

    public static GraphQLSchema graphQLSchema = GraphQLSchema.newSchema()
            .query(RootType)
            .build();

passing the next query

{
  profiles {
      people(fistName:"Superman", offset:10, limit: 20){
            firstName
           email
      }
  }
}

produces

{"profiles":null}

and data fetcher isn't invoked.
Does anyone know why it doesn't work? Perhaps, wrong schema definition...

Union types always return undefined field error

When you execute a query against a union type, you always get a undefined field error.

For example executing against the GarfieldSchema:

ExecutionResult execute = new GraphQL(GarfieldSchema).execute("{pets {name}}");
System.out.println(execute.getData());
System.out.println(execute.getErrors());

gives

null
[ValidationError{validationErrorType=FieldUndefined, sourceLocations=[SourceLocation{line=1, column=8}], description='Field name is undefined'}]

directive

I am trying to use directive in the following code example but if raises error.

GraphQLObjectType d = newObject()
                .name("Data")
                .field(newFieldDefinition()
                        .name("ID")
                        .type(GraphQLFloat)
                        .build())
                        .field(newFieldDefinition()
                                .name("Name")
                                .type(GraphQLString)
                                .build())
                                .build();

        GraphQLObjectType pageObject = newObject()
                .name("Page")
                .field(newFieldDefinition()
                        .name("Data")
                        .type(d)
                        .argument(
                                GraphQLArgument.newArgument()
                                .name("ID")
                                .type(GraphQLFloat)
                                .build()
                                )
                                .argument(
                                        GraphQLArgument.newArgument()
                                        .name("Name")
                                        .type(GraphQLString)
                                        .build()
                                        )
                                        .dataFetcher(new DataFetcher() {
                                            @Override
                                            public Object get(DataFetchingEnvironment environment) {

                                                Map<String, Object> arguments = environment.getArguments();
                                                Float id = (Float) arguments.get("ID");
                                                String name = (String) arguments.get("Name");

                                                Map<String, Object> result = new HashMap<String, Object>();
                                                result.put("ID", id);
                                                result.put("Name", name);
                                                return result;
                                            }
                                        })
                                        .build()
                        )
                        .build();


        GraphQLObjectType query = newObject()
                .name("sample")
                .field(newFieldDefinition()
                        .name("Page")
                        .type(pageObject)
                        .staticValue(pageObject)
                        .build())
                        .build();

        GraphQLSchema schema = GraphQLSchema.newSchema()
                .query(query)
                .build();

        System.out.println("Schema: " + schema.toString());
        //@include(Name: \"my\")
        String input = "query sample ($id: Float = 1.0, $name: String, $condition: Boolean) "
                + "{ Page { Data (ID: $id, Name:$name)  { ID , Name @skip(if: $condition) } } }";

        Map<String, Object> arguments = new HashMap<String, Object>();
        arguments.put("id", "2");
        arguments.put("name", "myName");
        arguments.put("condition", false);
        ExecutionResult result = new GraphQL(schema).execute(input, new Object(), arguments );
ValidationError{validationErrorType=MissingDirectiveArgument, sourceLocations=[SourceLocation{line=1, column=105}], description='Missing directive argument skip'}
ValidationError{validationErrorType=UnknownArgument, sourceLocations=[SourceLocation{line=1, column=111}], description='Unknown argument if'}
ValidationError{validationErrorType=VariableTypeMismatch, sourceLocations=[SourceLocation{line=1, column=115}], description='Variable type doesn't match'}

would you please tell me what is the problem?

Javadoc

I really like using graphql, but I am really struggling with this implementation because there is so little javadoc. For example, how should I define my own types with coerce() and coerceLiteral() methods? I can only gather so much information from the code itself.

ConnectionCursor gets serialized into invalid value

When using the provided helpers for Relay, the ConnectionCursor gets serialized into an invalid value, as ConnectionCursor#toString() is used for serialization. This results that the first cursor is "ConnectionCursor{value='c2ltcGxlLWN1cnNvcjA='}" instead of c2ltcGxlLWN1cnNvcjA=

Null for optional boolean field on complex input value throws GraphqlException

In the latest commits there has been a code change here:

graphql.execution.ValuesResolver#coerceValueForInputObjectField

It used to return null when the input was null.

Suppose you have a complex input type object having a boolean field. The boolean field is optional and has a default value of false in the schema.
Sending a mutation with this complex input type object (as required by relay) always results in a exception. The coerce code does not accept any of the primitives to be null at this point (Long, Boolean,...)

When first starting to parse, it parses the main arguments in the mutation request with this logic:

if (inputValue == null && variableDefinition.getDefaultValue() != null) {
return coerceValueAst(type, variableDefinition.getDefaultValue(), null);
}
Which is present here: graphql.execution.ValuesResolver#getVariableValue

However when parsing input object fields other logic is used an no optional values are allowed. Is there any reason for this ? Seems to me the same logic applies there and it should take into account optional fields with default values.

dataFetcher on type?

Hi!

I've been trying out your graphql java implementation and I found that it's not possible to add a datafetcher on the type level.

Although I don't think it's part of the spec (it doesn't seem to define how to define datafetcher-like functionality), the javascript reference implementation supports .resolve() on both fields and types. Perhaps something to add in a next version?

GraphQlFloat single vs double precision

Hi Andi,

Reading the GraphQL spec it says:

The Float scalar type represents signed doubleโ€precision fractional values as specified by IEEE 754.

but according to scalars.GraphQLFloat it accepts single-precision floating point numbers.

Do you think the implementation needs to be updated.

Relay helper for connection and edge

The edgeType and connectionType functions in Relay.java don't accept a dataFetcher. Is the intent (or one of the intents) for the field on the entity containing the connection (returned from connectionType) to provide a dataFetcher that returns data with an "edges" field which then contains a list of items with a "node" field which contains the data?

I've been able to get things working this way but before I shape our real returned data I'd like to make sure this is the correct direction.

Thank you for creating and maintaining this library,

Kind Regards,
Mark

Javadoc Missing

It would not hurt having comments in the code. I am trying to read the code and am feeling a bit wobbly.

Thanks in advance for adding them!

Enum Value cannot be optional in mutation input object

When doing a relay-like mutation, Enums cannot be optional. Suppose you trigger the following mutation;

mutation ChangeFriend(\$input:ChangeFriendRequest) {
                changeFriend(input:\$input) {
                    clientMutationId
                }
            }

ChangeFriendRequest has following schema:

{
          "kind": "INPUT_OBJECT",
          "name": "ChangeAttributeTypeRequest",
          "description": null,
          "fields": null,
          "inputFields": [
            {
              "name": "clientMutationId",
              "description": null,
              "type": {
                "kind": "SCALAR",
                "name": "String",
                "ofType": null
              },
              "defaultValue": null
            },
            {
              "name": "kind",
              "description": null,
              "type": {
                "kind": "ENUM",
                "name": "AttributeKind",
                "ofType": null
              },
              "defaultValue": null
            }]
    }

If you don' send the enum value in the mutation input you get the following stacktrace:

java.lang.NullPointerException
    at graphql.schema.GraphQLEnumType.getValueByName(GraphQLEnumType.java:43)
    at graphql.schema.GraphQLEnumType.access$100(GraphQLEnumType.java:14)
    at graphql.schema.GraphQLEnumType$1.parseValue(GraphQLEnumType.java:28)
    at graphql.execution.ValuesResolver.coerceValueForEnum(ValuesResolver.java:96)
    at graphql.execution.ValuesResolver.coerceValue(ValuesResolver.java:70)
    at graphql.execution.ValuesResolver.coerceValueForInputObjectField(ValuesResolver.java:84)
    at graphql.execution.ValuesResolver.coerceValue(ValuesResolver.java:74)
    at graphql.execution.ValuesResolver.getVariableValue(ValuesResolver.java:59)
    at graphql.execution.ValuesResolver.getVariableValues(ValuesResolver.java:16)
    at graphql.execution.ExecutionContextBuilder.build(ExecutionContextBuilder.java:55)
    at graphql.execution.Execution.execute(Execution.java:32)
    at graphql.GraphQL.execute(GraphQL.java:78)
    at graphql.GraphQL.execute(GraphQL.java:55)

Using a Set Collection causes a Validation Error on mutation input

graphql.validation.Validator is producing the following error when the mutation argument is mapped to an object that contains a Set

private Set<String> ids;

Request Query
mutation a {
createThing (info: {ids: ["abc"]}) {
title
id
}
}

Response
{
"errors": [
{
"errorType": "QueryValidationError",
"msg": "Validation error of type WrongType: argument value ObjectValue{objectFields=[ObjectField{name='ids', value=ArrayValue{values=[StringValue{value='abc'}]}}]} has wrong type [SourceLocation{line=2, column=19}]"
}
]
}

It works if the argument mapped in the object contains a List instead, but that is not ideal since we'll have to perform a further conversion to remove duplicates. The GraphQL server should be able to accept any Collection type for a json list?

Probably more of a question than an issue. Since Set isn't ordered that might be the reason it's not possible?

NPE when input enum value does not exist

At GraphQLEnumType.java line 31

GraphQLEnumValueDefinition enumValueDefinition = valueDefinitionMap.get(enumValue.getName());

enumValueDefinition is null when input enum value does not exist.
And NPE is thrown in the following line.

if (enumValueDefinition.getValue() != null) return enumValueDefinition.getValue();

Asynchronous DataFetcher?

Please consider adding support of Future return type for DataFetcher API.
Actually scratched that. We just noticed it is possible to provide a custom executor service per fetcher. But it will still block for each fetcher.
Is it actually possible to go async all the way?

  1. Across all fetchers
  2. Make top level graphql execute() async as well.

How to pass List of string to query?

Please could provide info how to pass list of string to query?
No matter what I have tried, getting " description='Unknown type List'}]" error message.
Call is like this:
List ids = new LinkedList(); ids.add("22222"); args.put("id", ids);
and Query:
" query FetchIssuer($id: List) { user ( id:$id) { firstName, lastName, id } }"

Access object from "parent" data fetcher

Hi,

Thank you for this awesome lib : )

Having a schema like:

Dogs
  type(GraphQLList(DogType))
  dataFetcher(DogsDatafetcher)

DogType
  name
  breed (BreedDatafetcher)

Is there some nice way BreedDatafetcher could communicate with the DogsDatafetcher to get a DogObject retrieved there to provide the data?

What I did is return the DogObject alongside other data returned from DogsDatafetcher.
Then in BreedDatafetcher i would get the DogObject using:
DogObject dog = ((Map<String, DogObject>)(environment.getSource())).get("DOG_OBJECT")

{ dogs { name breed }}

GraphQLInputObject wrapped in GraphQLList not parsed correctly

For example:

@Component
public class SpaceInviteInputType implements TypeDefinition<GraphQLInputObjectType> {

    @Override
    public GraphQLInputObjectType getType( Schema schema ) {
        return GraphQLInputObjectType.newInputObject()
                .name( getName() )

                .field( newInputObjectField()
                        .name( "invitee" )
                        .type( new GraphQLNonNull( Scalars.GraphQLString ) )
                        .build() )

                .field( newInputObjectField()
                        .name( "rights" )
                        .type( new GraphQLList( Scalars.GraphQLString ) )
                        .build() )

                .build();
    }

}

And wrapping this in a GraphQLList is not parsed correctly.

                .argument( newArgument()
                        .name( "newRights" )
                        .type( new GraphQLList( schema.type( SpaceInviteInputType.class ) ) )
                        .build() )

Throwing a TypeValidationMisMatch exception.

When just using the ObjectInput directly, it works.

Compilation error: cannot implement get(DataFetchingEnvironment) in DataFetcher

I'm trying to implement a simple DataFetcher and getting a compilation error.

The following is given as an argument to a field definition builder call to dataFetcher().

new DataFetcher() {
  @Override
  Object get(DataFetchingEnvironment environment) {
    // some code returning an Object
  }
}

The compilation error is:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.0.2:compile (default-compile) on project rest: Compilation failure
[ERROR] <path>/GraphQueryResource.java:[95,15] error: get(DataFetchingEnvironment) in <anonymous <package>.GraphQueryResource$1> cannot implement get(DataFetchingEnvironment) in DataFetcher

A more complete stack trace:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.0.2:compile (default-compile) on project rest: Compilation failure
[ERROR] <path>/GraphQueryResource.java:[95,15] error: get(DataFetchingEnvironment) in <anonymous <package>.GraphQueryResource$1> cannot implement get(DataFetchingEnvironment) in DataFetcher
[ERROR] -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.0.2:compile (default-compile) on project rest: Compilation failure
<path>/GraphQueryResource.java:[95,15] error: get(DataFetchingEnvironment) in <anonymous <package>.GraphQueryResource$1> cannot implement get(DataFetchingEnvironment) in DataFetcher


        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:213)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
        at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
        at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:320)
        at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
        at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537)
        at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
        at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
        at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
        at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Caused by: org.apache.maven.plugin.CompilationFailureException: Compilation failure
<path>/GraphQueryResource.java:[95,15] error: get(DataFetchingEnvironment) in <anonymous <package>.GraphQueryResource$1> cannot implement get(DataFetchingEnvironment) in DataFetcher


        at org.apache.maven.plugin.AbstractCompilerMojo.execute(AbstractCompilerMojo.java:516)
        at org.apache.maven.plugin.CompilerMojo.execute(CompilerMojo.java:114)
        at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
        ... 19 more
[ERROR]
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR]   mvn <goals> -rf :rest

Someone advised me to delete the user's .m2 folder, but that didn't help in my case.

Any ideas about what could be causing this?

GraphQLTypeReference should implement GraphQLUnmodifiedType?

I have a schema that uses GraphQLTypeReference for the usual reasons. When I go to execute a query against that schema that references a field that does not exist, I see:

java.lang.ClassCastException: graphql.schema.GraphQLTypeReference cannot be cast to graphql.schema.GraphQLUnmodifiedType
    at graphql.schema.SchemaUtil.getUnmodifiedType(SchemaUtil.java:33)
    at graphql.schema.SchemaUtil.isLeafType(SchemaUtil.java:15)
    at graphql.validation.rules.ScalarLeafs.checkField(ScalarLeafs.java:21)
    at graphql.validation.RulesVisitor.checkField(RulesVisitor.java:92)
    at graphql.validation.RulesVisitor.enter(RulesVisitor.java:51)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:19)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:22)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:22)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:22)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:22)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:22)
    at graphql.validation.LanguageTraversal.traverse(LanguageTraversal.java:14)
    at graphql.validation.Validator.validateDocument(Validator.java:20)
    at graphql.GraphQL.execute(GraphQL.java:66)
    at graphql.GraphQL.execute(GraphQL.java:50)
    at graphql.GraphQL.execute(GraphQL.java:42)

I'm using version 1.2 from the maven repo. I cloned the current state of master, built that, and get the same error.

What's particularly odd is that this is intermittent. I can run sometimes the same test with no changes and immediately after failing it will succeed. So I'm guessing there is some hash ordering diffs between runs that cause this to occasionally work.

So... Is GraphQLTypeReference supposed to implement GraphQLUnmodifiedType, or am I doing something wrong with my GraphQLTypeReferences?

Thanks. This is a wonderful library.

1.3 version?

Is there a 1.3 version in the future? There's been a lot of great work on the project, a lot of excellent fixes. Are you considering cutting another released version soon?

Input GraphQlFloat is Float when read from GraphQl variables and Double when input directly

I'm working on GraphQl for R5 and have query like that:

query requestPlan($fromTime: ZonedDateTime!, $fromLat:Float!, $fromLon:Float!) {
  plan(fromLat:$fromLat, fromLon:$fromLon,
  toLat:46.55680201284476,toLon:15.626914501190184,
  fromTime:$fromTime, toTime:"2015-02-05T10:30+01:00" directModes:[CAR,WALK],
  accessModes:[WALK, BICYCLE], egressModes:[WALK],
transitModes:[BUS]) {

Problem is that when I input values for toLat, fromLat, fromLon and toLon which are GraphQL Floats directly I read them on Java side as Doubles. But If I use GraphQL variables I read them as Floats.

Any idea why?

I'm using version 2016-02-01T07-19-40.

DataFetchingEnvironment creation

The DataFetchingEnvironment which is created in the ExecutionStrategy.java uses executionContext.getRoot() (line 37) but in the DataFetchingEnvironment itself, the parameter is named context. Shouldn't the executionContext.getRoot() be replaced with executionContext? That way, the whole executionContext is available within the DataFetcher.

I changed this in my fork to be able to add errors from within the DataFetcher (I use this for server-side input validation in mutations).

DataFetcher

Hi,
Suppose that I have defined the following schema hierarchy:

{ person { department { office (rate: 10) { rate } } }

this will be translated to a JPA join to fetch data from a SQL database. I could not find a simple way to get the office argument in person data fetcher. getting office argument in its own data fetcher is simple but where's the place to use all this arguments to create and execute a query? I thought I can use context to pass data around but it does not seem very clean. would you please suggest a pattern?

Regards,

Getting "java.lang.ClassCastException: graphql.schema.GraphQLArgument cannot be cast to graphql.schema.GraphQLInputObjectField"

Hi,

I'm getting multiple exceptions when running the GraphQL introspection query on my schema.

Stack trace is as follows:

15:49:11.335 INFO (Execution.java:134) Exception while fetching data
java.lang.ClassCastException: graphql.schema.GraphQLArgument cannot be cast to graphql.schema.GraphQLInputObjectField
    at graphql.introspection.Introspection$2.get(Introspection.java:87) ~[graphql-java-2015-08-16T21-37-10.jar:na]
    at graphql.execution.Execution.resolveField(Execution.java:132) [graphql-java-2015-08-16T21-37-10.jar:na]
    at graphql.execution.Execution.access$000(Execution.java:26) [graphql-java-2015-08-16T21-37-10.jar:na]
    at graphql.execution.Execution$1.call(Execution.java:97) [graphql-java-2015-08-16T21-37-10.jar:na]

The easiest way to replicate is to run GraphIndexTest#testGraphQLIntrospectionQuery from this branch

Execution time limits

Hi!

We are developing a next generation journey planner platform and expose our data through GraphQL APIs. We use OpenTripPlanner as our backend, into which we have implemented a GraphQL API using graphql-java.

Now, we would like to impose some limits to how our public API can be used. For example, it would be nice to be able to say that each query may take no longer than a set time, e.g. two seconds. It's quite possible that our 3rd party API users can accidentally ask for too much information, and that would degrade the quality of service for the other users. OTP also does not at its current state survive from out of memory situations, and the way the GraphQL API is implemented does not contain any other resource guards either.

After investigating the situation, I think one way to implement this would be to have the ExecutionContext contain information about the time when the query resolution began, and when spawning new (parallel) futures, i.e. resolving fields, you could check to see if the time limit was exceeded and stop there.

Have you had any thoughts about implementing such querying limitations? And / or do you have interest in developing them? Maybe we can also fit an implementation into our next sprint. Do you think it would be a useful feature for other users as well? Do you have other ideas about this?

Here is some more information, our project is completely open source & open data.

Thanks!

Generate schema from .class object

I'm programming on both: JavaScript and Java. I'm very excited about idea of GraphQL on a client side. But the Groovy (moreover I suppose Java) implementation seems not readable for me Let's look at the next examples:

  1. Data definition - https://github.com/andimarek/graphql-java/blob/master/src/test/groovy/graphql/StarWarsData.groovy
  2. Schema definition - https://github.com/andimarek/graphql-java/blob/master/src/test/groovy/graphql/StarWarsSchema.java
  3. Query tests - https://github.com/andimarek/graphql-java/blob/master/src/test/groovy/graphql/StarWarsQueryTest.groovy

For me the less readable part is schemas and data fetchers. Why you can't generate them from .class objects? Example:

class StarWarsEnum {
    NEWHOPE,
    EMPIRE,
    JEDI
}
GraphQLEnumType episodeEnum = GraphQL.from(StarWarsEnum.class)

No much benefit for enum, but that will significantly simplify characterInterface and humanType objects. Also your DAO layer may already have that POJO classes and GraphQL will just resure them.

Empty List of String scalars results into list with one null element

When doing a mutation requests the relay way with an input object type with the following schema:

{
          "kind": "INPUT_OBJECT",
          "name": "AddFriendRequest",
          "description": null,
          "fields": null,
          "inputFields": [
            {
              "name": "clientMutationId",
              "description": null,
              "type": {
                "kind": "SCALAR",
                "name": "String",
                "ofType": null
              },
              "defaultValue": null
            },
            {
              "name": "hobbies",
              "description": null,
              "type": {
                "kind": "LIST",
                "name": null,
                "ofType": {
                  "kind": "SCALAR",
                  "name": "String",
                  "ofType": null
                }
              },
              "defaultValue": null
            }
          ],
          "interfaces": null,
          "enumValues": null,
          "possibleTypes": null
        }

If you do a mutation without any hobbies, on the java side you'll get a ArrayList with one null element. This is highly inconvenient, I would expect the ArrayList to simply be null in this case.

float

I get invalid type name for Int in the following query:

query sample ($id: Int , $name: String) { name }

could you please tell me what is the problem?

Mandatory fields are not validated when inside a input object type

When doing a relay-like mutation and you have a input object with the following schema:

        {
          "kind": "INPUT_OBJECT",
          "name": "ChangeFriendRequest",
          "description": null,
          "fields": null,
          "inputFields": [
            {
              "name": "clientMutationId",
              "description": null,
              "type": {
                "kind": "SCALAR",
                "name": "String",
                "ofType": null
              },
              "defaultValue": null
            },
            {
              "name": "id",
              "description": null,
              "type": {
                "kind": "NON_NULL",
                "name": null,
                "ofType": {
                  "kind": "SCALAR",
                  "name": "String",
                  "ofType": null
                }
              }
           ],
          "interfaces": null,
          "enumValues": null,
          "possibleTypes": null
        }

Sending in a mutation:

mutation ChangeFriendMutation(\$input:ChangeFriendRequest) {
                changeFriend(input:\$input) {
                    clientMutationId
                 }
}

Does not return a validation error when not sending the id as an variable in the ChangeFriendRequest input object.

Add support for nullable fields in input

Hi,
I ran into a problem with mutations where we have a complex input object where not all fields need to be filled in. In out API, fields that are not set will be ignored during the update. This way we have a 'patch' instead of a full replace functionality.
This caused some nullpointers in the ValuesResolver class.
I have a patch, but cannot seem to attach it because I don't have write permissions in the repo.

Kind regards,

Schema JSON?

I'm not sure if this is an issue or just my lack of understanding. Is there currently a way to generate a schema JSON file so a client i'd write in JS would validate against the schema i've create on my Java based server?

I think really what i'm asking is if we could add a static string into Introspection called interospectionQuery as appears here:
https://github.com/graphql/graphql-js/blob/a941554fc56d607fecebe2188a7ca8848835c2a8/src/utilities/introspectionQuery.js#L11

Thanks! This is a great library!

Reference Equality Check in VariableTypesMatchRule breaks if GraphQLInputObjectType is created multiple times.

Normally in schema creation, it is OK to create multiple instances of the same type object. However, VariableTypesMatchRule uses reference equality, so if I create my schema with multiple instances of an equivalent GraphQLObjectInputType then I will get validation failures. This was tricky to track down because I create input types in methods (e.g. private GraphQLInputObjectType createPropertyMatchType()) and then call those methods when I need it them.

I think the ideal solution is to use deep equality instead of reference equality in VariableTypeMatchRule.

Otherwise some process in schema creation should canonicalize the types within the schema.

Trouble with UnmodifiedType and TypeReference

My schema has a circular link, and I plan to add many more, but I seem to be getting into a lot of trouble. In my schema, which is a GraphQL translation of the Tumblr API, based on the Jumblr client, you can get the Posts on a Blog, and the Notes on a Post, and the Blog that was the source of each Note. When I build the schema, I use direct GraphQLObjectTypes whenever possible, and GraphQLTypeReferences whenever not. I'm pretty sure this is the correct way to do this, as it's what's done in the Garfield schema sample. I seem to be running into trouble with the schema validator, which is not expecting type references. In fact, I wasn't expecting type references to be in the schema either, as the docs state that a type reference is "replaced with the real type object when the schema is build [sic]." When I build the schema, though, I clearly still have type references in there. I know because when I run System.out.println(((GraphQLObjectType) schema.getType("Note")).getFieldDefinition("blog").getType().getClass()), I get class graphql.schema.GraphQLTypeReference.

Here's the full stack trace:

[main] INFO graphql.GraphQL - Executing request. operation name: null. Request: {blog(blogName: "yo-fuckers") {name, posts(limit: "1", id: "125493544279") {id, notes {type, blog {name}}}}} 
Exception in thread "main" java.lang.ClassCastException: graphql.schema.GraphQLTypeReference cannot be cast to graphql.schema.GraphQLUnmodifiedType
    at graphql.schema.SchemaUtil.getUnmodifiedType(SchemaUtil.java:34)
    at graphql.schema.SchemaUtil.isLeafType(SchemaUtil.java:16)
    at graphql.validation.rules.ScalarLeafs.checkField(ScalarLeafs.java:21)
    at graphql.validation.RulesVisitor.checkField(RulesVisitor.java:92)
    at graphql.validation.RulesVisitor.enter(RulesVisitor.java:51)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:19)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:22)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:22)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:22)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:22)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:22)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:22)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:22)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:22)
    at graphql.validation.LanguageTraversal.traverseImpl(LanguageTraversal.java:22)
    at graphql.validation.LanguageTraversal.traverse(LanguageTraversal.java:14)
    at graphql.validation.Validator.validateDocument(Validator.java:20)
    at graphql.GraphQL.execute(GraphQL.java:73)
    at graphql.GraphQL.execute(GraphQL.java:55)
    at graphql.GraphQL.execute(GraphQL.java:47)
    at App.graphQLTest(App.java:81)
    at App.main(App.java:43)

Nested inputobject in mutation input cannot be optional

Suppose you do a relay-like mutation, with input object AddFriend as input object type. This input object type contains another List of nested input object types which is optional. The schema is more or less like follows:

{
          "kind": "INPUT_OBJECT",
          "name": "AddFriend",
          "description": null,
          "fields": null,
          "inputFields": [
            {
              "name": "clientMutationId",
              "description": null,
              "type": {
                "kind": "SCALAR",
                "name": "String",
                "ofType": null
              },
              "defaultValue": null
            },
            {
              "name": "sharingRules",
              "description": null,
              "type": {
                "kind": "LIST",
                "name": null,
                "ofType": {
                  "kind": "INPUT_OBJECT",
                  "name": "AddSharingRule",
                  "ofType": null
                }
              },
              "defaultValue": null
            }
          ],
          "interfaces": null,
          "enumValues": null,
          "possibleTypes": null
        }

If you send a mutation without any Sharing rule, you get a nullpointer with the followinng stacktrace:

java.lang.NullPointerException
    at graphql.execution.ValuesResolver.coerceValueForInputObjectField(ValuesResolver.java:84)
    at graphql.execution.ValuesResolver.coerceValue(ValuesResolver.java:74)
    at graphql.execution.ValuesResolver.coerceValueForList(ValuesResolver.java:107)
    at graphql.execution.ValuesResolver.coerceValue(ValuesResolver.java:72)
    at graphql.execution.ValuesResolver.coerceValueForInputObjectField(ValuesResolver.java:84)
    at graphql.execution.ValuesResolver.coerceValue(ValuesResolver.java:74)
    at graphql.execution.ValuesResolver.getVariableValue(ValuesResolver.java:59)
    at graphql.execution.ValuesResolver.getVariableValues(ValuesResolver.java:16)
    at graphql.execution.ExecutionContextBuilder.build(ExecutionContextBuilder.java:55)
    at graphql.execution.Execution.execute(Execution.java:32)
    at graphql.GraphQL.execute(GraphQL.java:78)
    at graphql.GraphQL.execute(GraphQL.java:55)

Support for recursive Objects

Very often there is a need for Nested structures in data models.

Example 1: Comments:

GraphQLObjectType commentType = newObject()
                        .name("Comment")
                        .field(newFieldDefinition()
                                .type(new GraphQLList(commentType))
                                .name("replies")
                                .build())
                        .build();

Example 2: Friends:

GraphQLObjectType personType = newObject()
                        .name("Person")
                        .field(newFieldDefinition()
                                .type(new GraphQLList(commentType))
                                .name("friends")
                                .build())
                        .build();

These fairly common use-cases current seem impossible with GraphQL-Java. This is because the type field cannot be null. GraphQL-js gets around this problem by letting you define your fields as a function:

var CommentsType = new GraphQLObjectType({
  name: 'Comments',
  fields: () => ({
    humanName: {type: GraphQLString},
    replies: {type: new GraphQLList(GreetingsType)}
  }),
});

Is something like this possible with GraphQL-java? If not can it be added??

I recommend, overloading the .type to accept a lambda Function. I'll try to make a pull request, that fill probably not work, but with your help it may be possible to make it work.

Boolean property via getter

Hi,

Do you think the following behaviour is incorrect:

Field name: isSelected
Usual java getter: isSelected()
GraphQl expected getter: isIsSelected

File PropertyDataFetcher.java, method getPropertyViaGetter

Why doesn't GraphQLTypeReference implement GraphQLInputType

I.e. why isn't it possible to use TypeReferences when creating input objects? If this is intended like this, what is the proper way to create a GraphQLInputObject hierarchy (used for dynamic generation of mutations) out of a Java entity hierarchy which includes bidirectional relationships?

Thank you!

Long type

Are there any plans to add a GraphQLLong built-in type?

Type Creation interface doesn't handle Entity <---> Entity relationships

An Example of this is assume you need to map a two Java Classes:

public class Person {
String name;
Asset myCar;
}

public Class Asset {
String name;
Person myCar;
}

The problem is that when I'm defining Person I've only got a GraphQLOutputType.Builder object while I'm defining Person, But it's field requires me to Define the Asset object so I recursively start to Define the Asset Object and have another GraphQLOutputType.Buidler for Asse.t When I encounter the Asset's field for Person I'm in a deadlock scenario.

Person needs Asset to be fully defined
Asset needs Person to be fully defined.

To handle this case I need to be able to Create the Person Object partially formed, without it's fields, and then define the Asset type fully pointing to the partially defined Person object. After asset is fully formed I update the field references for Person now that Asset is fully formed.

I've made the changes in a local copy by adding a replaceFieldDefinitions method to the GraphQLObjectType and GraphQLInputObjectType

this allows something like

 public GraphQLObjectType buildObject(Type type, Class classType) {
    // object types we create an object type and then recursively call ourselves to get the field types
    GraphQLObjectType glType = GraphQLObjectType.newObject().name(classType.getSimpleName()).build();

 // add the object type to our cache before we finish processing it's fields, this allows
 // the field objects to point to our partial definition when defining themselves
    outputTypeMap.put(type, glType);
    ImmutableList.Builder<GraphQLFieldDefinition> fieldBuilder = ImmutableList.builder();
    Class classItem = classType;
    do {
        for (Field field : classItem.getDeclaredFields()) {
                GraphQLOutputType fieldType = getObjectType(field.getGenericType());
                    GraphQLOutputType fieldObjectType = getObjectType(field.getGenericType());
                if (fieldObjectType != null) {
                    GraphQLFieldDefinition.Builder builder = GraphQLFieldDefinition.newFieldDefinition().name(field.getName()).type(fieldObjectType);
                    if (fieldObjectType instanceof GraphQLList) {
                            builder.dataFetcher(new CollectionConverterDataFetcher(field.getName()));
                    }
                    fieldBuilder.add(builder.build());
                }
            }
        }
        classItem = classItem.getSuperclass();
    } while (classItem != null && classItem != Object.class);
 // replace the field definition for this object now that we've defined all the sub-objects and our own fields
    glType.replaceFieldDefinitions(fieldBuilder.build());
    return glType;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.