UNPKG

@graphql-mesh/transport-rest

Version:
202 lines (201 loc) • 10.9 kB
import { isEnumType, isInterfaceType, isIntrospectionType, isScalarType, isSpecifiedScalarType, isUnionType, } from 'graphql'; import { ObjMapScalar } from '@graphql-mesh/transport-common'; import { getDefDirectives } from '@graphql-mesh/utils'; import { getDirective, getDirectiveExtensions } from '@graphql-tools/utils'; import { processDictionaryDirective } from './dictionary.js'; import { processDiscriminatorAnnotations } from './discriminator.js'; import { processFlattenAnnotations } from './flatten.js'; import { getTypeResolverForAbstractType } from './getTypeResolverForAbstractType.js'; import { addHTTPRootFieldResolver } from './httpOperation.js'; import { processLinkFieldAnnotations } from './link.js'; import { processPubSubOperationAnnotations } from './pubsubOperation.js'; import { processResolveRootAnnotations } from './resolveRoot.js'; import { processResolveRootFieldAnnotations } from './resolveRootField.js'; import { processResponseMetadataAnnotations } from './responseMetadata.js'; import { addExecutionLogicToScalar, processScalarType } from './scalars.js'; import { processTypeScriptAnnotations } from './typescriptAnnotations.js'; export function processDirectives(schema, { globalFetch, logger, pubsub, ...extraGlobalOptions } = {}) { const nonExecutableObjMapScalar = schema.getType('ObjMap'); if (nonExecutableObjMapScalar && isScalarType(nonExecutableObjMapScalar)) { addExecutionLogicToScalar(nonExecutableObjMapScalar, ObjMapScalar); } const transportDirectives = getDirectiveExtensions(schema)?.transport; const currDirective = transportDirectives?.[0]; const globalOptions = { endpoint: currDirective?.location, operationHeaders: currDirective?.headers, queryParams: currDirective?.queryParams, queryStringOptions: currDirective?.queryStringOptions, ...extraGlobalOptions, }; if (typeof globalOptions.operationHeaders === 'string') { globalOptions.operationHeaders = JSON.parse(globalOptions.operationHeaders); } if (Array.isArray(globalOptions.operationHeaders)) { globalOptions.operationHeaders = Object.fromEntries(globalOptions.operationHeaders); } if (typeof globalOptions.queryParams === 'string') { globalOptions.queryParams = JSON.parse(globalOptions.queryParams); } if (Array.isArray(globalOptions.queryParams)) { globalOptions.queryParams = Object.fromEntries(globalOptions.queryParams); } const typeMap = schema.getTypeMap(); for (const typeName in typeMap) { const type = typeMap[typeName]; if (isSpecifiedScalarType(type) || isIntrospectionType(type)) { continue; } const exampleAnnotations = getDirective(schema, type, 'example'); if (exampleAnnotations?.length) { const examples = []; for (const exampleAnnotation of exampleAnnotations) { if (exampleAnnotation?.value) { examples.push(exampleAnnotation.value); } } type.extensions = type.extensions || {}; type.extensions.examples = examples; } if (isScalarType(type)) { processScalarType(type); } if (isInterfaceType(type)) { const directiveAnnotations = getDefDirectives(schema, type); for (const directiveAnnotation of directiveAnnotations) { switch (directiveAnnotation.name) { case 'discriminator': processDiscriminatorAnnotations({ interfaceType: type, discriminatorField: directiveAnnotation.args.field, discriminatorMapping: directiveAnnotation.args.mapping, }); break; } } } if (isUnionType(type)) { const directiveAnnotations = getDefDirectives(schema, type); let statusCodeTypeNameIndexMap; let discriminatorField; let discriminatorMapping; for (const directiveAnnotation of directiveAnnotations) { switch (directiveAnnotation.name) { case 'statusCodeTypeName': statusCodeTypeNameIndexMap = statusCodeTypeNameIndexMap || {}; statusCodeTypeNameIndexMap[directiveAnnotation.args.statusCode] = directiveAnnotation.args.typeName; break; case 'discriminator': discriminatorField = directiveAnnotation.args.field; discriminatorMapping = directiveAnnotation.args.mapping; break; } } type.resolveType = getTypeResolverForAbstractType({ possibleTypes: type.getTypes(), discriminatorField, discriminatorMapping, statusCodeTypeNameMap: statusCodeTypeNameIndexMap, serviceName: currDirective?.subgraph, }); } if (isEnumType(type)) { const directiveAnnotations = getDefDirectives(schema, type); for (const directiveAnnotation of directiveAnnotations) { switch (directiveAnnotation.name) { case 'typescript': processTypeScriptAnnotations(type, directiveAnnotation.args.type); break; } } const enumValues = type.getValues(); for (const enumValue of enumValues) { const directiveAnnotations = getDefDirectives(schema, enumValue); for (const directiveAnnotation of directiveAnnotations) { switch (directiveAnnotation.name) { case 'enum': { const realValue = JSON.parse(directiveAnnotation.args.value); enumValue.value = realValue; let valueLookup = type._valueLookup; if (!valueLookup) { valueLookup = new Map(type.getValues().map(enumValue => [enumValue.value, enumValue])); type._valueLookup = valueLookup; } valueLookup.set(realValue, enumValue); break; } } } } } if ('getFields' in type) { const fields = type.getFields(); for (const fieldName in fields) { const field = fields[fieldName]; const directiveAnnotations = getDefDirectives(schema, field); for (const directiveAnnotation of directiveAnnotations) { switch (directiveAnnotation.name) { case 'resolveRoot': processResolveRootAnnotations(field); break; case 'resolveRootField': processResolveRootFieldAnnotations(field, directiveAnnotation.args.field); break; case 'flatten': processFlattenAnnotations(field); break; case 'pubsubOperation': processPubSubOperationAnnotations({ field: field, pubsubTopic: directiveAnnotation.args.pubsubTopic, globalPubsub: pubsub, logger, }); break; case 'httpOperation': { let operationSpecificHeaders = directiveAnnotation.args.operationSpecificHeaders; if (typeof directiveAnnotation.args.operationSpecificHeaders === 'string') { operationSpecificHeaders = JSON.parse(directiveAnnotation.args.operationSpecificHeaders); } if (Array.isArray(directiveAnnotation.args.operationSpecificHeaders)) { operationSpecificHeaders = Object.fromEntries(directiveAnnotation.args.operationSpecificHeaders); } addHTTPRootFieldResolver(schema, field, logger, globalFetch, // TODO: Fix JSON parsing here for queryParams and headers { sourceName: directiveAnnotation.args.sourceName, endpoint: directiveAnnotation.args.endpoint, path: directiveAnnotation.args.path, httpMethod: directiveAnnotation.args.httpMethod, operationSpecificHeaders, isBinary: directiveAnnotation.args.isBinary, requestBaseBody: typeof directiveAnnotation.args.requestBaseBody === 'string' ? JSON.parse(directiveAnnotation.args.requestBaseBody) : directiveAnnotation.args.requestBaseBody, queryParamArgMap: typeof directiveAnnotation.args.queryParamArgMap === 'string' ? JSON.parse(directiveAnnotation.args.queryParamArgMap) : directiveAnnotation.args.queryParamArgMap, queryStringOptionsByParam: typeof directiveAnnotation.args.queryStringOptionsByParam === 'string' ? JSON.parse(directiveAnnotation.args.queryStringOptionsByParam) : directiveAnnotation.args.queryStringOptionsByParam, jsonApiFields: directiveAnnotation.args.jsonApiFields, queryStringOptions: directiveAnnotation.args.queryStringOptions, }, globalOptions); break; } case 'responseMetadata': processResponseMetadataAnnotations(field); break; case 'oas_link': processLinkFieldAnnotations(field, directiveAnnotation.args.defaultRootType, directiveAnnotation.args.defaultField); break; case 'dictionary': processDictionaryDirective(fields, field); } } } } } return schema; }