Skip to content

RelayConnection wrapped by a Union causes issues #1274

@starJammer

Description

@starJammer

tl dr: Is the code in the sample project a good or bad solution for handling RelayConnections wrapped by a union? It uses a solution similar to the existing ConnectionFieldTypeVisitor.

Problem Description

Relay Pagination is supported in Spring Boot GraphQL so that in the following schema the integers field will work correctly, but the integersUnion field will not.

You can get a sample project here here: https://github.com/starJammer/spring-graphql-unions-pagination
The project's README.md file contains the everything I've written below as well.
The sample project includes the proposed solution below so it can be looked at in code.

You can start the sample project and see the resulting errors for yourself. (sample query below)

type Query {
    """ returns a list of integers from 1 to 1000 """
    integers(first: Int, after: String): IntegerConnection!
    """ Same as above except the connection object is wrapped in a union """
    integersUnion(first: Int, after: String): IntegerResult!
}

union IntegerResult = IntegerConnection | NoIntegersFound

type IntegerConnection {
    edges: [IntegerEdge]!
    pageInfo: PageInfo
}

type NoIntegersFound {
    message: String!   
}

type IntegerEdge {
    node: Int
    cursor: String   
}

type PageInfo {
    startCursor: String
    endCursor: String
    hasNextPage: Boolean
    hasPreviousPage: Boolean
}
# Sample query
query Integers {
	integersUnion {
		__typename
		... on IntegerConnection {
			pageInfo {
				startCursor
				endCursor
				hasNextPage
				hasPreviousPage
			}
			edges {
				node
			}
		}
		... on NoIntegersFound {
			message
		}
	}
}

The resulting error returned from the integersUnion field is:

{
	"errors": [
		{
			"message": "The field at path '/integersUnion/edges' was declared as a non null type, but the code involved in retrieving data has wrongly returned a null value.  The graphql specification requires that the parent field be set to null, or if that is non nullable that it bubble up null to its parent and so on. The non-nullable type is '[IntegerEdge]' within parent type 'IntegerConnection'",
			"path": [
				"integersUnion",
				"edges"
			],
			"extensions": {
				"classification": "NullValueInNonNullableField"
			}
		}
	],
	"data": null
}

Solution Description

Open the GraphQLUnionConfiguration.kt file in the project and go to line 23 and add uncomment it so the bean gets created. (make sure to uncomment the related import too at the top of the file)

Run the project again and attempt the query again and notice that it works. (or it should the last time I tested)

If you pass in a negative first value you will see that the NoIntegersFound object is returned instead of an IntegerConnection.

GraphQLUnionConfiguration will register the ConnectionUnderUnionTypeVisitor I created in the project.

Read comments on the class for more details but in short it will:

  1. Look for union types being returned and in a decorator data fetcher.
  2. The decorator data fecher will execute the original data fetcher and if the return value
    is a SliceWrapper or WindowWrapper it will adapt the return value to a Connection object
    the same way that ConnectionFieldTypeVisitor does. It also adds a type resolver for the union
    so it resolves the connection object to the Connection type.

Limitations:

  1. Does not support multiple connection objects under a union.
  2. Not sure if this is a good approach or if there is a better one.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions