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 和 檢視當前服務提供了那些可用的方法, 像這樣: