GraphQL入门总体创建教程

作者:王者之峰 时间:2022-10-16 12:29:09 

简介

因为目前做的项目查询提供的接口都使用GraphQL替代典型的REST API,所以有必要去对它进行了解和源码的阅读。本篇主要大致了解下GraphQL。

一种用于API的查询语言,让你的请求数据不多不少。前端按需获取,后端动态返回(不需要的数据不会返回甚至不会查库),对比起典型的REST API将更加灵活,后端代码提供可选能力。如果增加新的字段应用不想处理这部分数据可以不用区分版本。

后端确定哪些接口行为是被允许的,前端按需获取数据,让你的请求数据不多不少。

详细的介绍可以参考官方首页配合动图更加清晰。

简单示例

最好使用Spring Initializr去创建一个新的项目,不会产生一些冲突。

maven依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.1.6.RELEASE</version>
       <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.graphql-java.tutorial</groupId>
   <artifactId>book-details</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>book-details</name>
   <description>Demo project for Spring Boot</description>
   <properties>
       <java.version>1.8</java.version>
   </properties>
   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <!-- https://mvnrepository.com/artifact/com.graphql-java/graphql-java -->
       <dependency>
           <groupId>com.graphql-java</groupId>
           <artifactId>graphql-java</artifactId>
           <version>11.0</version>
       </dependency>
       <!-- https://mvnrepository.com/artifact/com.graphql-java/graphql-java-spring-boot-starter-webmvc -->
       <dependency>
           <groupId>com.graphql-java</groupId>
           <artifactId>graphql-java-spring-boot-starter-webmvc</artifactId>
           <version>1.0</version>
       </dependency>
       <!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
       <dependency>
           <groupId>com.google.guava</groupId>
           <artifactId>guava</artifactId>
           <version>26.0-jre</version>
       </dependency>
   </dependencies>
   <build>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
       </plugins>
   </build>
   <repositories>
       <repository>
           <id>central</id>
           <name>aliyun maven</name>
           <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
           <layout>default</layout>
           <!-- 是否开启发布版构件下载 -->
           <releases>
               <enabled>true</enabled>
           </releases>
           <!-- 是否开启快照版构件下载 -->
           <snapshots>
               <enabled>false</enabled>
           </snapshots>
       </repository>
   </repositories>
</project>

Schema

src/main/resources中创建schema.graphqls文件:

type Query {
   bookById(id: ID): Book
}
type Book {
   id: ID
   name: String
   pageCount: Int
   author: Author
}
type Author {
   id: ID
   firstName: String
   lastName: String
}

可以看到定义了一个bookById查询,用于根据id查询书籍,书籍中包含id、name、pageCount、author属性,其中author是一个复合类型所以定义了type Author

上面显示的用于描述schema的特定于域的语言称为schema定义语言或SDL。更多细节可以在这里找到。

解析schema并关联对应的fetchers

一旦我们有了这个文件,我们需要通过读取文件并解析它并且添加代码来为它获取数据使它&ldquo;栩栩如生&rdquo;。

package com.graphqljava.tutorial.bookdetails;
import com.google.common.base.Charsets;
import com.google.common.io.Resources;
import graphql.GraphQL;
import graphql.schema.GraphQLSchema;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.net.URL;
import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring;
@Component
public class GraphQLProvider {
   private GraphQL graphQL;
   /**
    * 注入GraphQL实例,GraphQL Java Spring适配器将使用GraphQL实例使我们的schema可用,通过Http-使用默认的"/graphql"url路径
    *
    * @return
    */
   @Bean
   public GraphQL graphQL() {
       return graphQL;
   }
   @PostConstruct
   public void init() throws IOException {
       //使用Resources读取graphqls文件
       URL url = Resources.getResource("schema.graphqls");
       //拿到graphqls文件内容
       String sdl = Resources.toString(url, Charsets.UTF_8);
       GraphQLSchema graphQLSchema = buildSchema(sdl);
       this.graphQL = GraphQL.newGraphQL(graphQLSchema).build();
   }
   @Autowired
   GraphQLDataFetchers graphQLDataFetchers;
   /**
    * 创建GraphQLSchema实例:解析schema并关联fetcher
    *
    * @param sdl
    * @return
    */
   private GraphQLSchema buildSchema(String sdl) {
       TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl);
       RuntimeWiring runtimeWiring = buildWiring();
       SchemaGenerator schemaGenerator = new SchemaGenerator();
       return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring);
   }
   /**
    * 根据层级去关联fetcher构建RuntimeWiring。最外层为Query可以提供bookById所需参数。第二层为Book-经过第一层获得的,可以为author提供所需参数。
    *
    * @return
    */
   private RuntimeWiring buildWiring() {
       return RuntimeWiring.newRuntimeWiring()
               .type(newTypeWiring("Query")
                       .dataFetcher("bookById", graphQLDataFetchers.getBookByIdDataFetcher()))
               .type(newTypeWiring("Book")
                       .dataFetcher("author", graphQLDataFetchers.getAuthorDataFetcher()))
               .build();
   }
}
package com.graphqljava.tutorial.bookdetails;
import com.google.common.collect.ImmutableMap;
import graphql.schema.DataFetcher;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@Component
public class GraphQLDataFetchers {
   /**
    * books静态数据
    */
   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")
   );
   /**
    * autors静态数据
    */
   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")
   );
   /**
    * bookById的fetcher,这里只是简单的通过静态数据进行筛选,具体生产使用sql进行查询
    *
    * @return
    */
   public DataFetcher getBookByIdDataFetcher() {
       return dataFetchingEnvironment -> {
           // 获得查询筛选参数
           String bookId = dataFetchingEnvironment.getArgument("id");
           return books
                   .stream()
                   .filter(book -> book.get("id").equals(bookId))
                   .findFirst()
                   .orElse(null);
       };
   }
   /**
    * 第二层author fetcher
    *
    * @return
    */
   public DataFetcher getAuthorDataFetcher() {
       return dataFetchingEnvironment -> {
           //获得上级对象
           Map<String, String> book = dataFetchingEnvironment.getSource();
           //根据上级对象找到关联id(相当于外键)
           String authorId = book.get("authorId");
           return authors
                   .stream()
                   .filter(author -> author.get("id").equals(authorId))
                   .findFirst()
                   .orElse(null);
       };
   }
}

DataFetchers

对于GraphQL Java服务器来说,最重要的概念可能是DataFetcher:DataFetcher在执行查询时获取一个字段的数据。

GraphQL Java在执行查询时,会为查询中遇到的每个字段调用相应的DataFetcher。DataFetcher是函数接口,函数具有一个参数为DataFetchingEnvironment类型。

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

Default DataFetchers

如上我们实现了两个DataFetchers。如上所述,如果你不指定一个,PropertyDataFetcher则是被默认使用。比如上面的例子中Book.id,Book.name,Book.pageCount,Author.id,Author.firstName和Author.lastName都有一个PropertyDataFetcher与之关联。

PropertyDataFetcher尝试以多种方式查找Java对象的属性。如果是java.util.Map,简单的通过key查找。这对我们来说非常好,因为book和author Maps的keys与schema中指定的字段相同。

总体创建过程

GraphQL入门总体创建教程

资料

Getting started with Spring Boot

graphql中文官网

来源:https://juejin.cn/post/7102815517416620040

标签:GraphQL,创建,教程
0
投稿

猜你喜欢

  • JavaMail实现邮件发送的方法

    2023-08-18 06:37:38
  • Android开发AsmClassVisitorFactory使用详解

    2023-07-22 05:34:53
  • 如何使用BeanUtils.copyProperties进行对象之间的属性赋值

    2023-10-17 19:01:40
  • java使用itext导出PDF文本绝对定位(实现方法)

    2021-07-27 19:11:44
  • jpa EntityManager 复杂查询实例

    2023-08-31 01:03:01
  • Java文件读写IO/NIO及性能比较详细代码及总结

    2021-11-28 12:56:30
  • java语言基础之标识符和命名规则详解

    2023-04-21 16:50:18
  • 流式图表拒绝增删改查之kafka核心消费逻辑上篇

    2023-04-19 03:32:11
  • Spring JPA 增加字段执行异常问题及解决

    2023-06-25 23:55:58
  • Java SE求解汉诺塔问题的示例代码

    2022-05-10 23:44:30
  • 基于java Files类和Paths类的用法(详解)

    2021-08-11 11:22:55
  • Android实现EditText的富文本编辑

    2022-04-14 21:44:29
  • Android 7.0系统webview 显示https页面空白处理方法

    2021-10-22 09:36:49
  • SpringMVC实现文件上传下载的全过程

    2023-04-05 21:16:52
  • Java装饰器设计模式_动力节点Java学院整理

    2023-11-11 03:03:10
  • unity 如何使用LineRenderer 动态划线

    2021-10-27 03:42:50
  • 基于Java接口回调详解

    2023-11-09 00:03:11
  • SpringBoot使用jasypt加解密密码的实现方法(二)

    2021-10-15 14:16:46
  • 使用linq to xml修改app.config示例(linq读取xml)

    2022-11-22 22:01:28
  • MyBatis-Plus找不到Mapper.xml文件的几种解决方法

    2023-11-24 03:37:52
  • asp之家 软件编程 m.aspxhome.com