赞
踩
GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。
GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑.
以上是 GraphQL 的一些介绍和描述. 看了你可能会一脸懵逼, 没事, 我也是(哈哈)… 因此, 我们先看使用后理解, 开始我们永久不衰的 Hello World.
这里以** SpringBoot 2.1.2.RELEASE** 为例, 构建工具选用 Gradle, 快速创建一个 Web 项目.
需要的依赖有
dependencies {
implementation 'com.graphql-java:graphql-java:11.0'
implementation 'com.graphql-java:graphql-java-spring-boot-starter-webmvc:1.0'
implementation 'com.google.guava:guava:26.0-jre'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
功能实现一个书本及作者信息查询. 所有数据用集合模拟如下:
private static List<Map<String, String>> books = Arrays.asList( ImmutableMap.of("id", "book-1", "name", "Harry Potter and the Philosopher's Stone", "pageCount", "223", "authorId", "author-1"), ImmutableMap.of("id", "book-2", "name", "Moby Dick", "pageCount", "635", "authorId", "author-2"), ImmutableMap.of("id", "book-3", "name", "Interview with the vampire", "pageCount", "371", "authorId", "author-3") ); private static List<Map<String, String>> authors = Arrays.asList( ImmutableMap.of("id", "author-1", "firstName", "Joanne", "lastName", "Rowling"), ImmutableMap.of("id", "author-2", "firstName", "Herman", "lastName", "Melville"), ImmutableMap.of("id", "author-3", "firstName", "Anne", "lastName", "Rice") );
在 resources 下新建
schema.graphqls
文件用于描述需要的 API.
type Query { bookById(id: ID): Book } type Book { id: ID name: String pageCount: Int author: Author } type Author { id: ID firstName: String lastName: String }
该语句定义了两个实体: Book 和 Author, 并且定义了一个查询: bookById, 通过书本 id 查询 Book 信息, Book 中又包含 Author 信息, 因此需要级联查询 Author.
创建一个
GraphQLProvider.java
用于初始化和暴露 GraphQL 实例.
@Component public class GraphQLProvider { private GraphQL graphQL; @Bean public GraphQL graphQL() { return graphQL; } @PostConstruct public void init() throws IOException { URL url = Resources.getResource("schema.graphqls"); String sdl = Resources.toString(url, Charsets.UTF_8); GraphQLSchema graphQLSchema = buildSchema(sdl); this.graphQL = GraphQL.newGraphQL(graphQLSchema).build(); } private GraphQLSchema buildSchema(String sdl) { // TODO: 在这里构造 Schema } }
基于
schema.graphqls
构造GraphQL
对象, 并暴露在 IOC 容器, GraphQL 适配器将会在此 GraphQL 对象之上构建 Schema 中的 API, 且默认的请求路径为/graphql
.
上面我们构建 GraphQL 实例还需要实现
buildSchema
方法, 此方法将会创建 GraphQLSchema 对象并获取数据.
@Autowired GraphQLDataFetchers graphQLDataFetchers; private GraphQLSchema buildSchema(String sdl) { TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl); RuntimeWiring runtimeWiring = buildWiring(); SchemaGenerator schemaGenerator = new SchemaGenerator(); return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring); } private RuntimeWiring buildWiring() { return RuntimeWiring.newRuntimeWiring() .type(newTypeWiring("Query") .dataFetcher("bookById", graphQLDataFetchers.getBookByIdDataFetcher())) .type(newTypeWiring("Book") .dataFetcher("author", graphQLDataFetchers.getAuthorDataFetcher())) .build(); }
TypeDefinitionRegistry
是 Schema 文件的解析器。SchemaGenerator
结合TypeDefinitionRegistry
和RuntimeWiring
来实际构造GraphQLSchema
.
buildWiring 使用 graphQLDataFetchers 这个 Bean 来实际注册了两个DataFetcher
.
- 一个通过书本 ID 查询书本的
DataFetcher
- 一个获取书本中作者信息的
DataFetcher
DataFetcher
和如何创建 graphQLDataFetchers 稍后说明. 总的来说, 创建GraphQL
及GraphQLSchema
的流程如下:
DataFetcher
是 GraphQL 最重要的概念之一, 用于查询时获取一个字段的数据.
当 GraphQL 执行查询时, 他会为每一个字段执行合适的DataFetcher
.DataFetcher
是一个只有一个方法的接口:
public interface DataFetcher<T> {
T get(DataFetchingEnvironment dataFetchingEnvironment) throws Exception;
}
Schema 中的每个字段都需要一个
DataFetcher
, 如果字段没有指定DataFetcher
, 那么就会使用的PropertyDataFetcher
作为默认的DataFetcher
.
创建 1.4 节中的 graphQLDataFetchers 实现
GraphQLDataFetchers.java
:
@Component public class GraphQLDataFetchers { private static List<Map<String, String>> books = Arrays.asList( ImmutableMap.of("id", "book-1", "name", "Harry Potter and the Philosopher's Stone", "pageCount", "223", "authorId", "author-1"), ImmutableMap.of("id", "book-2", "name", "Moby Dick", "pageCount", "635", "authorId", "author-2"), ImmutableMap.of("id", "book-3", "name", "Interview with the vampire", "pageCount", "371", "authorId", "author-3") ); private static List<Map<String, String>> authors = Arrays.asList( ImmutableMap.of("id", "author-1", "firstName", "Joanne", "lastName", "Rowling"), ImmutableMap.of("id", "author-2", "firstName", "Herman", "lastName", "Melville"), ImmutableMap.of("id", "author-3", "firstName", "Anne", "lastName", "Rice") ); public DataFetcher getBookByIdDataFetcher() { return dataFetchingEnvironment -> { String bookId = dataFetchingEnvironment.getArgument("id"); return books .stream() .filter(book -> book.get("id").equals(bookId)) .findFirst() .orElse(null); }; } public DataFetcher getAuthorDataFetcher() { return dataFetchingEnvironment -> { Map<String, String> book = dataFetchingEnvironment.getSource(); String authorId = book.get("authorId"); return authors .stream() .filter(author -> author.get("id").equals(authorId)) .findFirst() .orElse(null); }; } }
这里我们创建了两个
DataFetcher
: 通过 ID 获取书本信息的getBookByIdDataFetcher
以及获取书本中作者信息的getAuthorDataFetcher
.
至此 GraphQL 工程就搭建起来了, 基本结构如下:
启动 SpringBoot 应用
BookDetailsApplication
后, 我们就可以通过 http://localhost:8080/graphql 进行 API 访问.
你可以下载GraphQL
查询工具查询(工具下载: https://github.com/prisma/graphql-playground), 如下:
也可以通过 PostMan 查询, GraphQL 可以支持 GET 和 POST 两种请求查询.
Postman 中请求体已经支持了 GraphQL, 查询语句如下:
{
bookById(id: "book-1"){
id
name
pageCount
author {
firstName
lastName
}
}
}
正常的 POST 请求也可以查询 GraphQL, 需要请求体携带一个
query
参数, 该参数即是上面的查询语句, 但是由于请求必须是application/json
, 而 JSON 对多行字符串不支持, 因此需要做好 JSON 处理
由此也可以看出, GraphQL 请求体实际为我们做的就是请求参数的格式化.
GraphQL 也支持 GET 方式查询, 主要是因为 GraphQLServlet 实现了 doGet 和 doPost 两个方法. Get 请求查询时需要一个 query 请求参数, 且参数值需要 encode.
至此, 我们应该对 GraphQL 有一个简单的认识了, 那此时就有人会问了:
这玩意到底有啥用?
- 静态变动态, 前端可以自己从 API 获取想要的数据,不必依赖 REST 端返回的固定数据结构
- 请求次数及交互数据量的减少
- API 网关层面
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。