buildClientSchema.mjs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. import objectValues from "../polyfills/objectValues.mjs";
  2. import inspect from "../jsutils/inspect.mjs";
  3. import devAssert from "../jsutils/devAssert.mjs";
  4. import keyValMap from "../jsutils/keyValMap.mjs";
  5. import isObjectLike from "../jsutils/isObjectLike.mjs";
  6. import { parseValue } from "../language/parser.mjs";
  7. import { GraphQLSchema } from "../type/schema.mjs";
  8. import { GraphQLDirective } from "../type/directives.mjs";
  9. import { specifiedScalarTypes } from "../type/scalars.mjs";
  10. import { introspectionTypes, TypeKind } from "../type/introspection.mjs";
  11. import { isInputType, isOutputType, GraphQLList, GraphQLNonNull, GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, assertNullableType, assertObjectType, assertInterfaceType } from "../type/definition.mjs";
  12. import { valueFromAST } from "./valueFromAST.mjs";
  13. /**
  14. * Build a GraphQLSchema for use by client tools.
  15. *
  16. * Given the result of a client running the introspection query, creates and
  17. * returns a GraphQLSchema instance which can be then used with all graphql-js
  18. * tools, but cannot be used to execute a query, as introspection does not
  19. * represent the "resolver", "parse" or "serialize" functions or any other
  20. * server-internal mechanisms.
  21. *
  22. * This function expects a complete introspection result. Don't forget to check
  23. * the "errors" field of a server response before calling this function.
  24. */
  25. export function buildClientSchema(introspection, options) {
  26. isObjectLike(introspection) && isObjectLike(introspection.__schema) || devAssert(0, "Invalid or incomplete introspection result. Ensure that you are passing \"data\" property of introspection response and no \"errors\" was returned alongside: ".concat(inspect(introspection), ".")); // Get the schema from the introspection result.
  27. var schemaIntrospection = introspection.__schema; // Iterate through all types, getting the type definition for each.
  28. var typeMap = keyValMap(schemaIntrospection.types, function (typeIntrospection) {
  29. return typeIntrospection.name;
  30. }, function (typeIntrospection) {
  31. return buildType(typeIntrospection);
  32. }); // Include standard types only if they are used.
  33. for (var _i2 = 0, _ref2 = [].concat(specifiedScalarTypes, introspectionTypes); _i2 < _ref2.length; _i2++) {
  34. var stdType = _ref2[_i2];
  35. if (typeMap[stdType.name]) {
  36. typeMap[stdType.name] = stdType;
  37. }
  38. } // Get the root Query, Mutation, and Subscription types.
  39. var queryType = schemaIntrospection.queryType ? getObjectType(schemaIntrospection.queryType) : null;
  40. var mutationType = schemaIntrospection.mutationType ? getObjectType(schemaIntrospection.mutationType) : null;
  41. var subscriptionType = schemaIntrospection.subscriptionType ? getObjectType(schemaIntrospection.subscriptionType) : null; // Get the directives supported by Introspection, assuming empty-set if
  42. // directives were not queried for.
  43. var directives = schemaIntrospection.directives ? schemaIntrospection.directives.map(buildDirective) : []; // Then produce and return a Schema with these types.
  44. return new GraphQLSchema({
  45. description: schemaIntrospection.description,
  46. query: queryType,
  47. mutation: mutationType,
  48. subscription: subscriptionType,
  49. types: objectValues(typeMap),
  50. directives: directives,
  51. assumeValid: options === null || options === void 0 ? void 0 : options.assumeValid
  52. }); // Given a type reference in introspection, return the GraphQLType instance.
  53. // preferring cached instances before building new instances.
  54. function getType(typeRef) {
  55. if (typeRef.kind === TypeKind.LIST) {
  56. var itemRef = typeRef.ofType;
  57. if (!itemRef) {
  58. throw new Error('Decorated type deeper than introspection query.');
  59. }
  60. return new GraphQLList(getType(itemRef));
  61. }
  62. if (typeRef.kind === TypeKind.NON_NULL) {
  63. var nullableRef = typeRef.ofType;
  64. if (!nullableRef) {
  65. throw new Error('Decorated type deeper than introspection query.');
  66. }
  67. var nullableType = getType(nullableRef);
  68. return new GraphQLNonNull(assertNullableType(nullableType));
  69. }
  70. return getNamedType(typeRef);
  71. }
  72. function getNamedType(typeRef) {
  73. var typeName = typeRef.name;
  74. if (!typeName) {
  75. throw new Error("Unknown type reference: ".concat(inspect(typeRef), "."));
  76. }
  77. var type = typeMap[typeName];
  78. if (!type) {
  79. throw new Error("Invalid or incomplete schema, unknown type: ".concat(typeName, ". Ensure that a full introspection query is used in order to build a client schema."));
  80. }
  81. return type;
  82. }
  83. function getObjectType(typeRef) {
  84. return assertObjectType(getNamedType(typeRef));
  85. }
  86. function getInterfaceType(typeRef) {
  87. return assertInterfaceType(getNamedType(typeRef));
  88. } // Given a type's introspection result, construct the correct
  89. // GraphQLType instance.
  90. function buildType(type) {
  91. if (type != null && type.name != null && type.kind != null) {
  92. switch (type.kind) {
  93. case TypeKind.SCALAR:
  94. return buildScalarDef(type);
  95. case TypeKind.OBJECT:
  96. return buildObjectDef(type);
  97. case TypeKind.INTERFACE:
  98. return buildInterfaceDef(type);
  99. case TypeKind.UNION:
  100. return buildUnionDef(type);
  101. case TypeKind.ENUM:
  102. return buildEnumDef(type);
  103. case TypeKind.INPUT_OBJECT:
  104. return buildInputObjectDef(type);
  105. }
  106. }
  107. var typeStr = inspect(type);
  108. throw new Error("Invalid or incomplete introspection result. Ensure that a full introspection query is used in order to build a client schema: ".concat(typeStr, "."));
  109. }
  110. function buildScalarDef(scalarIntrospection) {
  111. return new GraphQLScalarType({
  112. name: scalarIntrospection.name,
  113. description: scalarIntrospection.description,
  114. specifiedByUrl: scalarIntrospection.specifiedByUrl
  115. });
  116. }
  117. function buildImplementationsList(implementingIntrospection) {
  118. // TODO: Temporary workaround until GraphQL ecosystem will fully support
  119. // 'interfaces' on interface types.
  120. if (implementingIntrospection.interfaces === null && implementingIntrospection.kind === TypeKind.INTERFACE) {
  121. return [];
  122. }
  123. if (!implementingIntrospection.interfaces) {
  124. var implementingIntrospectionStr = inspect(implementingIntrospection);
  125. throw new Error("Introspection result missing interfaces: ".concat(implementingIntrospectionStr, "."));
  126. }
  127. return implementingIntrospection.interfaces.map(getInterfaceType);
  128. }
  129. function buildObjectDef(objectIntrospection) {
  130. return new GraphQLObjectType({
  131. name: objectIntrospection.name,
  132. description: objectIntrospection.description,
  133. interfaces: function interfaces() {
  134. return buildImplementationsList(objectIntrospection);
  135. },
  136. fields: function fields() {
  137. return buildFieldDefMap(objectIntrospection);
  138. }
  139. });
  140. }
  141. function buildInterfaceDef(interfaceIntrospection) {
  142. return new GraphQLInterfaceType({
  143. name: interfaceIntrospection.name,
  144. description: interfaceIntrospection.description,
  145. interfaces: function interfaces() {
  146. return buildImplementationsList(interfaceIntrospection);
  147. },
  148. fields: function fields() {
  149. return buildFieldDefMap(interfaceIntrospection);
  150. }
  151. });
  152. }
  153. function buildUnionDef(unionIntrospection) {
  154. if (!unionIntrospection.possibleTypes) {
  155. var unionIntrospectionStr = inspect(unionIntrospection);
  156. throw new Error("Introspection result missing possibleTypes: ".concat(unionIntrospectionStr, "."));
  157. }
  158. return new GraphQLUnionType({
  159. name: unionIntrospection.name,
  160. description: unionIntrospection.description,
  161. types: function types() {
  162. return unionIntrospection.possibleTypes.map(getObjectType);
  163. }
  164. });
  165. }
  166. function buildEnumDef(enumIntrospection) {
  167. if (!enumIntrospection.enumValues) {
  168. var enumIntrospectionStr = inspect(enumIntrospection);
  169. throw new Error("Introspection result missing enumValues: ".concat(enumIntrospectionStr, "."));
  170. }
  171. return new GraphQLEnumType({
  172. name: enumIntrospection.name,
  173. description: enumIntrospection.description,
  174. values: keyValMap(enumIntrospection.enumValues, function (valueIntrospection) {
  175. return valueIntrospection.name;
  176. }, function (valueIntrospection) {
  177. return {
  178. description: valueIntrospection.description,
  179. deprecationReason: valueIntrospection.deprecationReason
  180. };
  181. })
  182. });
  183. }
  184. function buildInputObjectDef(inputObjectIntrospection) {
  185. if (!inputObjectIntrospection.inputFields) {
  186. var inputObjectIntrospectionStr = inspect(inputObjectIntrospection);
  187. throw new Error("Introspection result missing inputFields: ".concat(inputObjectIntrospectionStr, "."));
  188. }
  189. return new GraphQLInputObjectType({
  190. name: inputObjectIntrospection.name,
  191. description: inputObjectIntrospection.description,
  192. fields: function fields() {
  193. return buildInputValueDefMap(inputObjectIntrospection.inputFields);
  194. }
  195. });
  196. }
  197. function buildFieldDefMap(typeIntrospection) {
  198. if (!typeIntrospection.fields) {
  199. throw new Error("Introspection result missing fields: ".concat(inspect(typeIntrospection), "."));
  200. }
  201. return keyValMap(typeIntrospection.fields, function (fieldIntrospection) {
  202. return fieldIntrospection.name;
  203. }, buildField);
  204. }
  205. function buildField(fieldIntrospection) {
  206. var type = getType(fieldIntrospection.type);
  207. if (!isOutputType(type)) {
  208. var typeStr = inspect(type);
  209. throw new Error("Introspection must provide output type for fields, but received: ".concat(typeStr, "."));
  210. }
  211. if (!fieldIntrospection.args) {
  212. var fieldIntrospectionStr = inspect(fieldIntrospection);
  213. throw new Error("Introspection result missing field args: ".concat(fieldIntrospectionStr, "."));
  214. }
  215. return {
  216. description: fieldIntrospection.description,
  217. deprecationReason: fieldIntrospection.deprecationReason,
  218. type: type,
  219. args: buildInputValueDefMap(fieldIntrospection.args)
  220. };
  221. }
  222. function buildInputValueDefMap(inputValueIntrospections) {
  223. return keyValMap(inputValueIntrospections, function (inputValue) {
  224. return inputValue.name;
  225. }, buildInputValue);
  226. }
  227. function buildInputValue(inputValueIntrospection) {
  228. var type = getType(inputValueIntrospection.type);
  229. if (!isInputType(type)) {
  230. var typeStr = inspect(type);
  231. throw new Error("Introspection must provide input type for arguments, but received: ".concat(typeStr, "."));
  232. }
  233. var defaultValue = inputValueIntrospection.defaultValue != null ? valueFromAST(parseValue(inputValueIntrospection.defaultValue), type) : undefined;
  234. return {
  235. description: inputValueIntrospection.description,
  236. type: type,
  237. defaultValue: defaultValue,
  238. deprecationReason: inputValueIntrospection.deprecationReason
  239. };
  240. }
  241. function buildDirective(directiveIntrospection) {
  242. if (!directiveIntrospection.args) {
  243. var directiveIntrospectionStr = inspect(directiveIntrospection);
  244. throw new Error("Introspection result missing directive args: ".concat(directiveIntrospectionStr, "."));
  245. }
  246. if (!directiveIntrospection.locations) {
  247. var _directiveIntrospectionStr = inspect(directiveIntrospection);
  248. throw new Error("Introspection result missing directive locations: ".concat(_directiveIntrospectionStr, "."));
  249. }
  250. return new GraphQLDirective({
  251. name: directiveIntrospection.name,
  252. description: directiveIntrospection.description,
  253. isRepeatable: directiveIntrospection.isRepeatable,
  254. locations: directiveIntrospection.locations.slice(),
  255. args: buildInputValueDefMap(directiveIntrospection.args)
  256. });
  257. }
  258. }