GraphQL 介紹
GraphQL 既是一種用于 API 的查詢語言也是一個滿足你數(shù)據(jù)查詢的運(yùn)行時誉尖。 GraphQL 對你的 API 中的數(shù)據(jù)提供了一套易于理解的完整描述狞山,使得客戶端能夠準(zhǔn)確地獲得它需要的數(shù)據(jù)壶辜,而且沒有任何冗余,也讓 API 更容易地隨著時間推移而演進(jìn),還能用于構(gòu)建強(qiáng)大的開發(fā)者工具。
基于node的服務(wù)端開發(fā)中眼姐,GraphQL技術(shù)較為成熟常用,在基于Java
的服務(wù)端開發(fā)中佩番,由于國內(nèi)對該API標(biāo)準(zhǔn)的了解程度不高众旗,以及引入GraphQL可能需要維護(hù)兩份重復(fù)數(shù)據(jù)(schema和相應(yīng)java代碼實(shí)現(xiàn))。
開始
本文旨在從Java服務(wù)端開發(fā)的角度趟畏,介紹GraphQL的落地實(shí)踐贡歧。根據(jù)官網(wǎng)的示例:GraphQL Java和Spring Boot入門 ,遺憾是使用Gradle
構(gòu)建赋秀。本文使用Maven方式構(gòu)建SpringBoot
的一般方式利朵。根據(jù)官網(wǎng)的示例,基本能了解一些執(zhí)行方式猎莲。
使用依賴為本文發(fā)布時間最新版本v14,另外使用mvc
做url
地址映射/graphql
作為請求入口绍弟。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java</artifactId>
<version>14.0</version>
</dependency>
</dependencies>
GraphQL 實(shí)例
官網(wǎng)推薦SDL
的寫法,也可以使用Java語句編寫著洼,如果你喜歡樟遣。?*.graphql
的文件放置在src/main/resources
目錄下,通過讀取文件并對其進(jìn)行解析身笤。通過引用聲明Bean實(shí)例 GraphQL
到全局年碘,就完成數(shù)據(jù)查詢構(gòu)建。
總體上展鸡,創(chuàng)建GraphQL和GraphQLSchema實(shí)例的過程如下所示:
RuntimeWiring
內(nèi)編寫執(zhí)行函數(shù)數(shù)據(jù)返回DataFetcher
類型屿衅,進(jìn)行解析選擇字段的函數(shù)。
/**
* 輸出world
* qurey { hello }
* @return 返回字符串
*/
public DataFetcher getHelloWorldDataFetcher() {
return dataFetchingEnvironment -> "world";
}
主要編寫代碼如下:
@Bean
public GraphQL graphQL() throws IOException {
// SDL讀取查詢類型文件莹弊,new SchemaParser().parse(?)解析File涤久、InputStream、String
// ClassPathResource classPathResource = new ClassPathResource("schema.graphql");
// TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(classPathResource.getInputStream());
// 多SDL文件注冊
// ClassPathResource UserSchema = new ClassPathResource("schema/UserSchema.graphql");
// ClassPathResource schema = new ClassPathResource("schema/QuerySchema.graphql");
// TypeDefinitionRegistry typeRegistry = new TypeDefinitionRegistry();
// SchemaParser schemaParser = new SchemaParser();
// typeRegistry.merge(schemaParser.parse(UserSchema.getInputStream()));
// typeRegistry.merge(schemaParser.parse(schema.getInputStream()));
// 遍歷解析目錄下的schema忍弛,沒找到直接獲取文件列表的方法
TypeDefinitionRegistry typeRegistry = new TypeDefinitionRegistry();
SchemaParser schemaParser = new SchemaParser();
String[] schemaArr = {"UserSchema", "QuerySchema", "MutationSchema"};
for (String str : schemaArr) {
typeRegistry.merge(schemaParser.parse(new ClassPathResource("schema/" + str + ".graphql").getInputStream()));
}
RuntimeWiring runtimeWiring = buildWiring(); // 數(shù)據(jù)方法對應(yīng)編寫
SchemaGenerator schemaGenerator = new SchemaGenerator(); // 查詢器構(gòu)建
// 查詢生成
GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring);
return GraphQL.newGraphQL(graphQLSchema).build();
}
/**
* 數(shù)據(jù)類型方法對應(yīng)編寫
*
* @return RuntimeWiring對應(yīng)執(zhí)行方法
*/
private RuntimeWiring buildWiring() {
return RuntimeWiring.newRuntimeWiring()
// 查詢方法R/get
.type("Query", builderFunction -> builderFunction
.dataFetcher("hello", graphQLDataFetchers.getHelloWorldDataFetcher())
.dataFetcher("echo", graphQLDataFetchers.getEchoDataFetcher())
.dataFetcher("users", userDataFetcher.getUsersDataFetcher())
.dataFetcher("user", userDataFetcher.getUserByIdDataFetcher())
)
// 級聯(lián)字段關(guān)聯(lián)查詢
.type("User", builderFunction -> builderFunction.dataFetcher("info", userDataFetcher.getInfoDataFetcher()))
// 增改刪方法CUD/post/put/del
.type("Mutation", builderFunction -> builderFunction
.dataFetcher("createUser", userDataFetcher.createUserDataFetcher())
.dataFetcher("updateUser", userDataFetcher.updateUserDataFetcher())
.dataFetcher("deleteUser", userDataFetcher.deleteUserDataFetcher())
)
.build();
}
執(zhí)行方法
在controller中編寫URL入口/graphql
,進(jìn)行支持get
响迂、post
兩種請求方式,將得到的參數(shù)數(shù)據(jù)進(jìn)行處理后细疚,使用graphQL執(zhí)行查詢器蔗彤。可能很多人想處理錯誤和json輸出的,請閱讀官方對執(zhí)行的更多操作方法然遏。
/**
* 執(zhí)行g(shù)raphQL查詢
*
* @param query 查詢語句-類json字符
* @param operationName 查詢操作名稱-默認(rèn)空字符
* @param variables 查詢參數(shù)變量-map對象贫途、默認(rèn)為空map
* @return map對象
*/
private Map<String, Object> executeGraphqlQuery(String query, String operationName, Map<String, Object> variables) {
ExecutionInput executionInput = ExecutionInput.newExecutionInput()
.query(query)
.operationName(operationName)
.variables(variables)
.build();
return graphql.execute(executionInput).toSpecification();
}
最后
示例項(xiàng)目使用springboot
與maven
方式構(gòu)建,微服務(wù)采用restful
和graphql
兩種方式進(jìn)行開發(fā)待侵,兩者相輔相成丢早,比如:上傳、websocket等一些接口混用的模式秧倾。
示例代碼:GitHub
springboot
構(gòu)建版本:2.2.2.RELEASE
怨酝,建議改為你目前使用的版本,避免再次下載那先。