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 that no results are returned. (sample query and results below). You can also run the unit tests to check.

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	}	} }

There is no error but the service doesn't return any data. Instead it returns this:

{ "data": { "integersUnion": { "__typename": "IntegerConnection", "pageInfo": null, "edges": null	}	} }

The unit test fails with this at the high level and I included the detailed error below:

IntegersGraphQlControllerTest > generateUnionIssue() FAILED java.lang.AssertionError at IntegersGraphQlControllerTest.kt:67 Caused by: java.lang.AssertionError at IntegersGraphQlControllerTest.kt:67 
java.lang.AssertionError: No value at JSON path "$.data.integersUnion.edges" Request: document='query Integers { integersUnion { __typename ... on IntegerConnection { pageInfo { startCursor endCursor hasNextPage hasPreviousPage } edges { node } } ... on NoIntegersFound { message } } }' ..... 

This is the expected result (notice that the edges array is not null):

{ "data": { "integersUnion": { "__typename": "IntegerConnection", "pageInfo": { "startCursor": "S19bImphdmEudXRpbC5Db2xsZWN0aW9ucyRVbm1vZGlmaWFibGVNYXAiLHsic3RhcnQiOjF9XQ==", "endCursor": "S19bImphdmEudXRpbC5Db2xsZWN0aW9ucyRVbm1vZGlmaWFibGVNYXAiLHsic3RhcnQiOjEwfV0=", "hasNextPage": true, "hasPreviousPage": false	}, "edges": [	{ "node": 1	},	{ "node": 2	},	{ "node": 3	},	{ "node": 4	},	{ "node": 5	},	{ "node": 6	},	{ "node": 7	},	{ "node": 8	},	{ "node": 9	},	{ "node": 10	}	]	}	} }

Solution Description

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

Run the unit tests again you'll see they succeed. You can also run the service 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 fetcher 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

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions