GraphQL背后处理及执行过程是什么

这篇文章主要讲解了“GraphQL背后处理及执行过程是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“GraphQL背后处理及执行过程是什么”吧!

    Hello World

    package com.graphqljava.tutorial.bookdetails;
    import graphql.ExecutionResult;
    import graphql.GraphQL;
    import graphql.schema.GraphQLSchema;
    import graphql.schema.StaticDataFetcher;
    import graphql.schema.idl.RuntimeWiring;
    import graphql.schema.idl.SchemaGenerator;
    import graphql.schema.idl.SchemaParser;
    import graphql.schema.idl.TypeDefinitionRegistry;
    public class HelloWorld {
        public static void main(String[] args) {
            // 从最简单的schema字符串开始,省去对graphqls文件的读取
            String schema = "type Query{hello: String}";
            // 用于获得graphql schema定义,并解析放入TypeDefinitionRegistry中,以便放置在SchemaGenerator中使用
            SchemaParser schemaParser = new SchemaParser();
            // 解析schema定义字符串,并创建包含一组类型定义的TypeDefinitionRegistry
            TypeDefinitionRegistry typeDefinitionRegistry = schemaParser.parse(schema);
            // runtime wiring 是data fetchers、type resolves和定制标量的规范,这些都需要连接到GraphQLSchema中
            RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring()
                    // 添加一个类型连接
                    .type("Query", builder -> builder.dataFetcher("hello", new StaticDataFetcher("world")))
                    .build();
            //schemaGenerator对象可以使用typeDefinitionRegistry、runtimeWiring生成工作运行时schema
            SchemaGenerator schemaGenerator = new SchemaGenerator();
            //graphQLSchema代表graphql引擎的组合类型系统。
            GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring);
            //构建GraphQL用于执行查询
            GraphQL build = GraphQL.newGraphQL(graphQLSchema).build();
            //执行并获得结果
            ExecutionResult executionResult = build.execute("{hello}");
            System.out.println(executionResult.getData().toString());
        }
    }

    从上面的代码注释可以看到GraphQL大致执行的过程:

    • 根据给定的schema内容使用SchemaParser进行解析获得schema定义TypeDefinitionRegistry。

    • 拿到了schema定义之后还需要定义RuntimeWiring用于定义不同类型的type resolves和对应的数据提取器data fetchers。

    • 使用GraphQLSchema把TypeDefinitionRegistry和RuntimeWiring组合在一起便于以后的使用。

    • 使用GraphQLSchema构建出GraphQL用于后面的QL执行。

    • 传入QL使用GraphQL执行并获得结果ExecutionResult。

    从外层使用代码可以得出核心处理类为:SchemaParser、TypeDefinitionRegistry、RuntimeWiring、GraphQLSchema、GraphQL。

    下面我们分配看看核心类是怎么处理的。

    SchemaParser

    解析schema字符串定义并生成TypeDefinitionRegistry。

    public TypeDefinitionRegistry parse(String schemaInput) throws SchemaProblem {
        try {
            Parser parser = new Parser();
            Document document = parser.parseDocument(schemaInput);
            return buildRegistry(document);
        } catch (ParseCancellationException e) {
            throw handleParseException(e);
        }
    }

    使用Document构建TypeDefinitionRegistry

    public TypeDefinitionRegistry buildRegistry(Document document) {
        List<GraphQLError> errors = new ArrayList<>();
        TypeDefinitionRegistry typeRegistry = new TypeDefinitionRegistry();
        List<Definition> definitions = document.getDefinitions();
        for (Definition definition : definitions) {
            if (definition instanceof SDLDefinition) {
                typeRegistry.add((SDLDefinition) definition).ifPresent(errors::add);
            }
        }
        if (errors.size() > 0) {
            throw new SchemaProblem(errors);
        } else {
            return typeRegistry;
        }
    }

    可以看的出来TypeDefinitionRegistry只是对Document的定义提取,重点还是在于Document的生成,我们可以先通过debugger来先看看Document的大致内容。

    GraphQL背后处理及执行过程是什么  graphql 第1张

    可以看到就是把schema字符串解析成了方便后续使用的Document对象,我们还是详细看看这个对象里面的属性和大概的生成过程。

    Parser#parseDocument

    public Document parseDocument(String input, String sourceName) {
        CharStream charStream;
        if(sourceName == null) {
            charStream = CharStreams.fromString(input);
        } else{
            charStream = CharStreams.fromString(input, sourceName);
        }
        GraphqlLexer lexer = new GraphqlLexer(charStream);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        GraphqlParser parser = new GraphqlParser(tokens);
        parser.removeErrorListeners();
        parser.getInterpreter().setPredictionMode(PredictionMode.SLL);
        parser.setErrorHandler(new BailErrorStrategy());
        //词法分析从schema中解析出tokens(每个关键字、最后一个为EOF),documentContext包含children、start/stop字符等相当于结构。
        GraphqlParser.DocumentContext documentContext = parser.document();
        GraphqlAntlrToLanguage antlrToLanguage = new GraphqlAntlrToLanguage(tokens);
        // 生成document
        Document doc = antlrToLanguage.createDocument(documentContext);
        Token stop = documentContext.getStop();
        List<Token> allTokens = tokens.getTokens();
        if (stop != null && allTokens != null && !allTokens.isEmpty()) {
            Token last = allTokens.get(allTokens.size() - 1);
            //
            // do we have more tokens in the stream than we consumed in the parse?
            // if yes then its invalid.  We make sure its the same channel
            boolean notEOF = last.getType() != Token.EOF;
            boolean lastGreaterThanDocument = last.getTokenIndex() > stop.getTokenIndex();
            boolean sameChannel = last.getChannel() == stop.getChannel();
            if (notEOF && lastGreaterThanDocument && sameChannel) {
                throw new ParseCancellationException("There are more tokens in the query that have not been consumed");
            }
        }
        return doc;
    }

    tokens&documentContext

    GraphQL背后处理及执行过程是什么  graphql 第2张

    可以看到,主要是通过提取schema的关键字、识别结构最后生成Document主要内容为类型定义定义和类型定义中的字段定义。

    RuntimeWiring

    runtime wiring 是data fetchers、type resolves和定制标量的规范,这些都需要连接到GraphQLSchema中。

    RuntimeWiring.Builder#type

    这种形式允许使用lambda作为type wiring的构建器。

    public Builder type(String typeName, UnaryOperator<TypeRuntimeWiring.Builder> builderFunction) {
        TypeRuntimeWiring.Builder builder = builderFunction.apply(TypeRuntimeWiring.newTypeWiring(typeName));
        return type(builder.build());
    }

    添加type wiring。

    public Builder type(TypeRuntimeWiring typeRuntimeWiring) {
        String typeName = typeRuntimeWiring.getTypeName();
        Map<String, DataFetcher> typeDataFetchers = dataFetchers.computeIfAbsent(typeName, k -> new LinkedHashMap<>());
        typeRuntimeWiring.getFieldDataFetchers().forEach(typeDataFetchers::put);
        defaultDataFetchers.put(typeName, typeRuntimeWiring.getDefaultDataFetcher());
        TypeResolver typeResolver = typeRuntimeWiring.getTypeResolver();
        if (typeResolver != null) {
            this.typeResolvers.put(typeName, typeResolver);
        }
        EnumValuesProvider enumValuesProvider = typeRuntimeWiring.getEnumValuesProvider();
        if (enumValuesProvider != null) {
            this.enumValuesProviders.put(typeName, enumValuesProvider);
        }
        return this;
    }

    可以看到主要就是网RuntimeWiring里面添加了dataFetchers、defaultDataFetchers、typeResolvers、enumValuesProviders。下面分别介绍下各属性的含义:

    • DataFetcher:负责返回给定graphql字段数据值。graphql引擎使用datafetcher将逻辑字段解析/获取到运行时对象,该对象将作为整个graphql grapql.ExecutionResult的一部分发送回来。

    GraphQL背后处理及执行过程是什么  graphql 第3张

    GraphQLScalarType:scalar type是graphql树类型的叶节点。该类型允许你定义新的scalar type。

    GraphQL背后处理及执行过程是什么  graphql 第4张

    • TypeResolver:这在类型解析期间被调用,以确定在运行时GraphQLInterfaceTypes和GraphQLUnionTypes应该动态使用哪些具体的GraphQLObjectType。

      • GraphQLInterfaceTypes:在graphql中,接口是一种抽象类型,它定义了一组字段,类型必须包含这些字段才能实现该接口。在运行时,TypeResolver用于获取一个接口对象值,并决定哪个GraphQLObjectType表示此接口类型。关于这个概念的更多细节,请参见graphql.org/learn/schem&hellip;

      • GraphQLUnionTypes:联合类型,相当于组合。

      • GraphQLObjectType:这是工作马类型,表示一个对象,它具有一个或多个字段值,这些字段可以根据对象类型等进行自身的处理,直到到达由GraphQLScalarTypes表示的类型树的叶节点。关于这个概念的更多细节,请参见graphql.org/learn/schem&hellip;

    • SchemaDirectiveWiring:SchemaDirectiveWiring负责基于schema定义语言(SDL)中放置在该元素上的指令增强运行时元素。它可以增强graphql运行时元素并添加新的行为,例如通过更改字段graphql.schema. datafetcher。

    • WiringFactory:WiringFactory允许您基于IDL定义更动态的连接TypeResolvers和DataFetchers。

    • EnumValuesProvider:为每个graphql Enum值提供Java运行时值。用于IDL驱动的schema创建。Enum值被认为是静态的:在创建schema时调用。在执行查询时不使用。

    • GraphqlFieldVisibility:这允许您控制graphql字段的可见性。默认情况下,graphql-java使每个定义的字段可见,但您可以实现此接口的实例并减少特定字段的可见性。

    GraphQL

    build

    例子中通过传入GraphQLSchema构建GraphQL。

    public GraphQL build() {
        assertNotNull(graphQLSchema, "graphQLSchema must be non null");
        assertNotNull(queryExecutionStrategy, "queryStrategy must be non null");
        assertNotNull(idProvider, "idProvider must be non null");
        return new GraphQL(graphQLSchema, queryExecutionStrategy, mutationExecutionStrategy, subscriptionExecutionStrategy, idProvider, instrumentation, preparsedDocumentProvider);
    }

    除了graphQLSchema都是默认值,我们大概看看各个成员分别是用来干嘛的:

    • queryExecutionStrategy:异步非阻塞地运行字段的标准graphql执行策略。

    • mutationExecutionStrategy:异步非阻塞执行,但串行:当时只有一个字段将被解析。关于每个字段的非串行(并行)执行,请参阅AsyncExecutionStrategy。

    • subscriptionExecutionStrategy:通过使用reactive-streams作为订阅查询的输出结果来实现graphql订阅。

    • idProvider:executionid的提供者

    • instrumentation:提供了检测GraphQL查询执行步骤的功能。

    • preparsedDocumentProvider:客户端连接文档缓存和/或查询白名单的接口。

    execute

    下面我们还是来看看具体的执行:

    public ExecutionResult execute(ExecutionInput executionInput) {
        try {
            return executeAsync(executionInput).join();
        } catch (CompletionException e) {
            if (e.getCause() instanceof RuntimeException) {
                throw (RuntimeException) e.getCause();
            } else {
                throw e;
            }
        }
    }

    用提供的输入对象执行graphql query。这将返回一个承诺(又名CompletableFuture),以提供一个ExecutionResult,这是执行所提供查询的结果。

    public CompletableFuture<ExecutionResult> executeAsync(ExecutionInput executionInput) {
        try {
            log.debug("Executing request. operation name: '{}'. query: '{}'. variables '{}'", executionInput.getOperationName(), executionInput.getQuery(), executionInput.getVariables());
            // 创建InstrumentationState对象,这是一个跟踪Instrumentation全生命周期的对象
            InstrumentationState instrumentationState = instrumentation.createState(new InstrumentationCreateStateParameters(this.graphQLSchema, executionInput));
            InstrumentationExecutionParameters inputInstrumentationParameters = new InstrumentationExecutionParameters(executionInput, this.graphQLSchema, instrumentationState);
            // 检测输入对象
            executionInput = instrumentation.instrumentExecutionInput(executionInput, inputInstrumentationParameters);
            InstrumentationExecutionParameters instrumentationParameters = new InstrumentationExecutionParameters(executionInput, this.graphQLSchema, instrumentationState);
            // 在执行检测 chain前调用
            InstrumentationContext<ExecutionResult> executionInstrumentation = instrumentation.beginExecution(instrumentationParameters);
            // 检测GraphQLSchema
            GraphQLSchema graphQLSchema = instrumentation.instrumentSchema(this.graphQLSchema, instrumentationParameters);
            // 对客户端传递的query进行验证并执行
            CompletableFuture<ExecutionResult> executionResult = parseValidateAndExecute(executionInput, graphQLSchema, instrumentationState);
            //
            // finish up instrumentation
            executionResult = executionResult.whenComplete(executionInstrumentation::onCompleted);
            //
            // allow instrumentation to tweak the result
            executionResult = executionResult.thenCompose(result -> instrumentation.instrumentExecutionResult(result, instrumentationParameters));
            return executionResult;
        } catch (AbortExecutionException abortException) {
            return CompletableFuture.completedFuture(abortException.toExecutionResult());
        }
    }

    parseValidateAndExecute(executionInput, graphQLSchema, instrumentationState)进行验证并执行,验证我们就不看了直接看执行:

    private CompletableFuture<ExecutionResult> execute(ExecutionInput executionInput, Document document, GraphQLSchema graphQLSchema, InstrumentationState instrumentationState) {
        String query = executionInput.getQuery();
        String operationName = executionInput.getOperationName();
        Object context = executionInput.getContext();
        Execution execution = new Execution(queryStrategy, mutationStrategy, subscriptionStrategy, instrumentation);
        ExecutionId executionId = idProvider.provide(query, operationName, context);
        log.debug("Executing '{}'. operation name: '{}'. query: '{}'. variables '{}'", executionId, executionInput.getOperationName(), executionInput.getQuery(), executionInput.getVariables());
        CompletableFuture<ExecutionResult> future = execution.execute(document, graphQLSchema, executionId, executionInput, instrumentationState);
        future = future.whenComplete((result, throwable) -> {
            if (throwable != null) {
                log.error(String.format("Execution '%s' threw exception when executing : query : '%s'. variables '%s'", executionId, executionInput.getQuery(), executionInput.getVariables()), throwable);
            } else {
                int errorCount = result.getErrors().size();
                if (errorCount > 0) {
                    log.debug("Execution '{}' completed with '{}' errors", executionId, errorCount);
                } else {
                    log.debug("Execution '{}' completed with zero errors", executionId);
                }
            }
        });
        return future;
    }

    这里打印日志为

    Executing '9c81e267-c55a-4ebd-9f9c-3a2270b28103'. operation name: 'null'. query: '{hello}'. variables '{}'

    还要继续往下看:

    Execution#execute

    public CompletableFuture<ExecutionResult> execute(Document document, GraphQLSchema graphQLSchema, ExecutionId executionId, ExecutionInput executionInput, InstrumentationState instrumentationState) {
        // 获得要执行的操作
        NodeUtil.GetOperationResult getOperationResult = NodeUtil.getOperation(document, executionInput.getOperationName());
        Map<String, FragmentDefinition> fragmentsByName = getOperationResult.fragmentsByName;
        OperationDefinition operationDefinition = getOperationResult.operationDefinition;
        ValuesResolver valuesResolver = new ValuesResolver();
        // 获得输入的参数
        Map<String, Object> inputVariables = executionInput.getVariables();
        List<VariableDefinition> variableDefinitions = operationDefinition.getVariableDefinitions();
        Map<String, Object> coercedVariables;
        try {
            coercedVariables = valuesResolver.coerceArgumentValues(graphQLSchema, variableDefinitions, inputVariables);
        } catch (RuntimeException rte) {
            if (rte instanceof GraphQLError) {
                return completedFuture(new ExecutionResultImpl((GraphQLError) rte));
            }
            throw rte;
        }
        ExecutionContext executionContext = newExecutionContextBuilder()
                .instrumentation(instrumentation)
                .instrumentationState(instrumentationState)
                .executionId(executionId)
                .graphQLSchema(graphQLSchema)
                .queryStrategy(queryStrategy)
                .mutationStrategy(mutationStrategy)
                .subscriptionStrategy(subscriptionStrategy)
                .context(executionInput.getContext())
                .root(executionInput.getRoot())
                .fragmentsByName(fragmentsByName)
                .variables(coercedVariables)
                .document(document)
                .operationDefinition(operationDefinition)
                // 放入dataloder
                .dataLoaderRegistry(executionInput.getDataLoaderRegistry())
                .build();
        InstrumentationExecutionParameters parameters = new InstrumentationExecutionParameters(
                executionInput, graphQLSchema, instrumentationState
        );
        // 获得执行上下文
        executionContext = instrumentation.instrumentExecutionContext(executionContext, parameters);
        return executeOperation(executionContext, parameters, executionInput.getRoot(), executionContext.getOperationDefinition());
    }

    获得了执行上下文并执行,下面继续看executeOperation

    private CompletableFuture<ExecutionResult> executeOperation(ExecutionContext executionContext, InstrumentationExecutionParameters instrumentationExecutionParameters, Object root, OperationDefinition operationDefinition) {
        // ...
        ExecutionStrategyParameters parameters = newParameters()
                .executionStepInfo(executionStepInfo)
                .source(root)
                .fields(fields)
                .nonNullFieldValidator(nonNullableFieldValidator)
                .path(path)
                .build();
        CompletableFuture<ExecutionResult> result;
        try {
            ExecutionStrategy executionStrategy;
            if (operation == OperationDefinition.Operation.MUTATION) {
                executionStrategy = mutationStrategy;
            } else if (operation == SUBSCRIPTION) {
                executionStrategy = subscriptionStrategy;
            } else {
                executionStrategy = queryStrategy;
            }
            log.debug("Executing '{}' query operation: '{}' using '{}' execution strategy", executionContext.getExecutionId(), operation, executionStrategy.getClass().getName());
            result = executionStrategy.execute(executionContext, parameters);
        } catch (NonNullableFieldWasNullException e) {
              // ...
        }
        // ...
        return deferSupport(executionContext, result);
    }

    日志输出:

    Executing '9c81e267-c55a-4ebd-9f9c-3a2270b28103' query operation: 'QUERY' using 'graphql.execution.AsyncExecutionStrategy' execution strategy

    最终使用AsyncExecutionStrategy策略执行,继续往下看:

    AsynExecutionStrategy#execute
    public CompletableFuture<ExecutionResult> execute(ExecutionContext executionContext, ExecutionStrategyParameters parameters) throws NonNullableFieldWasNullException {
        Instrumentation instrumentation = executionContext.getInstrumentation();
        InstrumentationExecutionStrategyParameters instrumentationParameters = new InstrumentationExecutionStrategyParameters(executionContext, parameters);
        ExecutionStrategyInstrumentationContext executionStrategyCtx = instrumentation.beginExecutionStrategy(instrumentationParameters);
        Map<String, List<Field>> fields = parameters.getFields();
        // 字段名称
        List<String> fieldNames = new ArrayList<>(fields.keySet());
        List<CompletableFuture<FieldValueInfo>> futures = new ArrayList<>();
        List<String> resolvedFields = new ArrayList<>();
        for (String fieldName : fieldNames) {
            List<Field> currentField = fields.get(fieldName);
            ExecutionPath fieldPath = parameters.getPath().segment(mkNameForPath(currentField));
            ExecutionStrategyParameters newParameters = parameters
                    .transform(builder -> builder.field(currentField).path(fieldPath).parent(parameters));
            if (isDeferred(executionContext, newParameters, currentField)) {
                executionStrategyCtx.onDeferredField(currentField);
                continue;
            }
            resolvedFields.add(fieldName);
            // 处理字段,这里处理的是"hello"
            CompletableFuture<FieldValueInfo> future = resolveFieldWithInfo(executionContext, newParameters);
            futures.add(future);
        }
        CompletableFuture<ExecutionResult> overallResult = new CompletableFuture<>();
        executionStrategyCtx.onDispatched(overallResult);
        //并行执行所有filed处理的futures
        Async.each(futures).whenComplete((completeValueInfos, throwable) -> {
            BiConsumer<List<ExecutionResult>, Throwable> handleResultsConsumer = handleResults(executionContext, resolvedFields, overallResult);
            if (throwable != null) {
                handleResultsConsumer.accept(null, throwable.getCause());
                return;
            }
            List<CompletableFuture<ExecutionResult>> executionResultFuture = completeValueInfos.stream().map(FieldValueInfo::getFieldValue).collect(Collectors.toList());
            executionStrategyCtx.onFieldValuesInfo(completeValueInfos);
            Async.each(executionResultFuture).whenComplete(handleResultsConsumer);
        }).exceptionally((ex) -> {
            // if there are any issues with combining/handling the field results,
            // complete the future at all costs and bubble up any thrown exception so
            // the execution does not hang.
            overallResult.completeExceptionally(ex);
            return null;
        });
        overallResult.whenComplete(executionStrategyCtx::onCompleted);
        return overallResult;
    }

    可以看到这里会遍历所有fileds拿到每个filed future,最后并行执行,下面具体看看:

    ExecutionStrategy#resolveFieldWithInfo

    调用该函数来获取字段的值及额外的运行时信息,并根据graphql query内容进一步处理它。

    protected CompletableFuture<FieldValueInfo> resolveFieldWithInfo(ExecutionContext executionContext, ExecutionStrategyParameters parameters) {
        GraphQLFieldDefinition fieldDef = getFieldDef(executionContext, parameters, parameters.getField().get(0));
        Instrumentation instrumentation = executionContext.getInstrumentation();
        InstrumentationContext<ExecutionResult> fieldCtx = instrumentation.beginField(
                new InstrumentationFieldParameters(executionContext, fieldDef, createExecutionStepInfo(executionContext, parameters, fieldDef))
        );
        CompletableFuture<Object> fetchFieldFuture = fetchField(executionContext, parameters);
        CompletableFuture<FieldValueInfo> result = fetchFieldFuture.thenApply((fetchedValue) ->
                completeField(executionContext, parameters, fetchedValue));
        CompletableFuture<ExecutionResult> executionResultFuture = result.thenCompose(FieldValueInfo::getFieldValue);
        fieldCtx.onDispatched(executionResultFuture);
        executionResultFuture.whenComplete(fieldCtx::onCompleted);
        return result;
    }

    调用该函数获取filed值,使用从filed GraphQlFiledDefinition关联的DataFetcher。

    protected CompletableFuture<Object> fetchField(ExecutionContext executionContext, ExecutionStrategyParameters parameters) {
        Field field = parameters.getField().get(0);
        GraphQLObjectType parentType = (GraphQLObjectType) parameters.getExecutionStepInfo().getUnwrappedNonNullType();
        GraphQLFieldDefinition fieldDef = getFieldDef(executionContext.getGraphQLSchema(), parentType, field);
        GraphqlFieldVisibility fieldVisibility = executionContext.getGraphQLSchema().getFieldVisibility();
        Map<String, Object> argumentValues = valuesResolver.getArgumentValues(fieldVisibility, fieldDef.getArguments(), field.getArguments(), executionContext.getVariables());
        GraphQLOutputType fieldType = fieldDef.getType();
        DataFetchingFieldSelectionSet fieldCollector = DataFetchingFieldSelectionSetImpl.newCollector(executionContext, fieldType, parameters.getField());
        // ...
        CompletableFuture<Object> fetchedValue;
        // 获得dataFetcher,这里为HelloWorld的`new StaticDataFetcher("world")`
        DataFetcher dataFetcher = fieldDef.getDataFetcher();
        dataFetcher = instrumentation.instrumentDataFetcher(dataFetcher, instrumentationFieldFetchParams);
        ExecutionId executionId = executionContext.getExecutionId();
        try {
            log.debug("'{}' fetching field '{}' using data fetcher '{}'...", executionId, executionStepInfo.getPath(), dataFetcher.getClass().getName());
            // 执行dataFetcher获取值,enviroment为上下文环境包含参数
            Object fetchedValueRaw = dataFetcher.get(environment);
            log.debug("'{}' field '{}' fetch returned '{}'", executionId, executionStepInfo.getPath(), fetchedValueRaw == null ? "null" : fetchedValueRaw.getClass().getName());
            // 如果是具体值就返回已经有值的CompletableFuture,如果是CompletionStage就直接返回
            fetchedValue = Async.toCompletableFuture(fetchedValueRaw);
        } catch (Exception e) {
            log.debug(String.format("'%s', field '%s' fetch threw exception", executionId, executionStepInfo.getPath()), e);
            fetchedValue = new CompletableFuture<>();
            fetchedValue.completeExceptionally(e);
        }
        fetchCtx.onDispatched(fetchedValue);
        // 对结果的后续处理
        return fetchedValue
                .handle((result, exception) -> {
                    fetchCtx.onCompleted(result, exception);
                    if (exception != null) {
                        handleFetchingException(executionContext, parameters, field, fieldDef, argumentValues, environment, exception);
                        return null;
                    } else {
                        return result;
                    }
                })
                .thenApply(result -> unboxPossibleDataFetcherResult(executionContext, parameters, result))
                .thenApply(this::unboxPossibleOptional);
    }

    总体执行过程

    GraphQL背后处理及执行过程是什么  graphql 第5张

    感谢各位的阅读,以上就是“GraphQL背后处理及执行过程是什么”的内容了,经过本文的学习后,相信大家对GraphQL背后处理及执行过程是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是蜗牛博客,小编将为大家推送更多相关知识点的文章,欢迎关注!

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:niceseo99@gmail.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    评论

    有免费节点资源,我们会通知你!加入纸飞机订阅群

    ×
    天气预报查看日历分享网页手机扫码留言评论电报频道链接