解決什麼問題
根據請求控制傳回結果
例如: 一個User對象,有id,name,mobile,email
有些接口隻要傳回id,name ,有些接口還要要傳回 mobile
适用場景
- 弱文檔管理,公司對文檔要求不高
- 需求複雜變化快
- 單資源多種通路方式,元件複用
- 複雜API 還是restful好
開發流程
1.設計領域對象
2.定義GraphQL Schema
3.定義DataFetcher(實作資料通路層元件)
4.完成Data Wiring(GraphQlSourceBuilderCustomizer,舊版本RuntimeWiringBuilderCustomizer)
5.開啟graph配置或者自己實作Controller
spring.graphql.schema.printer.enabled=true
spring.graphql.path=/wenl/query
GraphQL Server執行個體
前提
spring boot 2.7+,JDK1.8,maven 3.5+
maven pom如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.13-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graphql</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.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.graphql</groupId>
<artifactId>spring-graphql-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.1.0</version>
</plugin>
</plugins>
</build>
設計領域對象
@Data
public class Author {
private Long id;
private String firstName;
private String lastName;
}
@Data
@NoArgsConstructor
public class Book {
private String id;
private String name;
private int pageCount;
private Author author;
public static List<Book> books = Arrays.asList(
new Book("book-1", "Effective Java", 416, "author-1"),
new Book("book-2", "Hitchhiker's Guide to the Galaxy",
208, "author-2"),
new Book("book-3", "Down Under", 436, "author-3")
);
public Book(String id, String name, int pageCount, String authorName) {
this.id = id;
this.name = name;
this.pageCount = pageCount;
Author author = new Author();
author.setFirstName(authorName);
author.setLastName("lastName");
this.author=author;
}
}
定義GraphQL Schema
檔案位置固定檔案名固定,resources/graphql/schema.graphqls
schema {
query : Query
}
type Query {
books: [Book]
bookById(id: String,name: String ): Book
}
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}
schema 是固定寫法
type Query 内部是對應的查詢方法。
books: [Book] 表示方法名稱為books(client需要配置) ,傳回的是list
bookById(id: String,name: String ): Book 這裡傳回單個Book,id,name是參數
其他的type 是傳回值的類。
定義DataFetcher(實作資料通路層元件)
@Component
public class BookDataFetcher implements DataFetcher<Book> {
@Override
public Book get(DataFetchingEnvironment dataFetchingEnvironment) throws Exception {
String id = (String) dataFetchingEnvironment
.getArguments().get("id");
String name = (String) dataFetchingEnvironment
.getArguments().get("name");
return Book.books.stream()
.filter(book ->
book.getId().equals(id)&&book.getName().equals(name))
.findFirst().orElse(null);
}
}
@Component
public class BooksDataFetcher implements DataFetcher<List<Book>> {
@Override
public List<Book> get(DataFetchingEnvironment dataFetchingEnvironment)
throws Exception {
return Book.books;
}
}
完成Data Wiring(GraphQlSourceBuilderCustomizer,舊版本RuntimeWiringBuilderCustomizer)
@Component
public class CustomerStaffDataWiring implements GraphQlSourceBuilderCustomizer {
@Autowired
private BooksDataFetcher booksDataFetcher;
@Autowired
private BookDataFetcher bookDataFetcher;
@Override
public void customize(GraphQlSource.SchemaResourceBuilder builder) {
builder.configureRuntimeWiring(new RuntimeWiringConfigurer() {
@Override
public void configure(RuntimeWiring.Builder builder) {
builder.type("Query", typeWiring -> typeWiring
.dataFetcher("books", booksDataFetcher)
.dataFetcher("bookById",bookDataFetcher)
);
}
});
}
}
開啟graph配置或者自己實作Controller
spring.graphql.schema.printer.enabled=true
spring.graphql.path=/wenl/query
自實作Controller
@RestController
public class BookController {
private GraphQL graphQL;
@Autowired
public BookController(GraphQlSource graphQlSource) {
graphQL = graphQlSource.graphQl();
}
@Data
public static class GraphQLInput{
String query;
Map<String,Object> variables;
}
@PostMapping(value = "/wenl/query")
public ResponseEntity<Object> query(
@RequestBody GraphQLInput graphQLInput)
{
ExecutionInput.Builder executionInputBuilder
= new ExecutionInput.Builder();
executionInputBuilder.query(graphQLInput.getQuery());
executionInputBuilder.variables(graphQLInput.getVariables());
ExecutionResult result = graphQL.execute(executionInputBuilder);
return ResponseEntity.ok(result.getData());
}
}
GraphQL Client 調用方式
就是簡單的POST 調用json方式,下面就使用Apifox 說明
傳回值如下:
調用JSON說明
{
"query":"query books($id:String,$name:String){ bookById(id:$id,name:$name){ id name pageCount author { firstName }}}",
"variables":{
"id":"book-1",
"name":"Effective Java"
}
}
$id,$name 表示參數 query,variables與GraphQLInput 字段一一對應。