Spring Boot GraphQL 實戰 01_快速入門

Coder小黑發表於2020-12-21

hello,大家好,我是小黑,又和大家見面啦~

新開一個專題是關於 GraphQL 的相關內容,主要是通過 Spring Boot 來快速開發 GraphQL 應用,希望對剛接觸 GraphQL 的同學有所幫助。

專案 github 地址:https://github.com/shenjianeng/graphql-spring-boot-example

什麼是 GraphQL

先看一下官網的解釋:

https://graphql.org/

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.

https://graphql.cn/

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 相關依賴

graphql-spring-boot-starter 預設情況下會掃描 classpath 下所有的 graphqls 字尾檔案。

當然,我們也可以通過 application.properties 來配置修改相關屬性,本案例中,我們使用預設配置即可。

graphql.tools.schema-location-pattern 預設配置

編寫第一個 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 檔案中定義的獲取使用者列表查詢。

UserGraphQLQueryResolver詳解

使用 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

使用graphiql發起請求

https://github.com/graphql-java-kickstart/graphql-spring-boot 的幫助下,實現一個 graphql 服務就是這麼的簡單。

自定義 Servlet Mapping 地址

我們來看看客戶端發出的請求長什麼樣子:

curl

同時,我們可以通過 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());
    }
}

下圖清晰的描述了上述程式中相關元件的關係:

圖源:https://www.graphql-java.com/tutorials/getting-started-with-spring-boot/

下期預告

下期我們將使用 graphQL 來實現簡單的增刪改查和自定義標量型別。感謝大家的關注和閱讀~~

參考資料:

https://github.com/graphql-java-kickstart/graphql-spring-boot

https://graphql.org

https://www.graphql-java.com/tutorials/getting-started-with-spring-boot/

https://graphql.org/code/#java-kotlin

相關文章