1. 程式人生 > >spring-boot整合graphql入門教程

spring-boot整合graphql入門教程

本文介紹一個spring-boot + graphql, 是一個 graphql java 入門專案

graphql 到底是什麼

    graphql 是一種 API 查詢語言, 用於伺服器端執行按已定義型別系統的查詢. GraphQL 不與任何特定的資料庫或儲存引擎進行繫結, 而是由您的程式碼和資料支援.(官方描述)

    說白了 就是想要什麼, 就傳入什麼欄位, 也就會返回什麼欄位, 具體欄位處理是伺服器所提供, 而 graphql 並不會關心怎麼伺服器怎麼處理

例如:

    傳統的rest api:  /test/user/{id}  return { id, name, age } 是一成不變的,

    graphql:  findOneUser(id: xx)  return { id, name }  (注: 傳輸引數id, 指定返回欄位 id, name, 當然也可以寫{ name, age },完全取決於前端需求 )

graphql 的優勢

    graphql 大大減少了溝通成本, 避免每次了定義api欄位的多少問題, 前端自己選擇、組合想要的欄位, 生成資料, graphql 提供了GUI 可以很方便的測試, 書寫graphql語句, 檢視服務提供的 doc, 詳細資訊請看 https://graphql.cn/

專案構建

<parent>
    <groupId
>
org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.0.RELEASE</version> </parent>

大神們封裝的 spring-boot 依賴

<!-- graphql -->
<dependency>
    <groupId>com.graphql-java</groupId>
    <artifactId
>
graphql-spring-boot-starter</artifactId> <version>4.0.0</version> </dependency> <dependency> <groupId>com.graphql-java</groupId> <artifactId>graphql-java-tools</artifactId> <version>4.3.0</version> </dependency>

專案的目錄( 隨便分的包最後會附上鍊接程式碼):

root.graphqls 是graphql 服務入口定義:

type Query {
    findAllAuthors: [Author]!
    countAuthors: Long!
    findOneAuthor(id: Long!): Author

    findAllBooks: [Book]!
    countBooks: Long!
}
type Mutation {
    newAuthor(firstName: String!, lastName: String!) : Author!

    newBook(title: String!, isbn: String!, pageCount: Int, authorId: Long!) : Book!
    saveBook(input: BookInput!): Book!
    deleteBook(id: ID!) : Boolean
    updateBookPageCount(pageCount: Int!, id: Long!) : Book!
}

scheme.graphqls 則是 query/mutation 具體的 scheme 定義欄位、型別

type Author {
    id: Long!
    createdTime: String
    firstName: String
    lastName: String
    books: [Book]
}
input BookInput {
    title: String!
    isbn: String!
    pageCount: Int
    authorId: Long
}
type Book {
    id: Long!
    title: String!
    isbn: String!
    pageCount: Int
    author: Author
}

Query 是查詢入口,  Mutation則是修改入口

例: findOneAuthor 傳入一個long id, 返回一個 Author schema, 

graphql 入口定義了, 但這只是一個描述, 我們需要實現 query/mutation中的描述

例如:

public class Query implements GraphQLQueryResolver {
    private AuthorRepository authorRepository;
    private BookRepository bookRepository;

    public Author findOneAuthor(Long id) {
        Optional<Author> opt = authorRepository.findById(id);
        return opt.isPresent() ? opt.get() : null;
    }
    public List<Author> findAllAuthors() {
        return authorRepository.findAll();
    }
    public Long countAuthors() {
        return authorRepository.count();
    }
    public List<Book> findAllBooks() {
        return bookRepository.findAll();
    }
    public Long countBooks() {
        return bookRepository.count();
    }
}

實現了所有的 Query中的描述(必須全部實現)

schema 一樣像我的目錄中的一樣 AuthorResolver 這是對schema中的描述的實現

注: query/mutation和普通的schema 一樣, 只是它們是 graphql服務的入口, resolver實現描述遵循:

1. method <name>(*args)

2.method is<Name>(*args) 僅支援 return boolean

3.method get<Name>(*args)

4.method getField<Name>(*args)

這是種實現, 當提供了resolver時優先使用, 其次是 class this.get<Name>方法

Author.class 中的createdTime 是 Date, 然而 schema Author { createdTime: String }, 所以單獨提供AuthorResovler 生成createdTime String, 而其他引數因為與schema Author型別一致,使用Author中的Get方法足夠了

@Component
@AllArgsConstructor
public class AuthorResolver implements GraphQLResolver<Author> {

    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private BookRepository bookRepository;

    public String getCreatedTime(Author author) {
        return sdf.format(author.getCreatedTime());
    }
    public List<Book> getBooks(Author author) {
        return bookRepository.findByAuthorId(author.getId());
    }
}

執行指令碼: ./run.sh 啟動專案, graphql 的預設endpoint:  /graphql


graphql GUI, 方便的用來編寫測試 graphql 和 檢視當前服務提供了那些可用的方法, 像這樣:

demo 程式碼、GUI奉上: