你是否曾想過,除了 REST API 外,是否有更好的方法來為應用程式提取數據?在後端開發中,GraphQL 已經成為一個強大的替代方案,提供了一種更靈活和高效的數據提取方式。對於熟悉 Java 的開發人員來說,將 GraphQL 整合到現代後端可以打開通往可擴展和高性能 API 的大門,適用於各種用例。
本文將探討 GraphQL 和 REST 之間的主要差異,突出使用 GraphQL 進行數據提取的獨特優勢,並指導您通過實際範例在 Java 中實現 GraphQL API。
什麼是 GraphQL?
GraphQL 是用於 API 的查詢語言,以及執行這些查詢的運行時。與 REST 不同,固定端點返回預定義的數據,GraphQL 允許客戶端精確請求他們需要的數據。這種細粒度使得 GraphQL 對於複雜或數據密集型應用程式尤其高效。
GraphQL 方法的優勢:
- 細粒度數據提取:客戶端可以查詢僅姓名和職稱,而無需檢索像部門這樣的不必要字段。
- 嵌套查詢:在一個查詢中連同員工信息一起提取經理詳細信息。
- 基於模式的開發:模式作為合同,使得 API 演進更容易。
什麼是 REST API?
Representational State Transfer(REST)是一種用於構建API的架構風格。它使用標準的HTTP方法如GET、POST、PUT和DELETE來執行CRUD操作。REST以其簡單性和廣泛應用而聞名。
REST的局限性:
- 數據的過度或不足提取。
- 需要多個端點和版本控制來應對變化。
- 沒有內建的實時功能。
GraphQL與REST API:有何不同?
GraphQL和REST是兩種流行的構建API的方法,各有其優勢。雖然REST多年來一直是標準,但GraphQL在數據檢索和前後端團隊協作方面提供了更大的靈活性和效率。
主要區別
- 與使用多個端點並需要版本控制進行更改的REST不同,GraphQL將數據檢索整合到一個查詢中,減少了對版本控制的需求,因為客戶端指定了數據需求。
- 而REST使用HTTP狀態碼來指示成功或錯誤,GraphQL始終返回200 OK狀態並在響應主體中通知錯誤。
- GraphQL還通過訂閱支持實時更新,這一點不同於REST缺乏內建的實時支持。
- 儘管 REST 已經廣泛建立並擁有許多工具,但 GraphQL 的環境迅速增長,提供了像 GraphiQL 這樣強大的工具以便於開發。
- 最後,雖然 REST 使用標頭進行快取,但 GraphQL 由於動態查詢需要更先進的技術,但提供了像持久查詢這樣的選項,以便有效快取。
核心 GraphQL 概念
1. 架構定義語言 (SDL)
GraphQL 擁有自己的類型系統,用於定義 API 的架構。編寫架構的語法稱為架構定義語言 (SDL)。
2. 查詢 vs. 變更 vs. 訂閱查詢
- 查詢 用於從伺服器獲取數據。與使用多個固定端點的 REST 不同,GraphQL 使用單一端點,而客戶端在查詢中指定所需的數據,提供了靈活性。
- 變更 用於修改伺服器上的數據,例如創建、更新或刪除數據。它們允許客戶端將更改發送到後端,對於需要寫入數據的應用程式至關重要。
- 訂閱 通過在客戶端和伺服器之間保持穩定的連接來實現實時更新。當訂閱的事件發生時,伺服器會將更新推送到客戶端,提供持續的數據流,與遵循請求-回應循環的查詢和變更不同。
3. GraphQL 架構
它定義了可查詢或變異的資料結構,作為伺服器與用戶端之間的合約。它指定了客戶端可以存取的類型、欄位和關係。架構通常包括特殊的根類型:查詢用於檢索資料、變異用於修改資料,以及訂閱用於實時更新。這些類型共同定義了API的功能和客戶端如何與之互動。
4. 解析器:將 GraphQL 查詢映射到資料
解析器是處理在 GraphQL 伺服器中擷取資料邏輯的函數。架構中的每個欄位都連結到一個解析器,該解析器決定如何檢索或計算該欄位的資料。當執行查詢時,伺服器會為請求的欄位調用適當的解析器。解析器可以返回純量或物件,如果返回物件則繼續執行子欄位,如果返回純量則完成。如果返回 null,執行將停止。解析器對於將 GraphQL 查詢映射到實際資料來源至關重要。
在 Java 中使用 GraphQL 的好處
- 精確的資料擷取:僅查詢所需的資料,確保可預測且高效的結果。
- 單一請求獲取多個資源:在一個查詢中檢索相關資料,減少多個 API 呼叫。
- 類型系統:按類型和欄位組織 API,確保查詢有效且錯誤清晰。
- 開發人員工具:使用諸如 GraphiQL 之類的工具增強生產力,使用類型定義進行更好的查詢構建和調試。
- 無版本演進:添加或棄用字段而不破壞現有查詢,使API易於維護。
- 靈活的數據集成:創建一個統一的API,覆蓋現有數據和代碼,與各種存儲引擎和語言兼容。
在Java中設置GraphQL API
實際示例:用戶和訂單
假設您正在為一家大型組織構建員工目錄API。目標是允許客戶查詢員工姓名、職稱、部門,甚至他們的報告層級等詳細信息。
1. 設置項目
使用Spring Tool Suite創建一個新的Spring Boot項目,或者前往Spring Initialiser。然後,在pom.xml
文件中添加這些依賴項:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graphql</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.graphql</groupId>
<artifactId>spring-graphql-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2. 創建您的實體
創建Java實體(例如,User
和Order
),以表示將通過GraphQL查詢或變異的數據。例如:
public class User {
strategy = GenerationType.IDENTITY) (
private Long userId;
private String name;
private String email;
private String password;
// Getters and setters...
}
public class Order {
strategy = GenerationType.IDENTITY) (
private Long orderId;
private String orderDetails;
private String address;
private int price;
private User user;
// Getters and setters...
}
3. 創建存儲庫
創建與數據庫交互的存儲庫:
public interface UserRepository extends JpaRepository<User, Long> {}
public interface OrderRepository extends JpaRepository<Order, Long> {}
4. 創建服務類
創建服務類來處理業務邏輯:
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User createUser(User user) {
return userRepository.save(user);
}
public User getUser(Long userId) {
return userRepository.findById(userId).orElseThrow(() -> new RuntimeException("User not found"));
}
public List<User> getAllUsers() {
return userRepository.findAll();
}
public boolean deleteUser(Long userId) {
userRepository.deleteById(userId);
return true;
}
}
5. 創建 GraphQL 控制器
定義 GraphQL 控制器以處理查詢和變更:
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
public List<User> getUsers() {
return userService.getAllUsers();
}
public User getUser( Long userId) {
return userService.getUser(userId);
}
public User createUser( String name, String email, String password) {
User user = new User();
user.setName(name);
user.setEmail(email);
user.setPassword(password);
return userService.createUser(user);
}
public boolean deleteUser( Long userId) {
return userService.deleteUser(userId);
}
}
6. 定義您的 GraphQL 架構
在 src/main/resources
目錄中創建一個 schema.graphqls
文件:
type User {
userId: ID!
name: String
email: String
password: String
}
type Query {
getUsers: [User]
getUser(userId: ID!): User
}
type Mutation {
createUser(name: String, email: String, password: String): User
deleteUser(userId: ID!): Boolean
}
7. 在 application.properties 中配置 GraphQL
可選地,在 scr/main/resources/application.properties
中配置 GraphQL 設置:
spring.graphql.graphiql.enabled=true
8. 運行應用程式
使用 mvn spring-boot:run
或從您的 IDE 運行 SpringBoot 應用程式。一旦運行,您可以在 /graphiql
訪問 GraphAL 端點。
9. 使用 GraphQL 查詢進行測試
使用像 GraphiQL 或 Postman 這樣的工具測試 GraphQL API。
對於 Mutation:
mutation {
createUser(
name:"swetha",
email:"[email protected]",
password:"23sde4dfg43"
){
name,
userId
}
}
輸出:
{
"data": {
"createUser": {
"name": "swetha",
"userId": "3"
}
}
}
對於 Query:
query{
getUsers{
name
}
}
輸出:
{
"data": {
"getUsers": [
{
"name": "Medha"
},
{
"name": "Riya"
},
{
"name": "swetha"
}
]
}
}
高級 GraphQL 功能
1. 通過 Fragments 增強重用性
片段基本上是為特定類型定義的可重用字段集。這是一個有助於改善您的 GraphQL 代碼結構和重用性的功能。
2. 使用參數化字段。
在GraphQL中,字段可以接受参数,使查询更具动态性和灵活性。这些参数允许您过滤或自定义API返回的数据。
3. 使用GraphQL进行分页和排序
分页
分页在API设计中是一个棘手的话题。从高层次来看,有两种主要方法来处理它。
- 限制-偏移:通过提供要检索的项目的索引来请求列表的特定块(实际上,您主要提供开始索引(偏移)以及要检索的项目数量(限制)。
- 基于游标:这种分页模型稍微更高级一些。列表中的每个元素都与一个唯一ID(游标)相关联。然后,浏览列表的客户端提供起始元素的游标以及要检索的项目数量。
排序
使用GraphQL API设计,可以返回根据特定标准排序的元素列表。
使用GraphQL的挑战和考虑
- 复杂性:管理GraphQL模式和查询对于简单的数据模型或经验不足的团队可能具有挑战性。
- 性能问题:深度嵌套的查询如果没有经过优化,可能会给后端资源带来压力。
- 缓存挑战:标准的基于REST的缓存策略不适用,需要定制解决方案。
- 安全性考量:過度抓取和惡意查詢需要查詢限制和其他防護措施。
- 混合使用:最適合複雜數據需求,通常與REST結合進行更簡單的操作。
結論
GraphQL提供了一種靈活且高效的方法來構建現代API,特別是在Java中,使其成為動態和數據密集型應用程序的理想選擇。它的單一端點架構和強類型簡化了API設計,同時確保了穩健的性能。無論您是在創建簡單的員工名錄還是複雜的分析平台,GraphQL都使開發者能輕鬆交付可擴展的解決方案。今天就開始探索GraphQL,使用Spring Boot和graphql-java
等工具,以在您的下一個項目中發揮其全部潛力。
源代碼
您可以在Github上找到本教程的完整源代碼。
Source:
https://dzone.com/articles/design-scalable-java-apis-with-graphql