testing GraphQL corner case
- schema.graphqls
- GraphQLスキーマ。全体で共通
- backend
- go-gqlgen
- Go + gqlgenによるGraphQLリゾルバーの実装
- node-apollo-server
- Node.js + Apollo ServerによるGraphQLリゾルバーの実装
- ruby-graphql-ruby
- Ruby + graphql-rubyによるGraphQLリゾルバーの実装
- perl-graphql-perl
- Perl + graphql-perlによるGraphQLリゾルバーの実装
- go-gqlgen
- router
検証するリクエスト。
query MergeConcreteTypeInRootFieldAndInterfaceFragment {
productA {
package {
id
name
}
... on AbstractProduct {
...ProductDetail
}
}
}
fragment ProductDetail on AbstractProduct {
... on ProductB {
package {
displayOwner: owner {
name
}
owners { name }
}
}
... on ProductA {
package {
displayOwner: owner {
name
}
owners { name }
}
}
}期待するレスポンス。
{
"data": {
"productA": {
"package": {
"id": "1",
"name": "pkgA",
"displayOwner": {
"name": "owner1"
},
"owners": [
{
"name": "owner1"
}
]
}
}
}
}- 期待するレスポンスが得られた構成
- backend/go-gqlgen
- backend/node-apollo-server
- backend/perl-graphql-perl
- backend/ruby-graphql-perl
- router/rust-apollo-router + backend
- 期待するレスポンスが得られなかった構成
- router/go-wundergraph-cosmo + backend
- router/node-apollo-gateway + backend
期待と異なるレスポンス。インラインフラグメントにネストしたオブジェクトのフィールドが消えてしまう。
{
"data": {
"productA": {
"package": {
"id": "1",
"name": "pkgA"
}
}
}
}検証するリクエスト。
query MergeInlineFragment {
itemList {
__typename
...ItemA
...ItemB
}
}
fragment ItemA on ItemA {
name
productList {
__typename
package {
id
}
}
}
fragment ItemB on ItemB {
name
productList {
__typename
package {
id
}
}
}期待するレスポンス。
{
"data": {
"itemList": [
{
"__typename": "ItemA",
"name": "itemA",
"productList": [
{
"__typename": "ProductA",
"package": {
"id": "1"
}
},
{
"__typename": "ProductA",
"package": {
"id": "2"
}
}
]
},
{
"__typename": "ItemB",
"name": "itemB",
"productList": [
{
"__typename": "ProductB",
"package": {
"id": "2"
}
},
{
"__typename": "ProductB",
"package": {
"id": "3"
}
}
]
}
]
}
}- 期待するレスポンスが得られた構成
- backend/go-gqlgen
- backend/node-apollo-server
- router/rust-apollo-router + backend/go-gqlgen
- router/rust-apollo-router + backend/node-apollo-server
- router/node-apollo-gateway + backend/go-gqlgen
- router/node-apollo-gateway + backend/node-apollo-server
- 期待するレスポンスが得られなかった構成
- backend/perl-graphql-perl
- backend/ruby-graphql-perl
- router/go-wundergraph-cosmo + backend/perl-graphql-perl
- router/go-wundergraph-cosmo + backend/ruby-graphql-perl
- router/rust-apollo-router + backend/perl-graphql-perl
- router/rust-apollo-router + backend/ruby-graphql-perl
- router/node-apollo-gateway + backend/perl-graphql-perl
- router/node-apollo-gateway + backend/ruby-graphql-ruby
期待と異なるレスポンス。routerと関係なくbackend単体でもエラーになるようだ。
{
"errors": [
{
"locations": [
{
"line": "59",
"column": "1"
}
],
"path": [
"itemList",
"0"
],
"message": "Can't call method \"isa\" on an undefined value at /app/local/lib/perl5/GraphQL/Role/Abstract.pm line 59.\n"
}
],
"data": null
}<h1>Internal Server Error</h1>{
"errors": [
{
"message": "Failed to fetch from Subgraph 'perl'.",
"extensions": {
"errors": [
{
"path": [
"itemList",
"0"
],
"message": "Can't call method \"isa\" on an undefined value at /app/local/lib/perl5/GraphQL/Role/Abstract.pm line 59.\n",
"extensions": {
"code": "DOWNSTREAM_SERVICE_ERROR"
}
}
],
"serviceName": "perl"
}
}
],
"data": null
}{
"errors": [
{
"message": "500: Internal Server Error"
}
],
"data": null
}{
"data": null,
"errors": [
{
"message": "Subgraph errors redacted",
"path": []
}
]
}{
"data": null,
"errors": [
{
"message": "Subgraph errors redacted",
"path": []
},
{
"message": "Subgraph errors redacted",
"path": []
}
]
}{
"errors": [
{
"message": "Can't call method \"isa\" on an undefined value at /app/local/lib/perl5/GraphQL/Role/Abstract.pm line 59.\n",
"path": [
"itemList",
"0"
],
"extensions": {
"serviceName": "perl",
"code": "DOWNSTREAM_SERVICE_ERROR",
"stacktrace": [
"GraphQLError: Can't call method \"isa\" on an undefined value at /app/local/lib/perl5/GraphQL/Role/Abstract.pm line 59.",
"",
" at Object.err (/app/node_modules/.pnpm/@apollo+federation-internals@2.12.2_graphql@16.12.0/node_modules/@apollo/federation-internals/dist/error.js:11:32)",
" at downstreamServiceError (/app/node_modules/.pnpm/@apollo+gateway@2.12.2_encoding@0.1.13_graphql@16.12.0/node_modules/@apollo/gateway/dist/executeQueryPlan.js:523:120)",
" at /app/node_modules/.pnpm/@apollo+gateway@2.12.2_encoding@0.1.13_graphql@16.12.0/node_modules/@apollo/gateway/dist/executeQueryPlan.js:341:59",
" at Array.map (<anonymous>)",
" at sendOperation (/app/node_modules/.pnpm/@apollo+gateway@2.12.2_encoding@0.1.13_graphql@16.12.0/node_modules/@apollo/gateway/dist/executeQueryPlan.js:341:44)",
" at process.processTicksAndRejections (node:internal/process/task_queues:103:5)",
" at async /app/node_modules/.pnpm/@apollo+gateway@2.12.2_encoding@0.1.13_graphql@16.12.0/node_modules/@apollo/gateway/dist/executeQueryPlan.js:255:49",
" at async executeNode (/app/node_modules/.pnpm/@apollo+gateway@2.12.2_encoding@0.1.13_graphql@16.12.0/node_modules/@apollo/gateway/dist/executeQueryPlan.js:200:17)",
" at async /app/node_modules/.pnpm/@apollo+gateway@2.12.2_encoding@0.1.13_graphql@16.12.0/node_modules/@apollo/gateway/dist/executeQueryPlan.js:96:35",
" at async /app/node_modules/.pnpm/@apollo+gateway@2.12.2_encoding@0.1.13_graphql@16.12.0/node_modules/@apollo/gateway/dist/index.js:112:38"
]
}
}
],
"data": null
}{
"errors": [
{
"message": "500: Internal Server Error",
"extensions": {
"response": {
"url": "http://backend-ruby-graphql-ruby:8084/graphql",
"status": 500,
"statusText": "Internal Server Error",
"body": "<h1>Internal Server Error</h1>"
},
"code": "INTERNAL_SERVER_ERROR",
"stacktrace": [
"GraphQLError: 500: Internal Server Error",
" at RemoteGraphQLDataSource.errorFromResponse (/app/node_modules/.pnpm/@apollo+gateway@2.12.2_encoding@0.1.13_graphql@16.12.0/node_modules/@apollo/gateway/dist/datasources/RemoteGraphQLDataSource.js:176:16)",
" at process.processTicksAndRejections (node:internal/process/task_queues:103:5)",
" at async RemoteGraphQLDataSource.sendRequest (/app/node_modules/.pnpm/@apollo+gateway@2.12.2_encoding@0.1.13_graphql@16.12.0/node_modules/@apollo/gateway/dist/datasources/RemoteGraphQLDataSource.js:108:23)",
" at async RemoteGraphQLDataSource.process (/app/node_modules/.pnpm/@apollo+gateway@2.12.2_encoding@0.1.13_graphql@16.12.0/node_modules/@apollo/gateway/dist/datasources/RemoteGraphQLDataSource.js:83:26)",
" at async sendOperation (/app/node_modules/.pnpm/@apollo+gateway@2.12.2_encoding@0.1.13_graphql@16.12.0/node_modules/@apollo/gateway/dist/executeQueryPlan.js:326:26)",
" at async /app/node_modules/.pnpm/@apollo+gateway@2.12.2_encoding@0.1.13_graphql@16.12.0/node_modules/@apollo/gateway/dist/executeQueryPlan.js:255:49",
" at async executeNode (/app/node_modules/.pnpm/@apollo+gateway@2.12.2_encoding@0.1.13_graphql@16.12.0/node_modules/@apollo/gateway/dist/executeQueryPlan.js:200:17)",
" at async /app/node_modules/.pnpm/@apollo+gateway@2.12.2_encoding@0.1.13_graphql@16.12.0/node_modules/@apollo/gateway/dist/executeQueryPlan.js:96:35",
" at async /app/node_modules/.pnpm/@apollo+gateway@2.12.2_encoding@0.1.13_graphql@16.12.0/node_modules/@apollo/gateway/dist/index.js:112:38",
" at async execute (/app/node_modules/.pnpm/@apollo+server@5.2.0_graphql@16.12.0/node_modules/@apollo/server/dist/cjs/requestPipeline.js:245:28)"
]
}
}
],
"data": null
}