天天看點

GraphQL入門實戰

解決什麼問題

根據請求控制傳回結果

例如: 一個User對象,有id,name,mobile,email

有些接口隻要傳回id,name ,有些接口還要要傳回 mobile

GraphQL入門實戰

适用場景

  • 弱文檔管理,公司對文檔要求不高
  • 需求複雜變化快
  • 單資源多種通路方式,元件複用
  • 複雜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 說明

GraphQL入門實戰

傳回值如下:

GraphQL入門實戰

調用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 字段一一對應。