Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typed @relation schemas are not parsed properly by graphql.idl() #184

Open
graphadvantage opened this issue Jun 27, 2019 · 6 comments
Open

Comments

@graphadvantage
Copy link

Schemas with typed @relation queries are not parsed properly when published to the Neo4j graphql endpoint using CALL graphql.idl().

Given a graphql schema:

schema {
   query: Query
}

type Person {
  name: String!
  born: Int
  movies: [ActedIn]
}

type Movie  {
  title: String!
  released: Int
  tagline: String
  actors: [ActedIn]
}

type ActedIn @relation(name: "ACTED_IN") {
  from: Person
  to: Movie
  roles: [String!]
}

type Query {

  movieByTitle(searchTerm: String): [Movie]!
    @cypher(statement:"MATCH (n:Movie) WHERE n.title CONTAINS $searchTerm RETURN n")

}

and a graphql query:

query SearchMovies {
  movieByTitle(searchTerm: "Polar Express") {
    title
    actors { 
      Person {name} 
      roles
    }
  }
}

When the schema is published via neo4j-graphql-js (eg grand-stack-starter) we get the expected result - returning relationship properties (roles)

{
  "data": {
    "movieByTitle": [
      {
        "title": "The Polar Express",
        "actors": [
          {
            "Person": {
              "name": "Tom Hanks"
            },
            "roles": [
              "Hero Boy",
              "Father",
              "Conductor",
              "Hobo",
              "Scrooge",
              "Santa Claus"
            ]
          }
        ]
      }
    ]
  }
}

when the schema is published via the plugin using CALL graphql.idl('<schema>') the query fails:

{
  "data": null,
  "errors": [
    {
      "message": "Validation error of type FieldUndefined: Field 'Person' in type 'ActedIn' is undefined @ 'movieByTitle/actors/Person'",
      "locations": [
        {
          "line": 6,
          "column": 7,
          "sourceName": null
        }
      ],
      "description": "Field 'Person' in type 'ActedIn' is undefined",
      "validationErrorType": "FieldUndefined",
      "queryPath": [
        "movieByTitle",
        "actors",
        "Person"
      ],
      "errorType": "ValidationError",
      "path": null,
      "extensions": null
    }
  ]
}

modifying the query to:

query SearchMovies {
  movieByTitle(searchTerm: "Polar Express") {
    title
    actors { 
      from {name} 
      roles
    }
  }
}

passes validation, but returns a null array for the @relation type and its properties

{
  "data": {
    "movieByTitle": [
      {
        "title": "The Polar Express",
        "actors": []
      }
    ]
  }
}
@jexp
Copy link
Contributor

jexp commented Jun 27, 2019

Please note that the existing/old transpiler in neo4j-graphql (the plugin) doesn't support those at all.

The new implementation in neo4j-graphql-java does, and should be available under /graphql/experimental.

Please try that and report back if it worked.

@graphadvantage
Copy link
Author

graphadvantage commented Jun 27, 2019

Thank you Michael - Using /graphql/experimental (plugin v 3.5.0.4 built from source) does work but requires the query to be modified for the plugin:

using the same schema above and the standard format query:

query SearchMovies {
  movieByTitle(searchTerm: "Polar Express") {
    title
    actors { 
      Person {name} 
      roles
    }
  }
}

throws an error:

{
  "error": "Failed to fetch. Please check your connection"
}

neo4j.log shows a missing field exception:

2019-06-27 14:05:58.564+0000 ERROR The RuntimeException could not be mapped to a response, re-throwing to the HTTP container No field Person in ActedIn
java.lang.IllegalStateException: No field Person in ActedIn
	at org.neo4j.graphql.Translator.projectField(Translator.kt:276)
	at org.neo4j.graphql.Translator.projectFields(Translator.kt:263)
	at org.neo4j.graphql.Translator.projectRichAndRegularRelationship(Translator.kt:382)
	at org.neo4j.graphql.Translator.projectRelationship(Translator.kt:335)
	at org.neo4j.graphql.Translator.projectField(Translator.kt:288)
	at org.neo4j.graphql.Translator.projectFields(Translator.kt:263)
	at org.neo4j.graphql.Translator.toQuery(Translator.kt:90)
	at org.neo4j.graphql.Translator.translate(Translator.kt:63)

Using the modified query -- replacing "Person" with the directional "from" does work:

query SearchMovies {
  movieByTitle(searchTerm: "Polar Express") {
    title
    actors { 
      from {name} 
      roles
    }
  }
}

yields:

{
  "data": [
    {
      "movieByTitle": {
        "actors": [
          {
            "roles": [
              "Hero Boy",
              "Father",
              "Conductor",
              "Hobo",
              "Scrooge",
              "Santa Claus"
            ],
            "from": {
              "name": "Tom Hanks"
            }
          }
        ],
        "title": "The Polar Express"
      }
    }
  ]
}

This is pretty close - /experimental can access the @relation properties, but the semantics are not consistent due the differences in the bindings -- it appears the transpiler is binding to the key from: and not to the value Person in the @relation directive.

type ActedIn @relation(name: "ACTED_IN") {
  from: Person
  to: Movie
  roles: [String!]
}

This would be good to fix since it makes the graphql queries not as portable as they could be across the platforms. Application result set parsers would also need to be different depending on the endpoint.

@jexp
Copy link
Contributor

jexp commented Jun 27, 2019

The Person field bit in your query doesn't make sense.
It should be from as that's the key name.

@jexp
Copy link
Contributor

jexp commented Jun 27, 2019

In the transpiler you can also provide other names in the directive for from and to.

@graphadvantage
Copy link
Author

graphadvantage commented Jun 28, 2019

I understand - the point I'm making is that we should try to have graphql operate the same irrespective of whether it's the neo4j js implementation or the neo4j java implementation. This greatly increases the value of leveraging graphql in real applications. One should be able to have interoperable schemas and queries.

@adamclerk
Copy link

I've now run into this issue. What was the actual fix?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants