每一个graphql中定义的字段都有一个相关联的graphql.schema.DataFetcher。java
有些字段使用自定义的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类型中的每一个字段也同样。ide
Query.products字段的Data Fetcher可能很是复杂,包含从数据库中读取Product对象的操做。它使用一个可选的match参数,进而能够对products结果中的对象进行过滤。性能
其示例以下:fetch
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以及其余信息,例如字段的类型,父类型,查询根对象或查询上下文对象。优化
在上下文调用中,可使用上下文对象,在访问数据库时提供安全性验证。ui
有了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); } }
如上所述,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();
每一个数据获取器都传递一个graphql.schema.DataFetchingEnvironment对象,使用该对象能够获取到当前正在获取的内容,以及相关的上下文信息。
GraphQL 查询的过程中,会建立一个field及其type的调用树。
经过调用ExecutionStepInfo.getParentTypeInfo,你能够在调用树的当前节点上,向上一层进行遍历,并查看到有哪些父field或type,触发了当前field的执行。
ExecutionStepInfo.getPath方法返回了一个树节点的path的表示。在日志中记录当前遍历的节点的path对于调试GraphQL的执行而言很是有用。
还有一些辅助方法,能够对使用@Nonnull或List包装后的类型进行拆解,获取其内部的原始类型。(例如:@NonNull Person person或List
对于以下查询
query { products { # the fields below represent the selection set name description sellingLocations { state } } }
products字段的子field(字段)表示该字段的selectionSet(选择集)。 提早获取到当前field 的子field在某些场景下很是有用,例如:能够经过提早获取当前field下的子field,来优化数据库访问的执行。例如,只请求当前field下的子选择集,而非查询当前表的全部字段,提高数据库访问性能。