From e01e79a82a4fedefd0d5861ba31f4a2b4e280a1f Mon Sep 17 00:00:00 2001 From: Trevor Scheer Date: Tue, 23 Jul 2019 14:44:28 -0700 Subject: [PATCH] Add serviceName info to new validation errors --- .../__tests__/composeAndValidate.test.ts | 32 +++++++------- .../sdl/__tests__/matchingUnions.test.ts | 2 +- ...t.ts => uniqueTypeNamesWithFields.test.ts} | 36 ++++++++-------- .../validate/sdl/matchingUnions.ts | 11 ++++- .../validate/sdl/uniqueTypeNamesWithFields.ts | 43 +++++++++++++++++-- 5 files changed, 83 insertions(+), 41 deletions(-) rename packages/apollo-federation/src/composition/validate/sdl/__tests__/{uniqueTypeNamesWithoutEnumsOrScalars.test.ts => uniqueTypeNamesWithFields.test.ts} (85%) diff --git a/packages/apollo-federation/src/composition/__tests__/composeAndValidate.test.ts b/packages/apollo-federation/src/composition/__tests__/composeAndValidate.test.ts index 15fd87ed58f..459777c9dfa 100644 --- a/packages/apollo-federation/src/composition/__tests__/composeAndValidate.test.ts +++ b/packages/apollo-federation/src/composition/__tests__/composeAndValidate.test.ts @@ -329,7 +329,7 @@ describe('value types integration tests', () => { expect(errors[0]).toMatchInlineSnapshot(` Object { "code": "VALUE_TYPE_NO_ENTITY", - "message": "Value types cannot be entities (using the @key directive). Please ensure that one type extends the other and doesn't redefine the type, or remove the @key directive if this is not an entity.", + "message": "[serviceB] Product -> Value types cannot be entities (using the \`@key\` directive). Please ensure that the \`Product\` type is extended properly or remove the \`@key\` directive if this is not an entity.", } `); }); @@ -366,11 +366,11 @@ describe('value types integration tests', () => { const { errors } = composeAndValidate([serviceA, serviceB]); expect(errors).toHaveLength(1); expect(errors[0]).toMatchInlineSnapshot(` - Object { - "code": "VALUE_TYPE_FIELD_TYPE_MISMATCH", - "message": "Found field type mismatch on expected value type. 'Product.color' is defined as both a String and a String!. In order to define 'Product' in multiple places, the fields and their types must be identical.", - } - `); + Object { + "code": "VALUE_TYPE_FIELD_TYPE_MISMATCH", + "message": "[serviceA] Product.color -> Found field type mismatch on expected value type belonging to services \`serviceA\` and \`serviceB\`. \`Product.color\` is defined as both a String and a String!. In order to define \`Product\` in multiple places, the fields and their types must be identical.", + } + `); }); it('on kind mismatch', () => { @@ -405,11 +405,11 @@ describe('value types integration tests', () => { const { errors } = composeAndValidate([serviceA, serviceB]); expect(errors).toHaveLength(1); expect(errors[0]).toMatchInlineSnapshot(` - Object { - "code": "VALUE_TYPE_KIND_MISMATCH", - "message": "Found kind mismatch on expected value type. 'Product' is defined as both a ObjectTypeDefinition and a InterfaceTypeDefinition. In order to define Product in multiple places, the kinds must be identical.", - } - `); + Object { + "code": "VALUE_TYPE_KIND_MISMATCH", + "message": "[serviceA] Product -> Found kind mismatch on expected value type belonging to services \`serviceA\` and \`serviceB\`. \`Product\` is defined as both a \`ObjectTypeDefinition\` and a \`InterfaceTypeDefinition\`. In order to define \`Product\` in multiple places, the kinds must be identical.", + } + `); }); it('on union types mismatch', () => { @@ -454,11 +454,11 @@ describe('value types integration tests', () => { const { errors } = composeAndValidate([serviceA, serviceB]); expect(errors).toHaveLength(1); expect(errors[0]).toMatchInlineSnapshot(` - Object { - "code": "VALUE_TYPE_UNION_TYPES_MISMATCH", - "message": "The union 'Product' is defined in multiple places, however the unioned types do not match. Union types with the same name must also consist of identical types. The types Cabinet, Mattress are mismatched.", - } - `); + Object { + "code": "VALUE_TYPE_UNION_TYPES_MISMATCH", + "message": "[serviceA] Product -> The union \`Product\` is defined in services \`serviceA\` and \`serviceB\`, however their types do not match. Union types with the same name must also consist of identical types. The types Cabinet, Mattress are mismatched.", + } + `); }); }); }); diff --git a/packages/apollo-federation/src/composition/validate/sdl/__tests__/matchingUnions.test.ts b/packages/apollo-federation/src/composition/validate/sdl/__tests__/matchingUnions.test.ts index 67b26f73f87..0bf60e509ee 100644 --- a/packages/apollo-federation/src/composition/validate/sdl/__tests__/matchingUnions.test.ts +++ b/packages/apollo-federation/src/composition/validate/sdl/__tests__/matchingUnions.test.ts @@ -68,7 +68,7 @@ describe('MatchingUnions', () => { expect(errors[0]).toMatchInlineSnapshot(` Object { "code": "VALUE_TYPE_UNION_TYPES_MISMATCH", - "message": "The union 'UPC' is defined in multiple places, however the unioned types do not match. Union types with the same name must also consist of identical types. The type Boolean is mismatched.", + "message": "[serviceA] UPC -> The union \`UPC\` is defined in services \`serviceA\` and \`serviceB\`, however their types do not match. Union types with the same name must also consist of identical types. The type Boolean is mismatched.", } `); }); diff --git a/packages/apollo-federation/src/composition/validate/sdl/__tests__/uniqueTypeNamesWithoutEnumsOrScalars.test.ts b/packages/apollo-federation/src/composition/validate/sdl/__tests__/uniqueTypeNamesWithFields.test.ts similarity index 85% rename from packages/apollo-federation/src/composition/validate/sdl/__tests__/uniqueTypeNamesWithoutEnumsOrScalars.test.ts rename to packages/apollo-federation/src/composition/validate/sdl/__tests__/uniqueTypeNamesWithFields.test.ts index 79c3e519c7f..387b6a9d10d 100644 --- a/packages/apollo-federation/src/composition/validate/sdl/__tests__/uniqueTypeNamesWithoutEnumsOrScalars.test.ts +++ b/packages/apollo-federation/src/composition/validate/sdl/__tests__/uniqueTypeNamesWithFields.test.ts @@ -106,17 +106,17 @@ describe('UniqueTypeNamesWithFields', () => { ]); expect(errors).toHaveLength(2); expect(errors).toMatchInlineSnapshot(` - Array [ - Object { - "code": "VALUE_TYPE_FIELD_TYPE_MISMATCH", - "message": "Found field type mismatch on expected value type. 'Product.sku' is defined as both a String! and a ID!. In order to define 'Product' in multiple places, the fields and their types must be identical.", - }, - Object { - "code": "VALUE_TYPE_FIELD_TYPE_MISMATCH", - "message": "Found field type mismatch on expected value type. 'Product.quantity' is defined as both a Int! and a Int. In order to define 'Product' in multiple places, the fields and their types must be identical.", - }, - ] - `); + Array [ + Object { + "code": "VALUE_TYPE_FIELD_TYPE_MISMATCH", + "message": "[serviceA] Product.sku -> Found field type mismatch on expected value type belonging to services \`serviceA\` and \`serviceB\`. \`Product.sku\` is defined as both a String! and a ID!. In order to define \`Product\` in multiple places, the fields and their types must be identical.", + }, + Object { + "code": "VALUE_TYPE_FIELD_TYPE_MISMATCH", + "message": "[serviceA] Product.quantity -> Found field type mismatch on expected value type belonging to services \`serviceA\` and \`serviceB\`. \`Product.quantity\` is defined as both a Int! and a Int. In order to define \`Product\` in multiple places, the fields and their types must be identical.", + }, + ] + `); }); it('object type definitions (overlapping fields, but non-value types)', () => { @@ -337,11 +337,11 @@ describe('UniqueTypeNamesWithFields', () => { UniqueTypeNamesWithFields, ]); expect(errors[0]).toMatchInlineSnapshot(` - Object { - "code": "VALUE_TYPE_KIND_MISMATCH", - "message": "Found kind mismatch on expected value type. 'Product' is defined as both a ObjectTypeDefinition and a InputObjectTypeDefinition. In order to define Product in multiple places, the kinds must be identical.", - } - `); + Object { + "code": "VALUE_TYPE_KIND_MISMATCH", + "message": "[serviceA] Product -> Found kind mismatch on expected value type belonging to services \`serviceA\` and \`serviceB\`. \`Product\` is defined as both a \`ObjectTypeDefinition\` and a \`InputObjectTypeDefinition\`. In order to define \`Product\` in multiple places, the kinds must be identical.", + } + `); }); it('value types cannot be entities (part 1)', () => { @@ -371,7 +371,7 @@ describe('UniqueTypeNamesWithFields', () => { expect(errors[0]).toMatchInlineSnapshot(` Object { "code": "VALUE_TYPE_NO_ENTITY", - "message": "Value types cannot be entities (using the @key directive). Please ensure that one type extends the other and doesn't redefine the type, or remove the @key directive if this is not an entity.", + "message": "[serviceA] Product -> Value types cannot be entities (using the \`@key\` directive). Please ensure that the \`Product\` type is extended properly or remove the \`@key\` directive if this is not an entity.", } `); }); @@ -403,7 +403,7 @@ describe('UniqueTypeNamesWithFields', () => { expect(errors[0]).toMatchInlineSnapshot(` Object { "code": "VALUE_TYPE_NO_ENTITY", - "message": "Value types cannot be entities (using the @key directive). Please ensure that one type extends the other and doesn't redefine the type, or remove the @key directive if this is not an entity.", + "message": "[serviceB] Product -> Value types cannot be entities (using the \`@key\` directive). Please ensure that the \`Product\` type is extended properly or remove the \`@key\` directive if this is not an entity.", } `); }); diff --git a/packages/apollo-federation/src/composition/validate/sdl/matchingUnions.ts b/packages/apollo-federation/src/composition/validate/sdl/matchingUnions.ts index cc56ead8964..87213149dbf 100644 --- a/packages/apollo-federation/src/composition/validate/sdl/matchingUnions.ts +++ b/packages/apollo-federation/src/composition/validate/sdl/matchingUnions.ts @@ -2,7 +2,7 @@ import { GraphQLError, ASTVisitor, UnionTypeDefinitionNode } from 'graphql'; import { SDLValidationContext } from 'graphql/validation/ValidationContext'; import Maybe from 'graphql/tsutils/Maybe'; import xorBy from 'lodash.xorby'; -import { errorWithCode } from '../../utils'; +import { errorWithCode, logServiceAndType } from '../../utils'; import { existedTypeNameMessage, duplicateTypeNameMessage, @@ -46,7 +46,14 @@ export function UniqueUnionTypes(context: SDLValidationContext): ASTVisitor { context.reportError( errorWithCode( 'VALUE_TYPE_UNION_TYPES_MISMATCH', - `The union '${typeName}' is defined in multiple places, however the unioned types do not match. Union types with the same name must also consist of identical types. The type${ + `${logServiceAndType( + duplicateTypeNode.serviceName!, + typeName, + )}The union \`${typeName}\` is defined in services \`${ + duplicateTypeNode.serviceName + }\` and \`${ + node.serviceName + }\`, however their types do not match. Union types with the same name must also consist of identical types. The type${ diffLength > 1 ? 's' : '' } ${unionDiff.map(diffEntry => diffEntry.name.value).join(', ')} ${ diffLength > 1 ? 'are' : 'is' diff --git a/packages/apollo-federation/src/composition/validate/sdl/uniqueTypeNamesWithFields.ts b/packages/apollo-federation/src/composition/validate/sdl/uniqueTypeNamesWithFields.ts index fe1c7a9cd28..67cc457d5ae 100644 --- a/packages/apollo-federation/src/composition/validate/sdl/uniqueTypeNamesWithFields.ts +++ b/packages/apollo-federation/src/composition/validate/sdl/uniqueTypeNamesWithFields.ts @@ -8,7 +8,12 @@ import { import { SDLValidationContext } from 'graphql/validation/ValidationContext'; import Maybe from 'graphql/tsutils/Maybe'; -import { isTypeNodeAnEntity, diffTypeNodes, errorWithCode } from '../../utils'; +import { + isTypeNodeAnEntity, + diffTypeNodes, + errorWithCode, + logServiceAndType, +} from '../../utils'; // Types of nodes this validator is responsible for type TypesWithRequiredUniqueNames = @@ -81,7 +86,19 @@ export function UniqueTypeNamesWithFields( possibleErrors.push( errorWithCode( 'VALUE_TYPE_FIELD_TYPE_MISMATCH', - `Found field type mismatch on expected value type. '${typeName}.${fieldName}' is defined as both a ${types[0]} and a ${types[1]}. In order to define '${typeName}' in multiple places, the fields and their types must be identical.`, + `${logServiceAndType( + duplicateTypeNode.serviceName!, + typeName, + fieldName, + )}Found field type mismatch on expected value type belonging to services \`${ + duplicateTypeNode.serviceName + }\` and \`${ + node.serviceName + }\`. \`${typeName}.${fieldName}\` is defined as both a ${ + types[0] + } and a ${ + types[1] + }. In order to define \`${typeName}\` in multiple places, the fields and their types must be identical.`, [node, duplicateTypeNode], ), ); @@ -101,7 +118,18 @@ export function UniqueTypeNamesWithFields( context.reportError( errorWithCode( 'VALUE_TYPE_KIND_MISMATCH', - `Found kind mismatch on expected value type. '${typeName}' is defined as both a ${kind[0]} and a ${kind[1]}. In order to define ${typeName} in multiple places, the kinds must be identical.`, + `${logServiceAndType( + duplicateTypeNode.serviceName!, + typeName, + )}Found kind mismatch on expected value type belonging to services \`${ + duplicateTypeNode.serviceName + }\` and \`${ + node.serviceName + }\`. \`${typeName}\` is defined as both a \`${ + kind[0] + }\` and a \`${ + kind[1] + }\`. In order to define \`${typeName}\` in multiple places, the kinds must be identical.`, [node, duplicateTypeNode], ), ); @@ -109,10 +137,17 @@ export function UniqueTypeNamesWithFields( // Error if either is an entity if (isTypeNodeAnEntity(node) || isTypeNodeAnEntity(duplicateTypeNode)) { + const entityNode = isTypeNodeAnEntity(duplicateTypeNode) + ? duplicateTypeNode + : node; + context.reportError( errorWithCode( 'VALUE_TYPE_NO_ENTITY', - `Value types cannot be entities (using the @key directive). Please ensure that one type extends the other and doesn't redefine the type, or remove the @key directive if this is not an entity.`, + `${logServiceAndType( + entityNode.serviceName!, + typeName, + )}Value types cannot be entities (using the \`@key\` directive). Please ensure that the \`${typeName}\` type is extended properly or remove the \`@key\` directive if this is not an entity.`, [node, duplicateTypeNode], ), );