hello,大家好,我是小黑,又和大家見面啦~
新開一個專題是關於 GraphQL 的相關內容,主要是通過 Spring Boot 來快速開發 GraphQL 應用,希望對剛接觸 GraphQL 的同學有所幫助。
專案 github 地址:https://github.com/shenjianeng/graphql-spring-boot-example
什麼是 GraphQL
先看一下官網的解釋:
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.
GraphQL 既是一種用於 API 的查詢語言也是一個滿足你資料查詢的執行時。 GraphQL 對你的 API 中的資料提供了一套易於理解的完整描述,使得客戶端能夠準確地獲得它需要的資料,而且沒有任何冗餘,也讓 API 更容易地隨著時間推移而演進,還能用於構建強大的開發者工具。
再看一下維基百科的解釋:
https://en.wikipedia.org/wiki/GraphQL
GraphQL is an open-source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data.GraphQL was developed internally by Facebook in 2012 before being publicly released in 2015.
It allows clients to define the structure of the data required, and the same structure of the data is returned from the server.
GraphQL 是一種用於 api 的開源資料查詢和操作語言,也是一種用於實現現有資料查詢的執行時。GraphQL 於2012年由 Facebook內部開發,2015年公開發布。
它允許客戶端定義所需資料的結構,並從伺服器返回相同的資料結構。
從字面上理解:GraphQL = Graph + QL = 圖表化、視覺化的查詢語言。它允許客戶端定義所需資料的結構,並從伺服器返回相同的資料結構。
Hello world
GraphQL 是一種規範,已有多種程式語言支援。
在本系列文章中,我們使用 graphql-spring-boot-starter 來完成 GraphQL 相關開發講解。
github 地址:https://github.com/graphql-java-kickstart/graphql-spring-boot
引入相關依賴
構建一個基礎的 Spring Boot Web 專案工程,引入最新的 graphql-spring-boot-starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>8.0.0</version>
</dependency>
通過 maven 我們可以很清楚的看到 graphql-spring-boot-starter 引入了哪些依賴包:
graphql-spring-boot-starter 預設情況下會掃描 classpath 下所有的 graphqls 字尾檔案。
當然,我們也可以通過 application.properties
來配置修改相關屬性,本案例中,我們使用預設配置即可。
編寫第一個 graphqls 檔案
在 resources 資料夾下新建 schema.graphqls 檔案。
如果你在使用 idea 的話,可以安裝 https://plugins.jetbrains.com/plugin/8097-js-graphql 外掛來幫助你編寫 graphqls 檔案。
# 表示構建一個 user 資料結構
type User{
# id,型別就是 ID ,! 表示是必填欄位
id:ID!
# username 欄位,String 型別
username:String!
nickname:String!
# city 欄位,型別是 City 列舉
city:City
}
# City 列舉值
enum City{
hangzhou
shanghai
}
# 查詢相關介面
type Query{
# 獲取使用者列表,返回 user 陣列
userList:[User!]
}
上述 schema.graphqls 檔案中定義了 User 和 City 這兩種資料型別。同時,我們生成兩個 Java Bean 來與之相對應。
public enum City {
hangzhou,
shanghai,
}
@Data
public class User {
private UUID id;
private String username;
private String nickname;
private City city;
}
定義 GraphQLQueryResolver
@Component
public class UserGraphQLQueryResolver implements GraphQLQueryResolver {
public Collection<User> userList() {
User user1 = new User();
user1.setId(UUID.randomUUID());
user1.setUsername("coder小黑");
user1.setNickname("coder小黑沒有暱稱");
user1.setCity(City.hangzhou);
User user2 = new User();
user2.setId(UUID.randomUUID());
user2.setUsername("今晚打老虎");
user2.setNickname("愛老虎油");
user2.setCity(City.shanghai);
return Arrays.asList(user1, user2);
}
}
- 定義了一個 Spring Beran
UserGraphQLQueryResolver
,實現了graphql.kickstart.tools.GraphQLQueryResolver
介面 - 有一個名為
userList
的方法,方法不需要入參,返回Collection<User>
沒錯,聰明的讀者同學是不是已經發現了:
UserGraphQLQueryResolver#userList
就是用來匹配 schema.graphqls 檔案中定義的獲取使用者列表查詢。
使用 graphiql 請求伺服器
graphiql 可以幫助我們方便的向 graphql 服務端發起請求,使用也十分簡單,引入相關依賴即可。
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphiql-spring-boot-starter</artifactId>
<version>8.0.0</version>
<scope>runtime</scope>
</dependency>
好,讓我們啟動 Spring Boot 應用,訪問 http://localhost:8080/graphiql
在 https://github.com/graphql-java-kickstart/graphql-spring-boot 的幫助下,實現一個 graphql 服務就是這麼的簡單。
自定義 Servlet Mapping 地址
我們來看看客戶端發出的請求長什麼樣子:
同時,我們可以通過 application.properties
檔案來修改服務端的請求接收路徑:
graphql.servlet.mapping=/coder-xiao-hei
使用原生 GraphQL 實現
下面,我們再使用 GraphQL 的原生 api 來實現一下上述的案例。
public class HelloWorld {
static Collection<User> userList() {
User user1 = new User();
user1.setId(UUID.randomUUID());
user1.setUsername("coder小黑");
user1.setNickname("coder小黑沒有暱稱");
user1.setCity(City.hangzhou);
return Collections.singletonList(user1);
}
public static void main(String[] args) throws IOException {
Resource resource = new DefaultResourceLoader().getResource("classpath:schema.graphqls");
String schema = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
SchemaParser schemaParser = new SchemaParser();
TypeDefinitionRegistry typeDefinitionRegistry = schemaParser.parse(schema);
RuntimeWiring runtimeWiring =
RuntimeWiring.newRuntimeWiring()
.type(TypeRuntimeWiring
.newTypeWiring("Query")
.dataFetcher("userList",
(DataFetcher<Collection<User>>) environment -> userList()))
.build();
SchemaGenerator schemaGenerator = new SchemaGenerator();
GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring);
GraphQL build = GraphQL.newGraphQL(graphQLSchema).build();
ExecutionResult executionResult = build.execute("query{\n" +
" userList{\n" +
" id\n" +
" username\n" +
" }\n" +
"}");
// {userList=[{id=486a181e-eec7-4001-a9d9-65e94a004f8c, username=coder小黑}]}
System.out.println(executionResult.getData().toString());
}
}
下圖清晰的描述了上述程式中相關元件的關係:
下期預告
下期我們將使用 graphQL 來實現簡單的增刪改查和自定義標量型別。感謝大家的關注和閱讀~~
參考資料:
https://github.com/graphql-java-kickstart/graphql-spring-boot
https://www.graphql-java.com/tutorials/getting-started-with-spring-boot/