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

Fragment safe divergence does not consider field nullability #1361

Closed
joshjcarrier opened this issue May 30, 2018 · 2 comments
Closed

Fragment safe divergence does not consider field nullability #1361

joshjcarrier opened this issue May 30, 2018 · 2 comments

Comments

@joshjcarrier
Copy link

Types on the same union are expected to have matching nullability constraints even when the fragments can never converge.

Given this schema:

type Cat {
  name: String!
}

type Dog  {
  name: String
}

union Pet = Cat | Dog

type Query {
  pet: Pet
}

and this operation:

{
  pet {
    ... on Cat {
      name
    }
    ... on Dog {
      name
    }
  }
}

The execution results in a validation error:

GraphQLError: Fields "name" conflict because they return conflicting types String! and String. Use different aliases on the fields to fetch both if this was intentional.

Related issue: #53

Repro script:

node test.js

test.js

var {
  graphql,
  GraphQLSchema,
  GraphQLNonNull,
  GraphQLObjectType,
  GraphQLUnionType,
  GraphQLString
} = require("graphql");

var CatType = new GraphQLObjectType({
  name: 'Cat',
  fields: () => ({
    name: { type: new GraphQLNonNull(GraphQLString) },
  })
});

var DogType = new GraphQLObjectType({
  name: 'Dog',
  fields: () => ({
    name: { type: GraphQLString },
  })
});

var PetType = new GraphQLUnionType({
  name: 'Pet',
  types: [ DogType, CatType ],
  resolveType(value) {
    return DogType;
  }
});

var schema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'RootQueryType',
    fields: {
      pet: {
        type: PetType,
        resolve() {
          return 'pet';
        }
      }
    }
  })
});

var query = `{
  pet {
    ... on Cat {
      name
    }
    ... on Dog {
      name
    }
  }
}`;

graphql(schema, query).then(result => {
  // Prints error
  // GraphQLError: Fields "name" conflict because they return conflicting types String! and String. Use different aliases on the fields to fetch both if this was intentional.
  console.log(result);
});

package-lock.json

{
  "requires": true,
  "lockfileVersion": 1,
  "dependencies": {
    "graphql": {
      "version": "0.13.2",
      "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.13.2.tgz",
      "integrity": "sha512-QZ5BL8ZO/B20VA8APauGBg3GyEgZ19eduvpLWoq5x7gMmWnHoy8rlQWPLmWgFvo1yNgjSEFMesmS4R6pPr7xog==",
      "requires": {
        "iterall": "1.2.2"
      }
    },
    "iterall": {
      "version": "1.2.2",
      "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz",
      "integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA=="
    }
  }
}
@IvanGoncharov
Copy link
Member

@joshjcarrier Thanks for very detailed issue 👍

Types on the same union are expected to have matching nullability constraints

It's implemented according to the specification:
See 3.a at: http://facebook.github.io/graphql/draft/#SameResponseShape()

However, specification doesn't set in stone so if you think that it should be changed please submit an issue in this repo: https://github.com/facebook/graphql
Also please don't forget to describe your use case in more details and what's prevent you from making both fields either nullable or non-nullable.

If you can't change your schema you can use the following workaround:

{
  pet {
    ... on Cat {
      name
    }
    ... on Dog {
      nullableName: name
    }
  }
}

@KATT
Copy link

KATT commented Oct 25, 2018

I just added graphql-js as a gateway to an existing GraphQL-service, in order to extend it. The existing service does not implement this part of the spec, leading to the whole frontend crashing. Until we've refactored I did the following workaround:

import { specifiedRules } from 'graphql';
import { OverlappingFieldsCanBeMerged } from 'graphql/validation/rules/OverlappingFieldsCanBeMerged';

// <😷>
// Hack graphql-js to prevent "conflict because they return conflicting types"
const index = specifiedRules.findIndex(
  item => item === OverlappingFieldsCanBeMerged
);
specifiedRules.splice(index, 1);
// </😷>

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