一、GraphQL简介

GraphQL是一种API查询语言,与SQL和数据库无关,但是两者有相似性,SQL是数据库查询语言,而GraphQL是API查询语言。它允许客户端定义响应结构(返回的字段及其类型),服务端接收请求后将返回指定的响应参数。例如下面请求示例要求返回id为1000的human的name和height:

query { # query默认可以省略不写human(id: "1000") {nameheight}
}

下面是服务端响应:

{"data": {"human": {"name": "Luke Skywalker","height": 1.72}}
}

操作类型

GraphQL支持三种类型的操作:query、mutation、subscription。query用于查询,mutation用于修改或新增,subscription用于订阅。

schema文件

schema文件定义了客户端读写数据的类型,GraphQL支持两种数据类型:Scalar、Object

  • scalar type即基本数据类型,包括:String,Int,Float,Boolean,ID,enum。其中ID是一种特殊的String,它表示字段是唯一的(即使服务端数据非String,GraphQL也会序列化成String)。
  • Object type即对象类型

GraphQL vs REST

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eJ2LgcKC-1629364874057)(https://mobilelive.ca/wp-content/uploads/2020/11/GraphQL_Image1.png)]

REST存在的问题:

  • 会使客户端与服务端产生多次交互问题,REST以资源为导向,因此在面对复杂场景查询,例如需要多个资源拼凑时,需要将原本一个请求拆分成多个(当然在实际实现时也可以做成一个请求,但是这不符合REST风格)
  • 存在过度获取(over-fetching)/获取不足(under-fetching)的问题,参数要么多给,要么少给,极少情况下接口给的参数刚好满足客户端需求

GraphQL可以解决REST以上痛点,它要求客户端指定自己需要的参数,服务端按照客户端的需求进行返回,不多不少。

但GraphQL目前也存在自身的一些问题:

  • 对文件上传支持不好,解决方案可参考:https://www.apollographql.com/blog/backend/file-uploads/file-upload-best-practices/
  • caching、security支持不够
  • 稳定性不如REST,REST由2000年提出,已经过市场20年的检验,毫无疑问是极为健壮的,市场占有率也碾压GraphQL。
  • 学习曲线较为困难

总结:GraphQL是一种查询语言、一种规范,它虽然可以解决REST的一些痛点,但它还存在着一些不完美的地方,就目前来说,GraphQL可以看做REST的补充,完全可以在项目中同时使用两者,但对于健壮性要求高的系统(例如金融领域),还是推荐使用REST。

二、在Spring Boot中使用GraphQL

截止目前,spring-graphql项目还处于里程碑版本,教程按照里程碑版本进行介绍,正式版发布后依赖包、注解可能会有些变化。
下面会以简单的Human和Car的例子介绍在Spring Boot中如何使用GraphQL。

依赖及核心注解介绍

由于spring-graphql还处于里程碑版本,还没有发布到maven中心库中,因此只能从spring的依赖仓库中拉取相关依赖,gradle配置如下:

repositories {maven { url "https://repo.spring.io/artifactory/libs-snapshot-local/" }mavenCentral()
}implementation 'org.springframework.experimental:graphql-spring-boot-starter:1.0.0-20210811.043505-62'

spring-graphql中定义的核心注解如下:

  • @GraphQlController:申明该类是GraphQL应用中的控制器
  • @QueryMapping:申明该类或方法使用GraphQL的query操作,等同于@SchemaMapping(typeName = "Query"),类似于@GetMapping
  • @Argument:申明该参数是GraphQL应用的入参
  • @MutationMapping:申明该类或方法使用GraphQL的mutation操作,等同于@SchemaMapping(typeName = "Mutation")
  • @SubscriptionMapping:申明该类或方法使用GraphQL的subscription操作,等同于@SchemaMapping(typeName = "Subscription")
  • @SchemaMapping:指定GraphQL操作类型的注解,类似@RequestMapping

例子说明

以Human和Car进行举例说明,下面是Human和Car实体类结构:

@Entity
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Human {@Idprivate Long id;private String cardNum; // 身份证号private String name;private Integer age;@Embeddedprivate Address address;@Embeddable@Getter@AllArgsConstructor@NoArgsConstructor@Builderpublic static class Address {private String province;private String city;private String addr;}public void modifyName(String name) {this.name = name;}
}@Entity
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Car {@Idprivate Long id;private String plateNum; // 车牌号private String ownerCardNum; // 车主身份证号
}

新建schema

在项目resources/graphql目录下新建schema.graphqls文件(支持扩展名为*.graphqls/.graphql/.gql/*.gqls的schema文件),该文件用于指定GraphQL的schema,所有定义的接口和类型都在记录在这个文件中。

定义controller

HumanController:

@GraphQlController
public class HumanController {private final HumanService humanService;public HumanController(HumanService humanService) {this.humanService = humanService;}@QueryMappingpublic List<Human> list(){return humanService.list();}@QueryMappingpublic Human details(@Argument Long id){return humanService.details(id);}@MutationMappingpublic Human modifyName(@Argument HumanUpdateCmd cmd){return humanService.modifyName(cmd.getId(), cmd.getName());}
}

CarController:

@GraphQlController
public class CarController {private final CarService carService;public CarController(CarService carService) {this.carService = carService;}@QueryMapping(value = "carList")public List<Car> list(@Argument String ownerCardNum){return carService.list(ownerCardNum);}
}

定义schema

type Query{details(id:ID!): Human # 根据ID查询Human详情,Human类型定义在下面list: [Human] # 查询所有HumancarList(ownerCardNum:String!): [Car] # 根据身份证号查询车辆car(id:ID!): Car
}type Human{id: ID! # Human id,不可为空cardNum: String! # 身份证号,不可为空name: String! # 名字,不可为空age: Int # 年龄address: Address # 住址,Address类型定义在下面
}type Address{province: String # 省份city: String # 城市addr: String # 地址详情
}type Car{plateNum: String! # 车牌号ownerCardNum: String # 车主身份证号
}type Mutation{modifyName(cmd:HumanUpdateCmd!): Human # 入参名称需要与接口入参名保持一致
}input HumanUpdateCmd{ # 接口入参需要使用input修饰id: ID!name: String!
}

调用接口

启动项目后,可通过Postman来请求接口,也可通过GraphiQL来请求。GraphiQL是一个帮助我们构造GraphQL请求的工具,它内嵌到我们项目中,因此只需访问http://localhost:8080/graphiql即可使用,下面是graphiql界面截图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T5nqaQXY-1629364874061)(https://raw.githubusercontent.com/lijian0706/spring-graphql-usage/main/img/graphiql.png)]

无入参的list接口

请求(只要求返回name和province):

{list{nameaddress{province}}
}

响应:

{"data": {"list": [{"name": "张三","address": {"province": "安徽省"}},{"name": "李四","address": {"province": "安徽省"}}]}
}
带入参的details接口

请求:

{details(id:1){name}
}

响应:

{"data": {"details": {"name": "张三"}}
}
同时返回Human和Car数据

与REST不同,GraphQL可以通过一次请求同时获取到Human和Car数据。
请求:

{details(id:1){name}carList(ownerCardNum:"1"){plateNum}
}

响应:

{"data": {"details": {"name": "张三"},"carList": [{"plateNum": "皖A1111"}]}
}
mutation用法

请求:

mutation($cmd: HumanUpdateCmd!){modifyName(cmd:$cmd){ # 入参名需要与schema中定义的入参名保持一致idname}
}

响应:

{"data": {"modifyName": {"id": "1","name": "张四"}}
}
subscription用法

由于GraphiQL不支持subscription,因此需要编写前端代码,在此不做介绍,具体可查看官方提供的例子:https://github.com/spring-projects/spring-graphql/tree/main/samples/webflux-websocket

完整示例代码
  • https://github.com/lijian0706/spring-graphql-usage

Spring GraphQL使用入门相关推荐

  1. Spring发布新成员:Spring GraphQL!高调出场的GraphQL能火起来了吗?

    7月6日,在GraphQL Java诞生6周年的时候,Spring社区通过博客宣布正式创建全新项目:Spring GraphQL,同时还发布了这个新项目的里程碑1.0版本. 博客原文:https:// ...

  2. Spring Cloud Eureka 入门 (三)服务消费者详解

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! "真正的进步 ...

  3. Spring Data ElasticSearch入门案例

    Spring Data ElasticSearch入门案例 创建maven工程elasticsearch_springdata 基于maven导入坐标 导入spring data elasticsea ...

  4. 微服务技术方案:Spring Cloud 从入门到实战

    随着互联网技术的发展与不断创新,以及用户流量的不断增大,越来越多的企业项目面临大数据.高并发等问题,随之而来的就是通过分布式模型组建架构,微服务思想就集中体现了应用价值,2020 年的你还没有掌握微服 ...

  5. spring social_Spring Social入门–第2部分

    spring social 几周前,我写了一篇文章,展示了我认为可以使用Spring Social编写的最简单的应用程序. 该应用程序读取并显示了Twitter用户的公共数据,并被编写为Spring ...

  6. Spring Data Solr入门

    Spring Data Solr是Spring Data项目的扩展,该项目旨在简化Apache Solr在Spring应用程序中的使用. 请注意,这不是Spring(数据)或Solr的简介. 我认为您 ...

  7. spring boot(一)入门

    目录 spring boot(一)入门 一.简介 1.微服务的概念 2.什么是spring boot 3.快速入门 4.springboot的快捷部署 spring boot(一)入门 一.简介 1. ...

  8. Spring Cloud Eureka 入门 (二)服务提供者详解

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! "优秀不是过 ...

  9. SpringBoot + Spring Security 简单入门

    这篇文章主要介绍了SpringBoot + Spring Security 简单入门 Spring Security 基本介绍 这里就不对Spring Security进行过多的介绍了,具体的可以参考 ...

最新文章

  1. 谷歌新作:视觉Transformer超越ResNet!!!从头开始训练!
  2. Docker 安装MySQL以及外部访问
  3. 在cmd指令看计算机位数,在.cmd中使用Windows命令来测试32位或64位并运行命令
  4. Memcached - In Action
  5. c语言课程描述英文版,c语言学生选课系统(国外英文资料).doc
  6. iOS逆向工具-Theos
  7. Laravel 2017 年度调查报告
  8. python selenium 获取接口数据
  9. 关闭git命令窗快捷键_git常用命令与AndroidStudio常用快捷键
  10. python核心编程源代码
  11. Android JTT808协议通讯
  12. TrafficMonitor 网速监控悬浮窗软件
  13. Unity 知识点复习
  14. Dell Latitude E6400找不到Broadcom USH及Contacted SmartCard驱动
  15. 驾驶车辆 档位与油门的关系
  16. 两边同时取对数求复合函数_【函数与导数】复合函数求导的几个妙用
  17. xgboost时间序列预测matlab,LightGBM和XGBoost实现时间序列预测(2019-04-02)
  18. python爬虫——正则表达式
  19. 在沙箱中IE不能上网的解决方法
  20. 华为笔记本没有网线口_matebook 14有网线接口吗

热门文章

  1. 用户查出本人所有待办流程
  2. Office2003安装时,自动输入25位密钥的快速工具
  3. linux 远程桌面
  4. 微信小程序从入门到精通(二) 小程序的能力
  5. 从2PC到Paxos
  6. 乔布斯离开后的苹果 | 历史上的今天
  7. javascript实现仿苹果电脑窗口最小化效果、css实现不规则图形的div
  8. Java实现 LeetCode 636 函数的独占时间(栈)
  9. iOS GPUImage研究总结
  10. 快速搭建前后端分离项目框架