Java World中的GraphQL简介

许多人认为GraphQL仅适用于前端和JavaScript,它在Java等后端技术中没有定位,但事实确实如此。

还经常将GraphQL与REST进行比较,但是这种比较是否合理?

首先,让我开始回答其中最重要的问题。 什么是GraphQL?

如果您查看官方网站,将会看到类似的内容

“ GraphQL是API的查询语言,并且是服务器端运行时,用于通过使用为数据定义的类型系统来执行查询。 GraphQL不受任何特定数据库或存储引擎的束缚,而是由您现有的代码和数据支持。”

实际上应该说的是

GraphQL是一个规范,仅此而已。

要记住这一点很重要,因为作为开发人员,我们将使用GraphQL的实现。 一些实现已经或多或少地实现了GraphQL规范中的功能。 有许多语言的实现,例如JavaScript,Java,PHP,Go和其他语言。 每天都有不同语言和现有语言的新实现。

如果您来自Java背景并且有很多REST API,那么您首先会感兴趣的是GraphQL与多年来开发的Traditional REST API有何不同。

让我将其放在一个简单的博客的上下文中,该博客由博客文章,博客文章的作者组成,并且可以在博客文章中添加评论。

从数据库的角度来看,这意味着我们有三个表

让我们假设前端是只读的,并从Traditional REST API获取数据,然后将数据呈现给用户。 如果我们要构建这种传统的REST API,则可能最终会得到类似以下的代码

 @RestController  public class SimpleRestController { @RequestMapping (path= "/authors" ) public List getAllAuthors() { ... } @RequestMapping (path= "/authors/{id}" ) public Author getAuthorById( @PathVariable String id) { ... } @RequestMapping (path= "/posts" ) public List getAllPosts( @RequestParam (value= "author_id" , required = false ) String authId) { ... } @RequestMapping (path= "/comments" ) public List getAllComments( @RequestParam (value= "post_id" , required = false ) String postId) { ... }  } 

因此,在这种情况下,如果我们想显示包含作者信息和评论的帖子,我们首先需要致电

  • /帖子

获取所有帖子,然后找到我们想要的帖子,查看authorId是什么,然后调用

  • / authours / <帖子中的ID>

之后,我们需要致电

  • / comments?post_id = <相关帖子的ID>

以获取该帖子的所有评论。

显然,这不是最佳方法。 当然,在这种情况下,我们所有人都会做的就是看好我们API的用例,并牢记这一点来优化端点和响应。 也许我们会将评论嵌入帖子,作者信息或类似内容中。 或者,由于某种原因,如果我们认为没问题,也许我们不会改变任何事情。 无论如何,我们将决定用户可以呼叫哪些端点,以及他们将获得什么样的响应。

确切地说,这是GraphQL的最大区别。 对于GraphQL,通常只有一个端点,例如

  • / graphql

该端点将获取对您的API的所有请求,并发送回所有响应。

起初听起来有点奇怪。 最简单的方法是拥有完整的示例代码。 我将使用一个这样的示例中的代码片段。 要获取完整的代码,只需点击以下URL :https://github.com/vladimir-dejanovic/simple-springboot-graphql-mongo-conftalk-demo

要记住的重要一点是,在GraphQL中,一切都始于架构。 如果我们转到上面的示例,博客文章,GraphQL模式可能看起来像这样:

 type Author { id: ID! name: String! posts: [Post] }  type Post { id: ID! title: String! body: String createdBy: Author! comments: [Comment]  } type Comment { id: ID! createdBy: Author! belongsTo: Post! text: String }  schema { query: Query  }  type Query { allPosts: [Post] allAuthors: [Author]  } 

我们从定义类型开始,对于将为表创建的POJO,类型几乎可以是1到1。 首先,我们输入一个名称,然后输入。 字符' '具有特殊含义,表示该字段是必填字段。 如果字段具有此字符并且不存在响应,则它将是无效响应,并且GraphQL将不会将响应发送回去,但会发送适当的错误。

关于模式要记住的重要一点是,所有请求和响应都将使用模式进行验证。 如果请求未通过架构验证,则服务器将不执行任何工作。 另外,如果响应未通过架构验证,则不会将其发送到客户端。

如果您选中“作者”类型,您将看到它具有“帖子数组”类型的字段帖子。 另外,Post具有类型为Author和comments的createdBy字段,其类型为Comment的Array。 这些字段在POJO的中不存在

 Author.java  public class Author {  private final String id;    private final String name;  .....get/set  }  Post.java  public class Post { private final String id;    private String authorId;    private final String title; private final String body;  ...get/set  } 

类似的是注释类型,我稍后会再讲。 定义类型之后,我们可以进入GraphQL模式的核心

 schema { query: Query  } 

这是我们定义与用户互动的地方。 我们说用户可以使用下面定义的Query类型的查询来读取数据。

 type Query { allPosts: [Post] allAuthors: [Author]  } 

Query是一种特殊类型,因为我们在DB中没有此数据,这实际上是传统思维方式中的端点。

如果您是从GitHub链接下载代码,进行编译并启动的,则可以转到http:// localhost:8080 / 。 然后,您将看到名为GraphiQL的漂亮用户界面。 您可以使用GraphiQL来玩GraphQL API

为了获得所有带有ID,标题和正文的帖子,只需将其输入GraphiQL

 query { allPosts { id title body }  } 

响应应如下所示

 { "data" : { "allPosts" : [ { "id" : "59f4c12e7718af0b1e001072" , "title" : "Who is Ed Wong" , "body" : "Edward Wong Hau Pepelu .....” }, . . . .  } 

例如,如果我们对身体不感兴趣,我们可以输入这样的内容

 query { allPosts { id title }  } 

那么响应将是这样的

 { "data" : { "allPosts" : [ { "id" : "59f4c12e7718af0b1e001072" , "title" : "Who is Ed Wong" , }, . . . .  } 

如您所见,当涉及到GraphQL时,用户在响应中并不总是获得相同的预定义字段集。 用户可以选择说出哪些字段应该发回,哪些不应该。

允许这样做的Java代码不是那么大。 首先,我们需要定义扩展SimpleGraphQLServlet的 Servlet。

 public class GraphQLEntryPoint extends SimpleGraphQLServlet {    public GraphQLEntryPoint(PostRepository postRepository, AuthorRepository authRepository, CommentRepository commentRepository) { super (buildSchema(postRepository, authRepository, commentRepository)); } private static GraphQLSchema buildSchema(PostRepository postRepository, AuthorRepository authRepository, CommentRepository commentRepository) { return SchemaParser .newParser() .file( "schema.graphqls" ) .resolvers( new Query(postRepository, authRepository), new PostResolver(authRepository, commentRepository), new AuthorResolver(postRepository), new CommentResolver(authRepository, postRepository)) .build() .makeExecutableSchema(); }  } 

在这里,我创建模式解析器,该解析器打开我的GraphQL模式文件,之后添加解析器,然后调用build和makeExecutableSchema方法。

这里的重要部分是解析器。 解析器是GraphQL将用于解决用户请求的类。

首先,最重要的是Query类。 它与模式中的Query类型具有相同的名称并非偶然。 这就是java GraphQL实现如何从架构中知道哪个类对应于查询逻辑的。 您可以使用任何喜欢的名称,只要该类具有相同的名称即可,但是,这意味着新人们也需要知道该名称,因此请保持标准,并且对于只读使用Query。

这是类查询的代码

 public class Query implements GraphQLRootResolver { private final PostRepository postRepository; private final AuthorRepository authRepo; public List<Post> allPosts() { return postRepository.findAll(); }    public List<Author> allAuthors() { return authRepo.findAll(); }  } 

它实现了GraphQLRootResolver ,并且您可以看到GraphQL模式中的每一行都有一个方法。

有一个叫allPost方法,该方法返回后的名单,也有方法allAuthors返回作者列表。 为了使我们的API能够正常工作,这就是所有这些。

如果您返回到GraphiQL并输入像这样的输入

 query { allPosts { id title createdBy { name } }  } 

响应将是这样的

 { "data" : { "allPosts" : [ { "id" : "59f4c12e7718af0b1e001072" , "title" : "Who is Ed Wong" , "createdBy" : { "name" : "Ed Wong” } }, . . . ]  } 

您会突然得到所有数据,而这不是Post pojo的一部分。 正如我们所看到的,Query类并没有做任何魔术,它只是返回Post类型的普通pojo列表。 那么,createdBy字段的作者信息从何而来?

为此,我们需要查看另一个解析器PostResolver,以使其更加精确,因此让我们看一下它的代码

 public class PostResolver implements GraphQLResolver<Post> {    private final AuthorRepository authRepository; private final CommentRepository commentRepository;    public Author createdBy(Post post) { return authRepository.findOne(post.getAuthorId()); }    public List<Comment> comments(Post post) { return commentRepository.findByPostId(post.getId()); }  } 

PostResolver实现了GraphQLResolver ,我们不得不说是哪种类型,在这种情况下,是Post类型 。 如您所见,Post中存在模式中的所有字段,但Pojo Post中不存在。 有一个createdBy方法,该方法采用Post类型的参数并返回Author。

此外,还有方法注释 ,该方法注释也采用Post类型的参数并返回Comment列表。

这就是全部,这就是我在代码中使用的GraphQL的java实现如何知道如何解析pojo中不存在的字段的方式。 在pojo的情况下,这非常简单,如果用户请求该字段,则只需调用适当的get方法,对于其他字段,必须为实现GraphQLResolver的类型提供解析器,并且需要一种具有正确签名和返回类型的方法。

如您所见,与我们一直以来创建的传统REST API相比,使用GraphQL,用户可以更好地控制他/她将获取哪些数据以及采用哪种格式。 因此,从用户的角度来看,这当然具有更好的用户体验,因为它具有更大的灵活性。 但是,这也意味着后端需要完成许多工作,因此系统在高负载下仍能正常运行。

在传统的REST API中,作为开发人员,我们完全控制用户与端点的交互方式,他们将获得什么样的响应以及用户请求将遵循的路径在我们的代码中。 如我们所见,使用GraphQL不再是这种情况。 我们知道的是,用户将点击解析器,而不是如何或通过哪个路径。 因此,优化困难得多。

幸运的是,并不是所有的东西都丢失了,我们仍然可以使用许多旧的技巧来解决这些新的/旧的问题。 例如,如果采用传统的REST API,解决高性能问题的一种方法是拥有一个带有端点的控制器,调用服务,然后该服务将承担繁重的工作。 在此设置中,我们可以缓存所有对服务的调用,并以这种简单的方式获得良好的性能。 我们可以用GraphQL做类似的事情,唯一的区别是控制器将调用服务,而不是控制器调用服务。

使用GraphQL,问题可能会更加棘手,但是,可以结合使用一些过去的技巧来使用过去的许多技术。 当然,每天都会出现许多解决问题的新方法。

我只在这里向您展示了如何读取数据,您当然也可以创建/编辑/修改数据,并使用GraphQL进行更多操作。 与GraphQL在构建API中提供的功能时,我与您分享的内容只是从头开始。

您需要记住的重要一点是,尽管GraphQL相对较新,但没有它也可以实现它提供的所有功能。 但是,在这种情况下,您将需要考虑允许用户做什么以及他们如何将请求发送到您的API。 对于GraphQL,其他人已经考虑过了,而您所要做的就是实现它。

最后,GraphQL API是REST API,这是高级REST API,具有许多功能和特性,因此更加精确。 这就是为什么问自己的问题,这是一件好事,您是否真的需要GraphQL提供的功能,并且会为您的API和为此API构建域的域增加更多的问题或解决方案。 也许GraphQL正是您所需要的,但也许又是旧的传统REST API所需要的。

资源资源

  • 代码示例https://github.com/vladimir-dejanovic/simple-springboot-graphql-mongo-conftalk-demo
  • GraphQL Java实现https://github.com/graphql-java/graphql-java
  • 弗拉基米尔·德雅诺维奇(Vladimir Dejanovic)在摩洛哥Devoxx上的Talk GraphQL vs传统REST API https://www.youtube.com/watch?v=2FH93GaoIto

翻译自: https://www.javacodegeeks.com/2017/12/gentle-intro-graphql-java-world.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/348844.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法题:在一个字符串中找到只出现一次的字符。如输入abaccdeeff,则输出bd。

今天的算法学习还是和字符串有关&#xff0c;这个题目据说是以前的某公司面试的笔试题目。题目意思就是说&#xff0c;在一个字符串中找到只出现了一次的那些字符&#xff0c;并且输出来。 作为非IT的我&#xff0c;平时使用Matlab比较多。不是科班出身&#xff0c;对于这个题…

Kafka的Spring Cloud Stream

总览 该示例项目演示了如何使用事件驱动的体系结构 &#xff0c; Spring Boot &#xff0c;Spring Cloud Stream&#xff0c; Apache Kafka和Lombok构建实时流应用程序。 在本教程结束时&#xff0c;您将运行一个简单的基于Spring Boot的Greetings微服务 从REST API获取消息 …

常见的股票技术因子学习以及计算

最近在看《量化投资数据挖掘技术与实践&#xff08;MATLAB版&#xff09;》。学习了其中的常见的股票衍生变量&#xff0c;并且利用WIND金融数据终端的matlab借口windmatlab导出一些数据进行了一个简单的学习。特此记录。 下面是我对于书中提到的几个因子的学习总结&#xff1…

Java – HashMap详细说明

HashMap基于哈希算法工作&#xff0c;根据Java文档HashMap具有以下四个构造函数&#xff0c; 建设者 描述 HashMap ​() 构造一个空的 具有默认初始容量&#xff08;16&#xff09;和默认加载因子&#xff08;0.75&#xff09;的HashMap 。 HashMap ​(int initialCapaci…

Python实现石头-剪刀-布小游戏

近日在学习Python的一些基础知识&#xff0c;觉得还是很有趣的一个一门语言&#xff01;就目前的学习的一些知识&#xff0c;编写了一些一个简单的石头剪刀布的游戏。主要是熟悉一些Python的一些控制语句。 import random while 1:sint(random.randint(1,3))print(s)print()if…

Python:递归输出斐波那契数列

今天学习Python的时候做一道练习题&#xff0c;题目是这样的&#xff1a; 题目 导入 问题 有一对兔子&#xff0c;从出生后第3个月起每个月都生一对兔子&#xff0c;小兔子长到第三个月后每个月又生一对兔子&#xff0c;假如兔子都不死&#xff0c;问每个月的兔子总对数为多…

排序算法二:快速排序算法原理以及MATLAB与Python实现

今天继续学习排序算法。今天的主角是快速排序算法。 1. 快速排序基本原理 快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略&#xff0c;通常称其为分治法(Divide-and-ConquerMethod)。 该方法的基本思想是&#xff1a; 1&#xff0e;先从数列…

排序算法三:堆排序基本原理以及Python实现

1. 基本原理 堆排序就是利用堆的特性进行一个无序序列的排序工作。 堆的特点 堆分为最大堆和最小堆&#xff0c;其实就是完全二叉树。 最大堆要求节点的元素都要不小于其孩子最小堆要求节点元素都不大于其左右孩子。 两者对左右孩子的大小关系不做任何要求&#xff0c;其实…

spring jms 消息_Spring JMS,消息自动转换,JMS模板

spring jms 消息在我的一个项目中&#xff0c;我应该创建一个消息路由器&#xff0c;就像所有路由器一样&#xff0c;它应该从一个主题获取JMS消息并将其放入另一个主题。 该消息本身是JMS文本消息&#xff0c;实际上包含XML消息。 收到消息后&#xff0c;我还应该添加一些其他…

排序算法四:归并排序基本原理以及Python实现

1. 基本原理 归并排序建立在归并操作上的一种算法。该算法是采用分治法&#xff08;Divide and Conquer&#xff09;的一个非常典型的应用。归并排序是将两 个已经有序的序列合成一个有序的序列的过程。 因此&#xff0c;对于一个待排序的序列来说&#xff0c;首先要将其进行…

如何将JAR添加到Jetbrains MPS项目

Jetbrains MPS是创建DSL的绝佳工具。 我们喜欢它&#xff0c;并在我们的咨询工作中定期使用它。 因此&#xff0c;我们之前已经写过关于Jetbrains MPS的文章 。 作为投影编辑器&#xff0c;您可以轻松创建可通过图形界面或数学公式之类使用的DSL。 尽管所有这些功能都需要做一…

Python 3实现k-邻近算法以及 iris 数据集分类应用

前言 这个周基本在琢磨这个算法以及自己利用Python3 实现自主编程实现该算法。持续时间比较长&#xff0c;主要是Pyhton可能还不是很熟练&#xff0c;走了很多路&#xff0c;基本是一边写一边学。不过&#xff0c;总算是基本搞出来了。不多说&#xff0c;进入正题。 1. K-邻近…

UART原理

UART原理 通用异步收发传输器&#xff08;Universal Asynchronous Receiver / Transmitter)&#xff0c;通常称作UART&#xff0c;是一种异步收发传输器&#xff0c;是电脑硬件的一部分。将资料由串行通信与并行通信间作传输转换&#xff0c;作为并行输入成为串行输出的芯片&am…

AttributeError: module 'tensorflow' has no attribute 'placeholder'等一系列tensorflow版本导致的问题

新人tensorflow2.1版本导致程序我无法运行最简单的办法 法1 tensorflow.compat.v1 import tensorflow.compat..v1 as tf tf.disable_v2_behavior() 亲测不好用 法2 卸载2.1&#xff0c;安装老版本 在Terminal界面输入 pip uninstall tensorflow接着输入Y确定卸载。 安装t…

word中一直提示校对错误,如何关闭当前文档校对功能

关闭当前文档校对功能 文件>选项>校对>例外项&#xff0c;选中两个&#xff0c;如图 对比效果&#xff1a;

将测微仪与Spring Boot 2一起使用

这是快速入门&#xff0c;介绍了如何使用出色的Micrometer库来检测基于Spring Boot 2的应用程序并在Prometheus中记录指标 介绍 Micrometer在各种监视工具提供的客户端库上提供了基于Java的外观。 以Prometheus为例&#xff0c;如果我要将Java应用程序与Prometheus集成&#…

与Maven的集成测试

用Maven实施单元测试是很普通的事情&#xff0c;我们大多数人都熟悉项目结构以及单元测试所在的位置。 但是&#xff0c;集成测试是一种不同的情况&#xff0c;大多数情况下它们具有完全不同的要求。 例如&#xff0c;可以让您的单元测试在内存数据库中的h2上运行&#xff0c;…

通信原理-通信系统的组成

第一章 通信系统的组成 1、通信系统一般模型 发送设备&#xff1a;将信源产生的原始电信号变换成适合在信道中传输的形式。变换方式有调制、放大、滤波、编码、多路复用等。 信道&#xff1a;传输信号的通道.即传输媒质。在给子信号通道的同时&#xff0c;信道也会对信号产生损…

使用log4j2免费分配日志记录

介绍 最近&#xff0c;我正在为一个客户端工作&#xff0c;试图为大型精心制作的Java系统消除一些GC暂停。 经过分析后&#xff0c;我意识到大部分垃圾都是通过日志记录产生的&#xff01; 是否有一种简单的方法来删除所有分配&#xff1f; 原来有:) 我应该使用哪个框架进行GC…

Verilog中fork...join 的用法

特点 中间的语句并行执行&#xff1b;&#xff08;延时不累加&#xff09; 不能用于综合&#xff1b; 代码 module signal_gen; reg wave; parameter cycle 5; initial beginforkwave 0;#(cycle) wave 1;#(2*cycle) wave 0;#(3*cycle) wave 1;#(4*cycle…