diff --git a/src/index.js b/src/index.js index d8e6917ed1..8bab21b217 100644 --- a/src/index.js +++ b/src/index.js @@ -268,7 +268,10 @@ export type { GraphQLFormattedError, GraphQLErrorLocation } from './error'; // Utilities for operating on GraphQL type schema and parsed sources. export { - // The GraphQL query recommended for a full schema introspection. + // Produce the GraphQL query recommended for a full schema introspection. + // Accepts optional IntrospectionOptions. + getIntrospectionQuery, + // Deprecated: use getIntrospectionQuery introspectionQuery, // Gets the target Operation from a Document getOperationAST, @@ -325,6 +328,7 @@ export { export type { BreakingChange, DangerousChange, + IntrospectionOptions, IntrospectionDirective, IntrospectionEnumType, IntrospectionEnumValue, diff --git a/src/type/__tests__/enumType-test.js b/src/type/__tests__/enumType-test.js index a7005b65e4..cadfbf8dfd 100644 --- a/src/type/__tests__/enumType-test.js +++ b/src/type/__tests__/enumType-test.js @@ -15,7 +15,7 @@ import { GraphQLInt, GraphQLString, GraphQLBoolean, - introspectionQuery, + getIntrospectionQuery, } from '../../'; describe('Type System: Enum Values', () => { @@ -411,7 +411,7 @@ describe('Type System: Enum Values', () => { }); it('can be introspected without error', async () => { - const result = await graphql(schema, introspectionQuery); + const result = await graphql(schema, getIntrospectionQuery()); expect(result).to.not.have.property('errors'); }); }); diff --git a/src/type/__tests__/introspection-test.js b/src/type/__tests__/introspection-test.js index 9cfe3bfc2d..fb319b9b12 100644 --- a/src/type/__tests__/introspection-test.js +++ b/src/type/__tests__/introspection-test.js @@ -19,7 +19,7 @@ import { GraphQLEnumType, } from '../../'; -import { introspectionQuery } from '../../utilities/introspectionQuery'; +import { getIntrospectionQuery } from '../../utilities/introspectionQuery'; describe('Introspection', () => { it('executes an introspection query', async () => { @@ -33,7 +33,7 @@ describe('Introspection', () => { }); return expect( - await graphql(EmptySchema, introspectionQuery), + await graphql(EmptySchema, getIntrospectionQuery()), ).to.containSubset({ data: { __schema: { diff --git a/src/utilities/__tests__/buildClientSchema-test.js b/src/utilities/__tests__/buildClientSchema-test.js index d71c2eaf45..b2a869f716 100644 --- a/src/utilities/__tests__/buildClientSchema-test.js +++ b/src/utilities/__tests__/buildClientSchema-test.js @@ -8,7 +8,7 @@ import { describe, it } from 'mocha'; import { expect } from 'chai'; import { buildClientSchema } from '../buildClientSchema'; -import { introspectionQuery } from '../introspectionQuery'; +import { getIntrospectionQuery } from '../introspectionQuery'; import { graphql, GraphQLSchema, @@ -35,9 +35,15 @@ import { GraphQLDirective } from '../../type/directives'; // query against the client-side schema, it should get a result identical to // what was returned by the server. async function testSchema(serverSchema) { - const initialIntrospection = await graphql(serverSchema, introspectionQuery); + const initialIntrospection = await graphql( + serverSchema, + getIntrospectionQuery(), + ); const clientSchema = buildClientSchema(initialIntrospection.data); - const secondIntrospection = await graphql(clientSchema, introspectionQuery); + const secondIntrospection = await graphql( + clientSchema, + getIntrospectionQuery(), + ); expect(secondIntrospection).to.deep.equal(initialIntrospection); } @@ -126,7 +132,7 @@ describe('Type System: build schema from introspection', () => { await testSchema(schema); - const introspection = await graphql(schema, introspectionQuery); + const introspection = await graphql(schema, getIntrospectionQuery()); const clientSchema = buildClientSchema(introspection.data); // Built-ins are used @@ -407,7 +413,7 @@ describe('Type System: build schema from introspection', () => { await testSchema(schema); - const introspection = await graphql(schema, introspectionQuery); + const introspection = await graphql(schema, getIntrospectionQuery()); const clientSchema = buildClientSchema(introspection.data); const clientFoodEnum = clientSchema.getType('Food'); @@ -658,7 +664,10 @@ describe('Type System: build schema from introspection', () => { }; const clientSchema = buildClientSchema(oldIntrospection); - const secondIntrospection = await graphql(clientSchema, introspectionQuery); + const secondIntrospection = await graphql( + clientSchema, + getIntrospectionQuery(), + ); expect(secondIntrospection.data).to.containSubset(newIntrospection); }); @@ -719,7 +728,7 @@ describe('Type System: build schema from introspection', () => { }), }); - const introspection = await graphql(schema, introspectionQuery); + const introspection = await graphql(schema, getIntrospectionQuery()); const clientSchema = buildClientSchema(introspection.data); const result = await graphql( @@ -818,7 +827,7 @@ describe('Type System: build schema from introspection', () => { }), }); - const introspection = await graphql(schema, introspectionQuery); + const introspection = await graphql(schema, getIntrospectionQuery()); expect(() => buildClientSchema(introspection.data)).to.throw( 'Decorated type deeper than introspection query.', ); @@ -848,7 +857,7 @@ describe('Type System: build schema from introspection', () => { }), }); - const introspection = await graphql(schema, introspectionQuery); + const introspection = await graphql(schema, getIntrospectionQuery()); expect(() => buildClientSchema(introspection.data)).to.throw( 'Decorated type deeper than introspection query.', ); @@ -877,7 +886,7 @@ describe('Type System: build schema from introspection', () => { }), }); - const introspection = await graphql(schema, introspectionQuery); + const introspection = await graphql(schema, getIntrospectionQuery()); buildClientSchema(introspection.data); }); }); diff --git a/src/utilities/index.js b/src/utilities/index.js index ec136c3171..54f24d8b6a 100644 --- a/src/utilities/index.js +++ b/src/utilities/index.js @@ -8,8 +8,13 @@ */ // The GraphQL query recommended for a full schema introspection. -export { introspectionQuery } from './introspectionQuery'; +export { + getIntrospectionQuery, + // Deprecated, use getIntrospectionQuery() + introspectionQuery, +} from './introspectionQuery'; export type { + IntrospectionOptions, IntrospectionQuery, IntrospectionSchema, IntrospectionType, diff --git a/src/utilities/introspectionQuery.js b/src/utilities/introspectionQuery.js index cc9ccfcab3..4071250998 100644 --- a/src/utilities/introspectionQuery.js +++ b/src/utilities/introspectionQuery.js @@ -9,70 +9,75 @@ import type { DirectiveLocationEnum } from '../language/directiveLocation'; -export const introspectionQuery = ` - query IntrospectionQuery { - __schema { - queryType { name } - mutationType { name } - subscriptionType { name } - types { - ...FullType +export type IntrospectionOptions = {| + // Whether to include descriptions in the introspection result. + // Default: true + descriptions: boolean, +|}; + +export function getIntrospectionQuery(options?: IntrospectionOptions): string { + const descriptions = !(options && options.descriptions === false); + return ` + query IntrospectionQuery { + __schema { + queryType { name } + mutationType { name } + subscriptionType { name } + types { + ...FullType + } + directives { + name + ${descriptions ? 'description' : ''} + locations + args { + ...InputValue + } + } } - directives { + } + + fragment FullType on __Type { + kind + name + ${descriptions ? 'description' : ''} + fields(includeDeprecated: true) { name - description - locations + ${descriptions ? 'description' : ''} args { ...InputValue } + type { + ...TypeRef + } + isDeprecated + deprecationReason } - } - } - - fragment FullType on __Type { - kind - name - description - fields(includeDeprecated: true) { - name - description - args { + inputFields { ...InputValue } - type { + interfaces { + ...TypeRef + } + enumValues(includeDeprecated: true) { + name + ${descriptions ? 'description' : ''} + isDeprecated + deprecationReason + } + possibleTypes { ...TypeRef } - isDeprecated - deprecationReason - } - inputFields { - ...InputValue - } - interfaces { - ...TypeRef } - enumValues(includeDeprecated: true) { + + fragment InputValue on __InputValue { name - description - isDeprecated - deprecationReason + ${descriptions ? 'description' : ''} + type { ...TypeRef } + defaultValue } - possibleTypes { - ...TypeRef - } - } - - fragment InputValue on __InputValue { - name - description - type { ...TypeRef } - defaultValue - } - fragment TypeRef on __Type { - kind - name - ofType { + fragment TypeRef on __Type { kind name ofType { @@ -93,6 +98,10 @@ export const introspectionQuery = ` ofType { kind name + ofType { + kind + name + } } } } @@ -100,8 +109,10 @@ export const introspectionQuery = ` } } } - } -`; + `; +} + +export const introspectionQuery = getIntrospectionQuery(); export type IntrospectionQuery = {| +__schema: IntrospectionSchema, @@ -135,68 +146,68 @@ export type IntrospectionInputType = | IntrospectionEnumType | IntrospectionInputObjectType; -export type IntrospectionScalarType = {| +export type IntrospectionScalarType = { +kind: 'SCALAR', +name: string, - +description: ?string, -|}; + +description?: ?string, +}; -export type IntrospectionObjectType = {| +export type IntrospectionObjectType = { +kind: 'OBJECT', +name: string, - +description: ?string, + +description?: ?string, +fields: $ReadOnlyArray, +interfaces: $ReadOnlyArray< IntrospectionNamedTypeRef, >, -|}; +}; -export type IntrospectionInterfaceType = {| +export type IntrospectionInterfaceType = { +kind: 'INTERFACE', +name: string, - +description: ?string, + +description?: ?string, +fields: $ReadOnlyArray, +possibleTypes: $ReadOnlyArray< IntrospectionNamedTypeRef, >, -|}; +}; -export type IntrospectionUnionType = {| +export type IntrospectionUnionType = { +kind: 'UNION', +name: string, - +description: ?string, + +description?: ?string, +possibleTypes: $ReadOnlyArray< IntrospectionNamedTypeRef, >, -|}; +}; -export type IntrospectionEnumType = {| +export type IntrospectionEnumType = { +kind: 'ENUM', +name: string, - +description: ?string, + +description?: ?string, +enumValues: $ReadOnlyArray, -|}; +}; -export type IntrospectionInputObjectType = {| +export type IntrospectionInputObjectType = { +kind: 'INPUT_OBJECT', +name: string, - +description: ?string, + +description?: ?string, +inputFields: $ReadOnlyArray, -|}; +}; export type IntrospectionListTypeRef< T: IntrospectionTypeRef = IntrospectionTypeRef, -> = {| +> = { +kind: 'LIST', - +ofType?: T, -|}; + +ofType: T, +}; export type IntrospectionNonNullTypeRef< T: IntrospectionTypeRef = IntrospectionTypeRef, -> = {| +> = { +kind: 'NON_NULL', - +ofType?: T, -|}; + +ofType: T, +}; export type IntrospectionTypeRef = | IntrospectionNamedTypeRef @@ -224,14 +235,14 @@ export type IntrospectionInputTypeRef = export type IntrospectionNamedTypeRef< T: IntrospectionType = IntrospectionType, -> = {| +> = { +kind: $PropertyType, +name: string, -|}; +}; export type IntrospectionField = {| +name: string, - +description: ?string, + +description?: ?string, +args: $ReadOnlyArray, +type: IntrospectionOutputTypeRef, +isDeprecated: boolean, @@ -240,21 +251,21 @@ export type IntrospectionField = {| export type IntrospectionInputValue = {| +name: string, - +description: ?string, + +description?: ?string, +type: IntrospectionInputTypeRef, +defaultValue: ?string, |}; export type IntrospectionEnumValue = {| +name: string, - +description: ?string, + +description?: ?string, +isDeprecated: boolean, +deprecationReason: ?string, |}; export type IntrospectionDirective = {| +name: string, - +description: ?string, + +description?: ?string, +locations: $ReadOnlyArray, +args: $ReadOnlyArray, |};