当前位置:   article > 正文

Java 后端的未来? GraphQL?_runtimewiring

runtimewiring

Java 后端的未来? GraphQL?

file

GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具

GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑.

以上是 GraphQL 的一些介绍和描述. 看了你可能会一脸懵逼, 没事, 我也是(哈哈)… 因此, 我们先看使用后理解, 开始我们永久不衰的 Hello World.

1. 项目构建

1.1 创建项目

这里以** 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'
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

功能实现一个书本及作者信息查询. 所有数据用集合模拟如下:

    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")
    );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

1.2 创建 Schema

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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

该语句定义了两个实体: Book 和 Author, 并且定义了一个查询: bookById, 通过书本 id 查询 Book 信息, Book 中又包含 Author 信息, 因此需要级联查询 Author.

1.3 创建 GraphQL 实例

创建一个 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
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

基于 schema.graphqls 构造 GraphQL 对象, 并暴露在 IOC 容器, GraphQL 适配器将会在此 GraphQL 对象之上构建 Schema 中的 API, 且默认的请求路径为 /graphql.

1.4 构建 GraphQLSchema

上面我们构建 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();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

TypeDefinitionRegistry 是 Schema 文件的解析器。SchemaGenerator 结合 TypeDefinitionRegistryRuntimeWiring 来实际构造 GraphQLSchema.
buildWiring 使用 graphQLDataFetchers 这个 Bean 来实际注册了两个 DataFetcher.

  • 一个通过书本 ID 查询书本的 DataFetcher
  • 一个获取书本中作者信息的 DataFetcher

DataFetcher 和如何创建 graphQLDataFetchers 稍后说明. 总的来说, 创建 GraphQLGraphQLSchema 的流程如下:

file

1.5 DataFetcher

DataFetcher 是 GraphQL 最重要的概念之一, 用于查询时获取一个字段的数据.
当 GraphQL 执行查询时, 他会为每一个字段执行合适的 DataFetcher. DataFetcher 是一个只有一个方法的接口:

public interface DataFetcher<T> {
    T get(DataFetchingEnvironment dataFetchingEnvironment) throws Exception;
}
  • 1
  • 2
  • 3

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);
        };
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

这里我们创建了两个 DataFetcher: 通过 ID 获取书本信息的 getBookByIdDataFetcher 以及获取书本中作者信息的 getAuthorDataFetcher.

至此 GraphQL 工程就搭建起来了, 基本结构如下:

file

2. API 查询

启动 SpringBoot 应用 BookDetailsApplication 后, 我们就可以通过 http://localhost:8080/graphql 进行 API 访问.
你可以下载 GraphQL 查询工具查询(工具下载: https://github.com/prisma/graphql-playground), 如下:

file

也可以通过 PostMan 查询, GraphQL 可以支持 GET 和 POST 两种请求查询.

2.1 Postman 通过 POST GraphQL 请求体查询

Postman 中请求体已经支持了 GraphQL, 查询语句如下:

{
  bookById(id: "book-1"){
    id
    name
    pageCount
    author {
      firstName
      lastName
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

file

2.2 Postman 通过普通 POST 请求查询

正常的 POST 请求也可以查询 GraphQL, 需要请求体携带一个 query 参数, 该参数即是上面的查询语句, 但是由于请求必须是 application/json, 而 JSON 对多行字符串不支持, 因此需要做好 JSON 处理

file

由此也可以看出, GraphQL 请求体实际为我们做的就是请求参数的格式化.

2.3 Postman 通过 GET 请求查询

GraphQL 也支持 GET 方式查询, 主要是因为 GraphQLServlet 实现了 doGet 和 doPost 两个方法. Get 请求查询时需要一个 query 请求参数, 且参数值需要 encode.

file

3. 应用场景

至此, 我们应该对 GraphQL 有一个简单的认识了, 那此时就有人会问了: 这玩意到底有啥用?

  • 静态变动态, 前端可以自己从 API 获取想要的数据,不必依赖 REST 端返回的固定数据结构
  • 请求次数及交互数据量的减少
  • API 网关层面

file

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/141653
推荐阅读
相关标签
  

闽ICP备14008679号