在不傳回資料的情況下實作 GraphQL 變更
一、簡介
GraphQL 是一種強大的 API 查詢語言,提供了一種靈活且有效率的方式與資料互動。處理突變時,通常會對伺服器上的資料執行更新或新增。然而,在某些情況下,我們可能需要在不返回任何數據的情況下進行變異。
在 GraphQL 中,預設行為是強制模式中的欄位不可為空,這表示欄位必須始終傳回一個值且不能為空,除非明確標記為可為空。雖然這種嚴格性有助於 API 的清晰度和可預測性,但在某些情況下可能需要傳回 null。但是,通常認為避免傳回空值的最佳實務。
在本文中,我們將探索在不檢索或傳回特定資訊的情況下實現 GraphQL 突變的技術。
2. 前提條件
對於我們的範例,我們需要以下依賴項:
<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>
Spring Boot GraphQL Starter為快速設定 GraphQL 伺服器提供了絕佳的解決方案。透過利用自動配置並採用基於註解的程式設計方法,我們只需專注於為我們的服務編寫基本程式碼。
我們已將Web 啟動器包含在我們的設定中,因為 GraphQL 與傳輸無關。這利用 Spring MVC 透過 HTTP 公開 GraphQL API。我們可以透過預設的/graphql
端點來存取它。我們也可以使用其他啟動器(例如 Spring Webflux)來實現不同的底層實作。
3. 使用可空類型
與某些程式語言不同,GraphQL 要求模式中的每個欄位都明確聲明可為空性。這種方法提高了清晰度,使我們能夠傳達某個欄位何時可能缺乏價值。
3.1.編寫架構
Spring Boot GraphQL 啟動器會自動在src/main/resources/graphql/**
位置下定位 GraphQL Schema 檔案。它基於它們建立正確的結構,並將特殊的 bean 連接到該結構。
我們將首先建立schema.graphqls
文件,並為我們的範例定義架構:
type Post {
id: ID
title: String
text: String
category: String
author: String
}
type Mutation {
createPostReturnNullableType(title: String!, text: String!, category: String!, authorId: String!) : Int
}
我們將有一個Post
實體和一個突變來創建新帖子。此外,為了讓我們的模式通過驗證,它必須有一個查詢。因此,我們將實作一個傳回貼文清單的虛擬查詢:
type Query {
recentPosts(count: Int, offset: Int): [Post]!
}
3.2.使用 Bean 表示類型
在 GraphQL 伺服器中,每個複雜類型都與一個 Java bean 關聯。這些關聯是根據物件和屬性名稱建立的。話雖這麼說,我們將為我們的帖子創建一個 POJO 類:
public class Post {
private String id;
private String title;
private String text;
private String category;
private String author;
// getters, setters, constructor
}
Java bean 上未對應的欄位或方法會在 GraphQL 模式中被忽略,不會造成任何問題。
3.3.創建突變解析器
我們必須使用 @MutationMapping 標籤來標記處理函數。這些方法應該放置在我們應用程式中的常規@Controller
元件中,將這些類別註冊為我們的 GraphQL 應用程式中的資料修改元件:
@Controller
public class PostController {
List<Post> posts = new ArrayList<>();
@MutationMapping
public Integer createPost(@Argument String title, @Argument String text, @Argument String category, @Argument String author) {
Post post = new Post();
post.setId(UUID.randomUUID().toString());
post.setTitle(title);
post.setText(text);
post.setCategory(category);
post.setAuthor(author);
posts.add(post);
return null;
}
}
我們必須根據模式中的屬性使用@Argument
註解方法的參數。在聲明模式時,我們確定我們的突變將返回Int
類型,不帶感嘆號。這允許傳回值為null
。
4. 建立自訂標量
在 GraphQL 中,標量是表示 GraphQL 查詢或模式中的葉節點的原子資料型態。
4.1.標量和擴展標量
根據GraphQL 規範,所有實作都必須包含以下標量類型: String
、 Boolean
、 Int
、 Float
或ID
。除此之外, graphql-java-extended-scalars增加了更多客製化標量,例如Long
、 BigDecimal
或LocalDate.
然而,原始標量集和擴展標量集都沒有一個特殊的null
值。**因此,我們將在本節中建立標量。**
4.2.建立自訂標量
要建立自訂標量,我們應該初始化GraphQLScalarType
單例實例。我們將利用 Builder 設計模式來創建標量:
public class GraphQLVoidScalar {
public static final GraphQLScalarType Void = GraphQLScalarType.newScalar()
.name("Void")
.description("A custom scalar that represents the null value")
.coercing(new Coercing() {
@Override
public Object serialize(Object dataFetcherResult) {
return null;
}
@Override
public Object parseValue(Object input) {
return null;
}
@Override
public Object parseLiteral(Object input) {
return null;
}
})
.build();
}
標量的關鍵組成部分是名稱、描述和強制。儘管名稱和描述是不言自明的,但創建自訂標量的困難部分是graphql.schema.Coercing
實作。此類別負責三個功能:
-
parseValue()
:接受變數輸入物件並將其轉換為對應的 Java 運行時表示形式 -
parseLiteral()
:接收 AST 文字graphql.language.Value
作為輸入並將其轉換為 Java 運行時表示 -
serialize()
:接受 Java 物件並將其轉換為該標量的輸出形狀
儘管對於複雜物件來說,強制的實作可能相當複雜,但在我們的例子中,我們將為每個方法傳回null
。
4.3.註冊自訂標量
我們首先建立一個配置類,在其中註冊標量:
@Configuration
public class GraphQlConfig {
@Bean
public RuntimeWiringConfigurer runtimeWiringConfigurer() {
return wiringBuilder -> wiringBuilder.scalar(GraphQLVoidScalar.Void);
}
}
我們建立一個RuntimeWiringConfigurer
bean,在其中為GraphQL
模式配置運行時連接。在此 bean 中,我們使用RuntimeWiring
類別提供的scalar()
方法來註冊自訂類型。
4.4.整合自訂標量
最後一步是透過使用定義的名稱來引用自訂標量,將其整合到我們的 GraphQL 模式中。在本例中,我們透過簡單地聲明scalar Void
來使用模式中的標量。
此步驟可確保 GraphQL 引擎在整個模式中識別並利用我們的自訂標量。現在,我們可以將標量整合到我們的突變中:
scalar Void
type Mutation {
createPostReturnCustomScalar(title: String!, text: String!, category: String!, authorId: String!) : Void
}
此外,我們將更新映射的方法簽章以傳回標量:
public Void createPostReturnCustomScalar(@Argument String title, @Argument String text, @Argument String category, @Argument String author)
5. 結論
在本文中,我們探索了在不返回特定數據的情況下實現 GraphQL 突變。我們示範了使用 Spring Boot GraphQL Starter 快速設定伺服器。此外,我們引入了一個自訂Void
標量來處理null
值,展示如何擴展 GraphQL 的功能。
與往常一樣,完整的程式碼片段可以 在 GitHub 上找到。