天天看點

Spring Boot + GraphQL 才是 API 的未來!

前言

在淺嘗GraphQL一文描述了GraphQL及基本使用,本文提供一個基本示例,描述如何基于spring boot的web項目快速應用。

graphql-java的官方文檔:Getting started with GraphQL Java and Spring Boot,提供了相關依賴用以快速配置,但是個人真心不建議使用這個庫及相關配置方式來搭建腳手架,在實際開發中,業務比較複雜的時候,會導緻需要配置的業務代碼比較多也比較繁瑣,相對下面這種方式,代碼複雜性比較高。

本文提供一種更靈活快捷的方式,在spring boot項目中快速應用開發。使用的依賴也和上面官方提供的都不一樣,請注意區分。

快速開始

建立spring boot工程

通過Spring Initializr快速搭建,我選的jdk版本及spring boot版本,如下所示,其它版本未做相容性測試。

Spring Boot + GraphQL 才是 API 的未來!
點選下方的Generate按鈕:
Spring Boot + GraphQL 才是 API 的未來!
打開工程結構如下,我将application.properties删除了替換成applicaiton.yml,因為我個人比較喜歡yaml的配置方式:
Spring Boot + GraphQL 才是 API 的未來!

引入相關依賴

pom.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.4.6</version>
  <relativePath/> <!-- lookup parent from repository -->
 </parent>
 <groupId>com.xuxd</groupId>
 <artifactId>graphql.demo</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <name>graphql.demo</name>
 <description>GraphQL Demo project for Spring Boot</description>
 <properties>
  <java.version>1.8</java.version>
  <maven.compiler.source>1.8</maven.compiler.source>
  <maven.compiler.target>1.8</maven.compiler.target>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <lombok.version>1.18.20</lombok.version>
  <graphql-java-tools.version>11.0.1</graphql-java-tools.version>
  <gson.version>2.8.7</gson.version>
 </properties>
 <dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter</artifactId>
  </dependency>

  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
  </dependency>

  <dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <version>${lombok.version}</version>
   <scope>provided</scope>
  </dependency>

  <dependency>
   <groupId>com.graphql-java-kickstart</groupId>
   <artifactId>graphql-java-tools</artifactId>
   <version>${graphql-java-tools.version}</version>
  </dependency>

  <dependency>
   <groupId>com.google.code.gson</groupId>
   <artifactId>gson</artifactId>
   <version>${gson.version}</version>
  </dependency>
 </dependencies>

 <build>
  <plugins>
   <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
   </plugin>
  </plugins>
 </build>

</project>      

初始化GraphQL執行個體

我們将建立一個GraphQL執行個體并将其注冊到spring容器中,代碼如下:

建立一個GraphQLProvider類:

@Component
public class GraphQLProvider {

    private GraphQL graphQL;

    @Autowired
    private IItemService itemService;

    @Bean
    public GraphQL graphQL() {
        return graphQL;
    }

    @PostConstruct
    public void init() throws IOException {
        GraphQLSchema graphQLSchema = SchemaParser.newParser()
            .file("graphql/base.graphqls")
            .resolvers(new Query(), new Mutation())
            .file("graphql/item.graphqls")
            .resolvers(new ItemResolver(itemService))
//            .file("book.graphqls")
//            .resolvers(new BookResolver())  //其它定義照上面的示例,繼續增加
            .build().makeExecutableSchema();

        this.graphQL = graphQL.newGraphQL(graphQLSchema).build();
    }

}      

關于

*.graphqls

或者對應的Resolver如ItemResolver,可以參看淺嘗GraphQL相關描述,這裡隻是作了微調整,相關代碼如下:

base.grqphqls

schema {
    # 查詢
    query: Query
    # 更新
    mutation: Mutation
}

type Query {
    version: String
}

type Mutation {
    version: String
}      

item.graphqls

# 定義一個查詢類型
extend type Query {
    queryItemList: ItemList  # 定義查詢項目清單
    queryById(id: ID): Item
}

extend type Mutation {
    updateName(param: Param): Item
}

# 定義項目字段
type Item {
    id: ID!
    code: String!
    name: String!
}

type ItemList {
    itemList: [Item!]!  #擷取項目清單
    total: Int!      # 擷取項目總數
}

input Param {
    id: ID!
    name: String!
}      

ItemResolver

public class ItemResolver implements GraphQLQueryResolver, GraphQLMutationResolver {

    private IItemService itemService;

    public ItemResolver(IItemService itemService) {
        this.itemService = itemService;
    }

    // 對應item.graphqls裡的queryItemList
    public ItemList queryItemList() {
        return itemService.queryItemList();
    }

    public Item queryById(Long id) {
        return itemService.queryById(id);
    }

    public Item updateName(Param param) {
        return itemService.updateName(param);
    }
}      

相關業務代碼比較多,就不一一貼了。

提供API

我們需要暴露一個接口來接收請求,并作相關處理,也隻需提供一個接口即可。是以我們建立一個Controller:GraphqlController.

@RestController
@RequestMapping("/graphql")
@Log
public class GraphqlController {

    @Autowired
    private GraphQL graphQL;

    @PostMapping
    public Object execute(@RequestBody GraphqlRequest request) {
        ExecutionInput executionInput = ExecutionInput.newExecutionInput()
            .query(request.getQuery())
            .variables(request.getVariables())
            .build();
        Map<String, Object> result = new HashMap<>();

        ExecutionResult executionResult = graphQL.execute(executionInput);
        List<GraphQLError> errors = executionResult.getErrors();

        if (errors != null && !errors.isEmpty()) {
            result.put("errors", errors);
            return result;
        }
        return executionResult.getData();
    }
}      

到這一步,其實基本功能都已配置完成,可以啟動項目進行相關測試了。

整個項目的代碼結構如下,我盡量用了一個比較正常的web項目結構(controller,service,dao等):

Spring Boot + GraphQL 才是 API 的未來!

測試

示例中總共提供了3個接口,兩個查詢一個更新,分别進行測試:

ItemList queryItemList();

Item queryById(Long id);

Item updateName(Param param);      

查詢所有項目清單(隻擷取每個項目的編碼和名稱,以及清單總數):

Spring Boot + GraphQL 才是 API 的未來!

根據ID查詢,擷取項目的id和名稱

Spring Boot + GraphQL 才是 API 的未來!

更新指定ID的項目名稱

我們項目Id為1編碼為test的項目修改為“java項目”

Spring Boot + GraphQL 才是 API 的未來!

再查詢一下,可以看到結果更新了:

Spring Boot + GraphQL 才是 API 的未來!

結束語

這樣整個項目的GraphQL相關的基本配置已經完成,可以進行業務開發了。