每一個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下的子選擇集,而非查詢當前表的全部字段,提高數據庫訪問性能。