GraphQL介绍以及在Spring Boot/Cloud项目中搭建GraphQL并测试

GraphQL what & why

GraphQL是一种API查询语言,它是一种动态的API查询方式,同一个API可以返回不同的结果。

普通的REST请求是预先定义好的,前端需要什么数据会和后端讲,然后后端开始商量好返回数据格式,然后进行开发。而GraphQL是REST的升级版,定义好某个API之后,可以用GraphQL做多种操作,比如说只需要id那么可以在调用的时候指明只返回id,如果需要id, name, comments….等等,也可以指定。因此,它查询的结果是动态的,这样可以降低前后端的耦合。

 

官方解释:

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

 

为什么要用GraphQL

  1. 强类型的schema

它请求的结构和返回的结构很相似,可以很直观的设置参数并预知返回结果。

  1. 按需获取,节省网络负载,提高页面加载速度

比如我只要id和name那么我指定一下,它就只返回id和name,而不会像API一样返回一堆没有用的数据(现在的VDM 有些查询的API会把所有引用到的对象的信息都查出来)

  1. 特别适用于结构固定,数据模型清晰的业务场景

比如我们的VDM,里面基本都是数据库相应表的增删改查,不会有其他系统对接或特殊的逻辑处理,使用GraphQL就好像前端直接在操作数据库。

  1. 支持快速产品开发

GraphQL的schema是用配置文件xxx.graphqls定义,里面定义了各种接口名、参数和返回对象,然后在所有实现了GraphQLQueryResolver, GraphQLMutationResolver的类中去做具体的操作。

只要后端将schema定义好之后,前端便可开始工作。

5.可以使用内联查询将多个API的信息拼接一次返回。

6.  活跃的社区

7.  GitHub 最新的v4版本API已经完全采用GraphQL

 

GraphQL的Type:

两种,一种是标量类型(Scalar Type)一种是对象类型(Object Type)。有点类似java中的基本数据类型和对象类型。

GraphQL 自带一组默认标量类型:

    Int:有符号 32 位整数。

    Float:有符号双精度浮点值。

    String:UTF‐8 字符序列。

    Boolean:true 或者 false。

    ID:ID 标量类型表示一个唯一标识符,通常用以重新获取对象或者作为缓存中的键。ID 类型使用和 String 一样的方式序列化;然而将其定义为 ID 意味着并不需要人类可读型。

大部分的 GraphQL 服务实现中,都有自定义标量类型的方式。例如,我们可以定义一个 Date 类型:

scalar Date

然后就取决于我们的实现中如何定义将其序列化、反序列化和验证。例如,你可以指定 Date 类型应该总是被序列化成整型时间戳,而客户端应该知道去要求任何 date 字段都是这个格式。

枚举类型(Enumeration Types)是一种特殊的标量,它限制在一个特殊的可选值集合内。这让你能够:

验证这个类型的任何参数是可选值的的某一个

与类型系统沟通,一个字段总是一个有限值集合的其中一个值。

下面是一个用 GraphQL schema 语言表示的 enum 定义:

enum Episode {

  NEWHOPE

  EMPIRE

  JEDI

}

 

接口类型是特殊的对象类型,一个对象类型继承了某个接口,就必须包含这个接口里面的所有字段。比如下面:

interface BaseResponseVO {

    status:String

    version:String

    httpCode:Int

}

type TypeResponse implements BaseResponseVO {

    status:String

    version:String

    statusDesc:String

    httpCode:Int

         data:[Type]

}

GraphQL的查询和变更:

在GraphQL的schema中有两个特殊类型:

schema {

  query: Query

  mutation: Mutation

}

这是所有schema的入口,后面写的schema需要继承这两个类型。

Query 表示查询的入口,专门展示数据的

Mutation 是变更的入口,做增删改的。

 

每一个 GraphQL 服务都至少有一个 query 类型,可能有一个 mutation 类型。这两个类型和常规对象类型无差,但是它们之所以特殊,是因为它们定义了每一个 GraphQL 查询的入口。因此如果你看到一个像这样的查询:

那表示这个 GraphQL 服务需要一个 Query 类型,且其上有 hero 和 droid 字段:

type Query {

  hero(episode: Episode): Character

  droid(id: ID!): Droid

}

 

再来看看变更(Mutation):

变更和查询很类似,定义一些字段,然后就可以去调用并由前端定义需要返回的数据。

 

比如定义一个对象类型作为入参(注意所有入参的声明是input, 所有返回结果的声明是type):

input TestInput {

         id:Int

         name:String!

         createdBy:String

}

然后定义一个返回对象:

type TestResponse {

         statusCode:Int

         messageCode:String

         message:String

}

 

然后执行下面这个更新操作,语句如下:

mutation($testInput:TestInput!) {

  update(testInput:$testInput) {

    statusCode

         messageCode

    message

  }

}

它的意思是:执行mutation下面的update方法,传入一个对象类型的变量$testInput作为参数,返回结果里面取statusCode, messageCode, message这三个字段。

 

这个变量类型也需要设置值,如果你是用的GraphiQL客户端工具,请在左下角查询变量设置区域填充值:

{

  "testInput": {

    "name": "testgraphql"

  }

}

 

有必要记住的是,除了作为 schema 的入口,Query 和 Mutation 类型与其它 GraphQL 对象类型是一样的,它们的字段也是一样的工作方式。

 

 

在Spring Boot/Cloud项目中使用GraphQL:

Gradle加入下面这两个依赖:

compile group: 'com.graphql-java', name: 'graphql-spring-boot-starter', version: '4.0.0'

compile group: 'com.graphql-java', name: 'graphql-java-tools', version: '4.3.0'

加完依赖后,重新refresh一下项目,下载并resolve完之后,开始写代码:

数据库访问层(dao, repository, model)基本不需要改动,因为不管是用REST还是GraphQL这些数据库访问还是差不多的。GraphQL相当于替换了项目的视图层,有点类似SpringMVC中的controller包下面定义的接口信息,至于怎么处理业务逻辑和怎样去查询和操作数据库,这是你自己去决定的。

新建一个resolve包,然后建一个TestResolver类,这个类需要加个@Component注解,表示是Spring的bean,然后这个类需要实现GraphQLQueryResolver或者 GraphQLMutationResolver这两个接口,这两个接口里面没有任何方法,主要是GraphQL会根据这两个接口去查找相关的实现类。

如果只有查询,只需要implements GraphQLQueryResolver就好了。

如下所示:

这里面注入了一个service,所有具体的逻辑是可以在service里面去处理的,当然你也可以用resolver类代替service,将逻辑处理放在resolver里面,直接操作dao层。

 

在项目的resource目录下建一个graphql的文件夹,然后在里面去建graphql的schema文件:

比如建一个root.graphqls文件:

root.graphqls里面定义了Query和Mutation 的所有接口名、参数、返回信息:

 

Query和mutation语法格式很容易懂,[]表示是一个数组,!表示这是必要的,:后面是返回对象类型,括号里面的是入参类型。

 

还有一个配置文件:schema.graphqls 这个里面定义了所有的type和 input类型字段定义。

比如下面:

interface BaseResponseVO {

    status:String

    version:String

    httpCode:Int

}

type TypeResponse implements BaseResponseVO {

    status:String

    version:String

    httpCode:Int

   data:[Type]

}

type Type {

         id:Int

         name:String

         createUser:String

         createTimestamp:String

         updateUser:String

         lastUpdateTimestamp:String

}

 

入参用Input声明,返回的类型用type声明。Input/Type都是在这个文件里面去定义的,如果Type那个对象里面还引用了其他对象,那么其他对象也要用Type去定义,直至保证所有引用到的对象类型都定义完,只有标量类型

 

OK,这些做完了一个简单的GraphQL项目就跑起来了,请启动项目,然后用GraphQL的客户端程序去测试吧,客户端推荐GraphiQL, 附上下载链接:

https://electronjs.org/apps/graphiql

 

安装好之后,进入了这么个界面:

请在地址栏输入 http://{域名}:{项目端口号}/graphql

然后左边框输入查询语句,左下角是入参的声明和指定值,点击播放按钮,右边会显示结果。

 

 

原文地址:https://www.cnblogs.com/cnsec/p/13407121.html