Spring Boot和Netflix DGS的GraphQL原始碼案例

發表於2021-04-28

Netflix Domain Graph Service(DGS)是在Netflix內部建立的一個新的開放原始碼框架,該框架簡化並幫助了使用GraphQL實施Spring Boot應用程式。

DGS的特徵:

  • 它是一個基於Spring Boot樣式的註釋的系統。
  • 與Spring Security整合。
  • 錯誤管理。
  • 適用於Java的GraphQL客戶端。
  • 支援WebSockets,SSE,檔案上傳或GraphQL Federation。

Netflix的域圖服務(DGS)框架極大地促進了帶有Spring Boot的GraphQL的開發,從而能夠以更簡單的方式構建任何API。由於GraphQL的適應性和靈活性以及其他特性,它被定位為Rest的廣泛使用的替代方法,因此使用GraphQL的頻率越來越高。

 

案例說明

完整的示例在github上

這個示例中,將使用帶有H2的記憶體關聯式資料庫,以簡化使用JPA的示例。我們的示例將由三個非常基本的實體組成:銀行,使用者和帳戶銀行,其中使用者在銀行中有一個或N個銀行帳戶,而一個銀行有1個或N個銀行帳戶。

在我們的應用程式中,使用Lombok簡化刪除Java樣板。

 

新增依賴:

<dependency>
   <groupId>com.netflix.graphql.dgs</groupId>
   <artifactId>graphql-dgs-spring-boot-starter</artifactId>
   <version>${netflix-dgs.version}</version>
</dependency>

有必要為我們的應用程式新增更多的依賴項。

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <scope>runtime</scope>
</dependency>

 

建立GraphQL的Schema

與建立關聯式資料庫的表結構一樣,我們將對GraphQL進行相同的操作,即建立schema。我們建立的必須位於以下路徑/ src / main / resources / schema中,並且在此路徑中,Netflix DGS將負責載入模式。

對於每個模式,我們建立了一個副檔名為graphqls的不同檔案。其中有一個QueryResolver型別,它將具有兩個不同的搜尋,以及一個MutationResolver以便能夠在資料庫中建立物件。

建立3個不同的方案,帳戶,使用者和銀行:

type QueryResolver {
    users: [User]
    user(id: ID!): User!
}

type MutationResolver {
    createUser(user: UserInput!): User
}

input UserInput {
    firstName: String!
    lastName: String!
    address: String!
    country: String!
    city: String!
    age: Int
}

type User {
    id: ID!
    firstName: String!
    lastName: String!
    address: String!
    country: String!
    city: String!
    age: Int!
    bank: Bank
    accounts: [Account]
}

schema {
    query: QueryResolver
    mutation: MutationResolver
}

  

在Spring Boot中建立實體

接下來,我們將建立負責對映關聯式資料庫和GraphQL模式的實體。

@Entity
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class User {

    @Id
    @GeneratedValue
    private UUID id;

    private String firstName;

    private String lastName;

    private int age;

    private String address;

    private String country;

    private String city;

    @OneToMany(mappedBy = "user")
    private Set<Account> accounts;

    @ManyToOne()
    private Bank bank;
}

 

建立變化物件

如前所述,我們已經為每個架構建立了一個MutationResolver型別,因此我們需要建立一個新的物件,並傳遞該物件來建立它。也就是說,它將是與之進行繫結的物件,當進行請求和呼叫時,它將具有與我們在模式中輸入的名稱相同的名稱。

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class UserInput {

    private String firstName;

    private String lastName;

    private int age;

    private String address;

    private String country;

    private String city;
}

  

使用Spring Boot建立儲存庫

對於永續性或儲存庫層,我們將使用JpaRepository,它將為我們提供所有JPA工具,使其能夠儲存和查詢我們的資料庫物件。

例如,對於“帳戶”,如下所示:

public interface AccountRepository extends JpaRepository<Account, UUID> {
}

 

Spring Boot的Netflix DGS

Netflix已經建立了它的基於註釋的DGS框架,該框架由Spring Boot支援。下面我們展示了要使應用程式與GrpahQL和Spring Boot一起執行時要考慮的基本註釋。

  • @DgsComponent:此批註負責指示類將要執行查詢。該類應在定義中帶有此註釋。
  • @DgsData,每個帶有邏輯以執行查詢的方法都必須使用@DgsData進行註釋。我們將在其中新增父型別的位置,這是架構的型別以及在架構中定義的欄位。
  • @InputArgument,用於定義在查詢中作為引數傳遞的引數。
  • @DgsQuery,是parentType為query時@DgsData的縮寫。
  • @DgsMutation,是parentType為Mutation時@DgsData的縮寫。

使用DGS時要記住的另一個問題是能夠通過實現DgsCustomContextBuilder類來建立自己的上下文。您可以使用它來記錄或儲存狀態,或儲存一些通過DataFetchingEnvironment類訪問的資訊。在示例類UserQuery中,您可以看到其用法。

 

在Spring Boot中使用Netflix DGS查詢

Netflix DGS的查詢類使用了我們上面提到的一些註釋:

@DgsComponent
@RequiredArgsConstructor
public class UserQuery {

    private final UserRepository userRepository;

    private final CustomContextBuilder contextBuilder;


    @DgsData(parentType = "QueryResolver", field = "users")
    public Iterable<User> findAll(DgsDataFetchingEnvironment dfe) {

        var users = (List<User>) userRepository.findAll();

        contextBuilder.customContext(users, null, null).build();

        return users;
    }

    @DgsData(parentType = "QueryResolver", field = "user")
    public User findById(@InputArgument("id") String id, DataFetchingEnvironment dfe) {

        CustomContext customContext = DgsContext.getCustomContext(dfe);

        var users = customContext.getUsers();


        if (null != users) {
            var user = users.stream().filter(u -> u.getId().equals(UUID.fromString(id))).findFirst();

            return user.orElseGet(() -> userRepository.findById(UUID.fromString(id)).orElseThrow(DgsEntityNotFoundException::new));

        } else {

            return userRepository.findById(UUID.fromString(id)).orElseThrow(DgsEntityNotFoundException::new);
        }

    }
}

該類的一個亮點是CustomContextBuilder的使用,該類建立了自己的上下文,在該上下文中新增了不同的返回物件,然後可以直接對其進行訪問。

 

在Spring Boot中使用Netflix DGS進行更改

接下來,我們將看到UserMutation類,該類負責在資料庫中儲存新使用者。

如您在@DgsData中所看到的,我們首先指示parentType是MutationResolver,欄位是createUser,它與模式中的定義匹配。

@DgsComponent
@RequiredArgsConstructor
public class UserMutation {

    private final UserRepository userRepository;

    @DgsData(parentType = "MutationResolver", field = "createUser")
    public User createUser(@InputArgument("user") UserInput user) {
        return userRepository.save(new User(null, user.getFirstName(), user.getLastName(), user.getAge(), user.getAddress(), user.getCountry(), user.getCity(), null, null));
    }

}
 

使用Spring Boot測試Netflix DGS應用程式

完成應用程式並全部實現後,就可以啟動一些查詢了。

我們使用以下命令執行我們的應用程式:mvn spring-boot:run

我們訪問頁面 http://localhost:8080/graphiql,然後會出現一個介面,我們可以在其中啟動查詢。

 

相關文章