GraphQL在Wildfly群上

“ GraphQL是API的查询语言,是用于使用现有数据完成这些查询的运行时。 GraphQL为您的API中的数据提供了一个完整且易于理解的描述,使客户能够准确地询问他们所需的内容,仅此而已,使随着时间的推移更容易开发API并启用强大的开发人员工具。

–来自https://graphql.org/

任何已经构建了可供多个消费者使用的REST服务的人,例如其他服务,网站或移动设备,都将知道很难构建满足所有需求的完美端点。 对于所有这些特殊情况,您通常最终都会获得相同服务的变体:)

现在,我们都知道我们应该只使用HATEOAS …,它在我的TODO列表中(承诺!),直到我偶然发现GraphQL为止 。

因此,在此博客文章中,我将解释如何轻松地将GraphQL添加到现有的JAX-RS应用程序中。

示例项目

Github中提供了示例项目,并且非常容易上手。

git clone https://github.com/phillip-kruger/membership.git
cd membership
mvn clean install

这将使用示例应用程序http:// localhost:8080 / membership /来启动fatjar wildfly-swarm

高水平

该示例是基本的成员资格服务,您可以在其中获得所有成员或特定成员。 您可以添加,编辑和删除成员。

该应用程序是典型的JAX-RS,CDI,EJB,JPA,Bean验证Java EE应用程序,并且我们正在添加一个新的GraphQL端点。

GraphQL部分使用以下库:

  • graphql-java
  • graphql-java-servlet
  • graphQL-spqr
  • 石墨烯

我添加来将现有的JAX-RS公开为GraphQL的唯一Java类:

  • MembershipGraphQLListener –注册“ / graphql” Servlet侦听器。
  • MembershipGraphQLApi – GraphQL端点。 仅包装现有的@Stateless服务。
  • MembershipErrorHandler –处理异常。

使用graphQL-spqr的注释, MembershipGraphQLApi类实际上只是描述和包装了现有的@Stateless服务:

@RequestScopedpublic class MembershipGraphQLApi {@Injectprivate MembershipService membershipService;// ...@GraphQLQuery(name = "memberships")public List<Membership> getAllMemberships(Optional<MembershipFilter> filter,@GraphQLArgument(name = "skip") Optional<Integer> skip,@GraphQLArgument(name = "first") Optional<Integer> first) {return membershipService.getAllMemberships(filter, skip, first);   }// ...}

我的希望–我们很快将在Java EE(或Jakarta EE或MicroProfile)中提供一个JAX-QL(或其他东西),以使其变得更加简单!

首先是一些REST

我正在使用MicroProfile OpenAPI和Swagger UI为REST端点创建Open API定义。

您可以使用http:// localhost:8080 / membership / rest / openapi-ui /测试一些查询

示例 –获取所有成员资格:

GET http://localhost:8080/membership/rest

这将返回:

[{"membershipId": 1,"owner": {"id": 1,"names": ["Natus","Phillip"],"surname": "Kruger"},"type": "FULL"},{"membershipId": 2,"owner": {"id": 2,"names": ["Charmaine","Juliet"],"surname": "Kruger"},"type": "FULL"},{"membershipId": 3,"owner": {"id": 3,"names": ["Koos"],"surname": "van der Merwe"},"type": "FULL"},{"membershipId": 4,"owner": {"id": 4,"names": ["Minki"],"surname": "van der Westhuizen"},"type": "FREE"}]

示例 –获得一定的成员资格(1):

GET http://localhost:8080/membership/rest/1

这将返回:

{"membershipId": 1,"owner": {"id": 1,"names": ["Natus","Phillip"],"surname": "Kruger"},"type": "FULL"}

现在让我们看一下GraphQL

该应用程序包括GraphiQL UI(作为Webjar),可以轻松测试一些GraphQL查询

您可以使用http:// localhost:8080 / membership / graph / graphiql /测试一些查询

因此,让我们看看GraphQL是否兑现了“不再需要过度提取和提取不足”的承诺。

获取所有成员资格和所有字段(与REST相同)

query Memberships {memberships{...fullMembership}}fragment fullMembership on Membership {membershipIdowner{...owner}type}fragment owner on Person {idnamessurname  }

这将返回所有值,但是,现在很容易定义应包括哪些字段…

获取所有会员资格,但仅包括id字段

query Memberships {memberships{...membershipIdentifiers}}fragment membershipIdentifiers on Membership {membershipId}

现在产生的有效负载要小得多:

{"data": {"memberships": [{"membershipId": 1},{"membershipId": 2},{"membershipId": 3},{"membershipId": 4}]}}

现在,仅获取特定类型的会员资格(因此,获取所有免费会员资格)

query FilteredMemberships {memberships(filter:{type:FREE}){...fullMembership}}fragment fullMembership on Membership {membershipIdowner{...owner}type}fragment owner on Person {idnamessurname  }

这将仅返回免费会员资格。 好酷!

甚至更好,所有姓氏的成员都以“ Kru”开头

query FilteredMemberships {memberships(filter:{surnameContains: "Kru"}){...fullMembership}}fragment fullMembership on Membership {membershipIdowner{...owner}type}fragment owner on Person {idnamessurname  }

太好了! 我们找到了两个人:

{"data": {"memberships": [{"membershipId": 1,"owner": {"id": 1,"names": ["Natus","Phillip"],"surname": "Kruger"},"type": "FULL"},{"membershipId": 2,"owner": {"id": 2,"names": ["Charmaine","Juliet"],"surname": "Kruger"},"type": "FULL"}]}}

使用客户端上的变量获取特定的成员资格:

query Membership($id:Int!) {membership(membershipId:$id){...fullMembership}}fragment fullMembership on Membership {membershipIdowner{...owner}type}fragment owner on Person {idnamessurname  }

变量:

{"id":1}

在特定条件下包括字段:

query Membership($id:Int!,$withOwner: Boolean!) {membership(membershipId:$id){...fullMembership}}fragment fullMembership on Membership {membershipIdowner @include(if: $withOwner){...owner}type}fragment owner on Person {idnamessurname  }

变量:

{"id":1,"withOwner": false}

这将排除所有者(正确包括):

{"data": {"membership": {"membershipId": 1,"type": "FULL"}}}

分页

让我们使用get all查询,但要分页。

query Memberships($itemsPerPage:Int!,$pageNumber:Int!) {memberships(first:$itemsPerPage,skip:$pageNumber) {membershipIdowner{namessurname}type}}

变量:

{"itemsPerPage": 2,"pageNumber": 1}

这将返回前2个结果,然后您可以通过增加“ pageNumber”值来进行分页。

变异

创建

mutation CreateMember {createMembership(membership: {type:FULL,owner: {names: "James",surname:"Small"}}) {membershipId}}

这将创建新的成员资格并返回ID。

更新资料

mutation EditMember($membership: MembershipInput!) {createMembership(membership:$membership) {membershipId}}

变量:

{"membership": {"membershipId": 2,"owner": {"names": ["Charmaine","Juliet"],"surname": "Krüger"},"type": "FULL"}}

(在克鲁格大学添加了变音符号,现在应该是克鲁格)

删除

mutation DeleteMembership($id:Int!){deleteMembership(membershipId:$id){membershipId}}

变量:

{"id":1}

这将删除成员资格1。

例外。

MembershipErrorHandler转换一个ConstraintViolationException(在bean验证失败时抛出),并为GraphQL创建一个不错的错误消息。

因此,让我们尝试创建一个姓氏仅为一个字母的成员。

mutation CreateMember($membership: MembershipInput!) {createMembership(membership:$membership) {membershipId}}

变量:

{"membership": {"owner": {"names": "Christina","surname": "S"},"type": "FULL"}}

这将返回bean验证错误消息:

{"data": {"createMembership": null},"errors": [{"message": "Surname 'S' is too short, minimum 2 characters","path": null,"extensions": null}]}

如果您查看Person POJO:

@NotNull(message = "Surname can not be empty") @Size(min=2, message = "Surname '${validatedValue}' is too short, minimum {min} characters")private String surname;

内省

GraphQL的另一个好处是,它具有可查询的架构和类型系统:

{__schema {queryType {namefields {name}}mutationType{namefields{name}}subscriptionType {namefields{name}}}}

上面将描述此端点上可用的查询和变异。

您还可以描述您的模型:

{__type(name: "Membership") {namekindfields {nameargs {name}}}}

摘要

在此示例中,我们没有删除REST,只是添加了GraphQL作为使用者的替代选项。

到现在为止,应该清楚的是,客户端具有更多的选项来完全根据需要过滤和查询数据。 所有这些都无需服务器做任何额外的工作。 这样可以在客户端进行快速的产品迭代。

线上的有效负载已得到优化,我们正在节省带宽!

再次,我希望–我们很快将在Java EE(或Jakarta EE或MicroProfile)中提供一个JAX-QL(或其他东西),以使其变得更加简单!

翻译自: https://www.javacodegeeks.com/2018/05/graphql-on-wildfly-swarm.html

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

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

相关文章

javafx 示例_示例介绍:JavaFX 8打印

javafx 示例我有一段时间没有写博客了&#xff0c;我想与其他人分享有关JavaFX的所有信息&#xff08;我的日常工作和家庭可能是借口&#xff09;。 对于那些对此博客不熟悉的人 &#xff0c;我是JavaFX 2 Introduction by Example&#xff08;JIBE&#xff09;的作者&#xff…

Spring Data JPA教程

在Java类或对象与关系数据库之间管理数据是一项非常繁琐且棘手的任务。 DAO层通常包含许多样板代码&#xff0c;应简化这些样板代码&#xff0c;以减少代码行数并使代码可重复使用。 在本教程中&#xff0c;我们将讨论Spring数据的JPA实现。 1.简介 1.1什么是JPA&#xff1f;…

使用storm 实时计算_使用Storm进行可扩展的实时状态更新

使用storm 实时计算在本文中&#xff0c;我将说明如何借助Storm框架以可扩展且无锁定的方式在数据库中维护实时事件驱动流程的当前状态。 Storm是基于事件的数据处理引擎。 它的模型依赖于基本原语&#xff0c;例如事件转换&#xff0c;过滤&#xff0c;聚合……&#xff0c;我…

【多元域乘法】多项式乘法电路原理及MATLAB详解

关注公号【逆向通信猿】更精彩!!! 关于二元域上的两个元素的乘法、多项式除法,在之前的博客 【有限域除法】二元多项式除法电路原理及MATLAB详解 子程序:sub_poly_div.m 【有限域元素加法和乘法】有限域元素加法和乘法的原理及MATLAB实现 子程序:sub_gf_add.m、sub_gf_…

my CSAPP Attack lab堆栈详解

关注公号【逆向通信猿】更精彩!!! 这个实验时学习了简书上的一篇文章后,自己根据课程例子进行的一次小测试,phase 4和5的堆栈图解还没有画,等后续有时间会进行补充。 本人转载的简书原文: https://blog.csdn.net/wlwdecs_dn/article/details/121249364#comments_19237…

Spring MVC教程

1.简介 作为企业Java开发人员&#xff0c;这项工作的主要重点之一是开发Web应用程序。 对于Web应用程序&#xff0c;后果还包括许多挑战。 具体来说&#xff0c;其中一些是状态管理&#xff0c;工作流和验证。 HTTP协议的无状态性质只会使事情变得更加复杂。 Spring的Web框架旨…

ubuntu22.04 下载路径

ftp下载路径 csdn下载 ubuntu22.04下载路径ubuntu-22.04-desktop-amd64.7z.001资源-CSDN文库 ubuntu22.04下载路径ubuntu-22.04-desktop-amd64.7z.002资源-CSDN文库 【免费】ubuntu-22.04-desktop-amd64.7z.003资源-CSDN文库 【免费】ubuntu-22.04-desktop-amd64.7z.004资源-…

Spring Reactor教程

在RESTful服务的世界中&#xff0c;实际上实际上是在幕后进行许多工作&#xff0c;我们通常必须在应用程序中进行很多处理&#xff0c;而实际上并不会影响需要发送给真实用户的响应。 可以被动地做出这些业务决策&#xff0c;以便它们对与应用程序交互的用户没有任何影响。 Spr…

api签名_使用签名保护基于HTTP的API

api签名我在EMC上的一个平台上可以构建SaaS解决方案。 与越来越多的其他应用程序一样&#xff0c;该平台具有基于RESTful HTTP的API。 使用JAX-RS之类的开发框架&#xff0c;构建这样的API相对容易。 但是&#xff0c; 正确构建它们并不容易。 建立基于HTTP的API的问题 问…

【多元域除法】多项式除法电路原理及MATLAB详解

关注公号【逆向通信猿】更精彩!!! 关于二元域上的两个元素的加法和乘法、多项式除法,在之前的博客 【有限域除法】二元多项式除法电路原理及MATLAB详解 子程序:sub_poly_div.m 【有限域元素加法和乘法】有限域元素加法和乘法的原理及MATLAB实现 子程序:sub_gf_add.m、s…

win10高分辨率下修改字体显示大小(不是缩放百分比)

问题 不通过修改设置缩放百分比来增大win10的字体显示大小&#xff0c;缩放百分比调大后会导致很多问题出现&#xff01;&#xff01;&#xff01; 修改 打开设置&#xff0c;或者右键个性化&#xff0c;在搜索栏输入&#xff1a;“放大文本大小”&#xff0c;搜索框下面会自…

应用程序无法正常启动 0xc0150002

Visual Studio 2017在debug下运行程序报错 应用程序无法正常启动 0xc0150002 分析原因 可能是&#xff1a;原程序是低版本的VS所编写的&#xff0c;缺少低版本的运行库&#xff0c;所以报错 解决 安装了VS2010后即可正常运行 error LNK2019: 无法解析的外部符号 __vsnwprin…

Excel之抽奖器实现

Excel实现一个抽奖器&#xff0c;关键在于学会几个Excel中的函数即可轻松实现。 单人抽奖 RANDBETWEEN 例&#xff1a; INDEX(A2:A61,RANDBETWEEN(1,60))缺点&#xff1a;这种方式生成的抽奖器&#xff0c;在多人情况下&#xff0c;由于RANDBETWEEN函数的返回值有可能是相同…

【RS码1】系统RS码编码原理及MATLAB实现(不使用MATLAB库函数)

关注公号【逆向通信猿】更精彩!!! 基础知识 要想搞懂本节知识,需要先熟悉掌握以下前几篇博客 【多元域乘法】多项式乘法电路原理及MATLAB详解 【多元域除法】多项式除法电路原理及MATLAB详解 RS码编码原理 RS码的编码与BCH码类似,区别在于RS码为多进制的 生成多项式…

如何用Java编写类似C的Sizeof函数

如果您刚开始学习Java并且是C语言背景&#xff0c;那么您可能已经注意到Java和C编程语言之间存在一些差异&#xff0c;例如String是Java中的对象&#xff0c;而不是NULL终止的字符数组。 同样&#xff0c;Java中没有sizeof&#xff08;&#xff09;运算符。 所有原始值都有预定…

Spring启动教程

1.简介 如果您一直想使用一个Web框架&#xff0c;它使您能够快速开始API开发&#xff0c;而无须设置Web服务器&#xff0c;收集所有有线依赖项&#xff0c;安装各种工具的麻烦&#xff0c;那么您将拥有一个出色的框架&#xff0c;即Spring开机 Spring Boot的主要座右铭是约定优…

【LDPC系列1】基于MATLAB中LDPC编译码器对象的图像传输通信系统仿真

关注公号【逆向通信猿】更精彩!!! 1. 构造编码器对象 采用MATLAB内置的comm.LDPCEncoder构造编码器对象,其中使用默认的校验矩阵,信息位长32400比特,码长64800比特,该校验矩阵中除第一行中1的个数为6个外,其余行中1的个数均为7;前12960列中1的个数为8,后32400列构成…

【LDPC系列2】基于MATLAB中LDPC编译码器对象的图像传输通信系统仿真(IEEE 802.16e标准协议基础矩阵)

关注公号【逆向通信猿】更精彩!!! 1. 构造校验矩阵H,并保存为mat文件 采用IEEE 802.16e标准协议中的基础校验矩阵 通过构造QC-LDPC校验矩阵,码长n=2304,信息长k=1152,码率r=1/2,基础矩阵维数为1224: Hb = [-1 94 73 -1

VS2010附加进程调试DLL时断点无法断下的解决方法

系统版本&#xff1a;Win10 x64 1809 VS版本&#xff1a;VS2017 企业版 问题一 在动态链接库(DLL)附加到进程调试时&#xff0c;用VS2017附加后单步调试&#xff0c;结果发现总是在调试过程中卡死&#xff0c;VS2017无响应&#xff1b; 解决办法是&#xff1a;强制结束VS2017…

用于SaaS和NoSQL的Jdbi

一个自然的接口&#xff0c;用于与CRM&#xff0c;ERP&#xff0c;会计&#xff0c;营销自动化&#xff0c;NoSQL&#xff0c;平面文件等基于Java的数据集成 Jdbi是Java的SQL便利库&#xff0c;它为JDBC提供更自然的Java数据库接口&#xff0c;该接口易于绑定到域数据类型。 该…