• GraphQL Java


    一、graphql如何获取数据

    每个graphql中定义的字段都有一个相关联的graphql.schema.DataFetcher。

    有些字段使用自定义的data fetcher代码,用于访问数据库并从数据库中获取字段信息。而大多数字段仅使用字段名称,在内存中的Map对象或或普通的Java对象(POJO)中获取数据。

    在其他的GraphQL 实现当中,Data Fetcher会有时称为resolvers。

    假设一个类型定义如下:

        type Query {
            products(match : String) : [Product]   # a list of products
        }
    
        type Product {
            id : ID
            name : String
            description : String
            cost : Float
            tax : Float
            launchDate(dateFormat : String = "dd, MMM, yyyy') : String
        }
    

    Query.products字段有一个Data Fetcher,Product类型中的每个字段也一样。

    Query.products字段的Data Fetcher可能非常复杂,包含从数据库中读取Product对象的操作。它使用一个可选的match参数,进而可以对products结果中的对象进行过滤。

    其示例如下:

            DataFetcher productsDataFetcher = new DataFetcher<List<ProductDTO>>() {
                @Override
                public List<ProductDTO> get(DataFetchingEnvironment environment) {
                    DatabaseSecurityCtx ctx = environment.getContext();
    
                    List<ProductDTO> products;
                    String match = environment.getArgument("match");
                    if (match != null) {
                        products = fetchProductsFromDatabaseWithMatching(ctx, match);
                    } else {
                        products = fetchAllProductsFromDatabase(ctx);
                    }
                    return products;
                }
            };
    

    每个DataFetcher都传递一个graphql.schema.DataFetchingEnvironment对象,该对象包含正在fetch的field(字段),提供给字段的参数argument以及其他信息,例如字段的类型,父类型,查询根对象或查询上下文对象。

    在上下文调用中,可以使用上下文对象,在访问数据库时提供安全性验证。

    有了ProductDTO对象列表,通常不需要在每个字段上使用专门的数据获取器。 graphql-java提供了graphql.schema.PropertyDataFetcher,它可以根据字段名称,遵循POJO模式获取字段的值。 在上面的示例中,有一个name字段,PropertyDataFetcher将尝试查找POJO中的String getName()方法来获取数据。

    graphql.schema.PropertyDataFetcher是默认的字段data fetcher。

    也可以通过访问DTO方法中的graphql.schema.DataFetchingEnvironment,调整字段的返回值。

    例如,上面我们有一个launchDate字段,它接受一个可选的dateFormat参数。 我们可以让ProductDTO具有将此日期格式应用于所需格式的逻辑。

        class ProductDTO {
    
            private ID id;
            private String name;
            private String description;
            private Double cost;
            private Double tax;
            private LocalDateTime launchDate;
    
            // ...
    
            public String getName() {
                return name;
            }
    
            // ...
    
            public String getLaunchDate(DataFetchingEnvironment environment) {
                String dateFormat = environment.getArgument("dateFormat");
                return yodaTimeFormatter(launchDate,dateFormat);
            }
        }
    

    二、定制化PropertyDataFetcher

    如上所述,graphql.schema.PropertyDataFetcher是graphql-java中字段的默认数据获取器,它将使用标准模式来获取对象字段值。

    它以Java习惯的方式支持POJO对象方法和Map映射值获取。 默认情况下,假定对于graphql字段fieldX,它可以在Map类型对象中寻找key为fieldX的值,或POJO对象中名为fieldX的属性值。

    GraphQL Schema中的字段明明和运行时对象的命名之间可能存在细微差别。 例如,假设Product.description在运行时实际调用的java方法为getDesc()。

    如果使用SDL指定schema,则可以使用@fetch指令指示此重新映射。

        directive @fetch(from : String!) on FIELD_DEFINITION
    
        type Product {
            id : ID
            name : String
            description : String @fetch(from:"desc")
            cost : Float
            tax : Float
        }
    

    graphql.schema.PropertyDataFetcher在获取名为description的字段数据时会使用属性名desc。

    如果使用代码手动构造schema,那么只需要在代码中直接进行指定即可。

            GraphQLFieldDefinition descriptionField = GraphQLFieldDefinition.newFieldDefinition()
                    .name("description")
                    .type(Scalars.GraphQLString)
                    .build();
    
            GraphQLCodeRegistry codeRegistry = GraphQLCodeRegistry.newCodeRegistry()
                    .dataFetcher(
                            coordinates("ObjectType", "description"),
                            PropertyDataFetcher.fetching("desc"))
                    .build();
    

    三、DataFetchingEnvironment

    每个数据获取器都传递一个graphql.schema.DataFetchingEnvironment对象,使用该对象可以获取到当前正在获取的内容,以及相关的上下文信息。

    • T getSource():source对象用于获取field的信息。 它是获取parent field时请求到的返回值对象。 通常,它是存放于内存中的DTO对象,可以通过getter方法获取field的值。 在一些复杂场景中,可以通过该对象来获取当前请求的field相关的更详细的信息。 在对graphql请求树上的field发起请求时,每个请求field得到的返回值,都会作为该field下的子field的source对象。
    • T getRoot(): root对象是graphql查询中的初始数据。对于graphql查询树的根查询field,其source对象和root对象是同一个。 root对象在查询进行期间不可修改。
    • Map<String, Object> getArguments():表示在请求一个field时所需传递的变量参数。表示已在字段上提供的参数以及从传递的变量,GraphQL内部的AST常量或默认参数值。 在发起请求是,可以在field字段上附加参数arguments,来改变请求fields时的内部逻辑。
    • T getContext():context对象是初次执行查询时所设置的对象。在GraphQL查询的整个周期内,该对象保持唯一。 context对象上可以是任意值,通常用于为每个data fetcher提供获取field相应值所需的上下文信息。 例如,当前用户凭证或数据库连接参数可以附加在context对象中,以便data fetcher进行业务层调用。 在设计GraphQL的接口是,关键的权衡点之一就是如何使用context对象。 有些情况下,设计人员会依赖其他框架保存相关上下文信息,这种情况下就不需要使用GraphQL中的context对象。
    • ExecutionStepInfo getExecutionStepInfo():ExecutionStepInfo对象在GraphQL查询进行时创建,它包含了关于field的所有类型信息。
    • DataFetchingFieldSelectionSet getSelectionSet():SelectionSet表示在GraphQL查询树上,当前正在查询的field字段下的所有子查询字段。
    • ExecutionId getExecutionId():GraphQL的每一次查询都有一个唯一的执行id,可以用于日志记录当中。

    3.1 ExecutionStepInfo

    GraphQL 查询的过程当中,会创建一个field及其type的调用树。
    通过调用ExecutionStepInfo.getParentTypeInfo,你可以在调用树的当前节点上,向上一层进行遍历,并查看到有哪些父field或type,触发了当前field的执行。

    ExecutionStepInfo.getPath方法返回了一个树节点的path的表示。在日志中记录当前遍历的节点的path对于调试GraphQL的执行而言非常有用。

    还有一些辅助方法,可以对使用@Nonnull或List包装后的类型进行拆解,获取其内部的原始类型。(例如:@NonNull Person person或List,通过调用辅助方法, 可以获取到原始类型Person)

    3.2 DataFetchingFieldSelectionSet

    对于如下查询

        query {
            products {
                # the fields below represent the selection set
                name
                description
                sellingLocations {
                    state
                }
            }
        }
    

    products字段的子field(字段)表示该字段的selectionSet(选择集)。 提前获取到当前field 的子field在某些场景下非常有用,例如:可以通过提前获取当前field下的子field,来优化数据库访问的执行。例如,只请求当前field下的子选择集,而非查询当前表的所有字段,提升数据库访问性能。

  • 相关阅读:
    [Swift]LeetCode380. 常数时间插入、删除和获取随机元素 | Insert Delete GetRandom O(1)
    [Swift]LeetCode378. 有序矩阵中第K小的元素 | Kth Smallest Element in a Sorted Matrix
    说说心声------ 一些经历
    安装eclipse maven插件m2eclipse No repository found containing
    苹果浏览器实战(三)
    CSDN挑战编程——《绝对值最小》
    高可用技术工具包 High Availability Toolkit
    jstl 标签 循环 序号
    坚向的ViewPager,上下滑动的组件,android上下滑动 VerticalPager
    Php socket数据编码
  • 原文地址:https://www.cnblogs.com/pku-liuqiang/p/11502414.html
Copyright © 2020-2023  润新知