graphql_GraphQL在Wildfly群上

graphql

“ 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

graphql

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

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

相关文章

android中有哪些utils的作用,AndroidUtils

多年开发Android积攒下来好多常用的工具方法&#xff0c;保存在随笔中&#xff0c;持续更新。TimeUtil/*** 获取距当前时刻的时间戳** param createTime* return*/public static String getTimestamp(long createTime) {long currrentMillis System.currentTimeMillis();// if…

Java中的关键字this_super

文章目录要点错误的理解正确的理解演示代码要点 1.在类的构造器中&#xff0c;可以使用 this() 调用本类的其它构造器&#xff0c;调用的时候根据构造器声明的参数列表传递参数值 2.super() 调用父类的无参构造器 3.super.method() 调用父类的 method() 方法 4.super.name …

Spring Hibernate教程

1.简介 在本文中&#xff0c;我们将演示如何利用最流行的ORM&#xff08;对象关系映射&#xff09;工具之一的Hibernate的功能 &#xff0c;该工具可将面向对象的域模型转换为传统的关系数据库。 Hibernate是目前最流行的Java框架之一。 由于这个原因&#xff0c;我们在Java Co…

百度地图瓦片 android,百度地图自定义瓦片图获取

nodejs代码const request require(request);const fs require(fs);const bagpipe require(bagpipe);const TileLnglatTransform require(tile-lnglat-transform);let [x1, y1] [72.26, 54.57]; // 起始点坐标(左上角)let [x2, y2] [137.31, 17.8]; // 终点坐标(右下角)le…

IntelliJ IDEA for Mac 如何自定义快捷键_设置快捷键

文章目录设置代码补全快捷键设置展开全部的快捷键折叠全部快捷键设置代码补全快捷键 代码自动补全&#xff0c;即智能提示。 打开【系统偏好设置】如下图所示&#xff1a; 在左侧的菜单栏中找到 Keymap → Main Menu → Code → Code Completion → Basic&#xff1a; 设…

android8 老手机,华为多款老旧手机获升安卓8.0,流畅度飙升!

原标题&#xff1a;华为多款老旧手机获升安卓8.0&#xff0c;流畅度飙升&#xff01;一直以来&#xff0c;在手机用户圈都有这么一个共识&#xff0c;那就是安卓手机不如iPhone流畅&#xff0c;之前安卓手机给人的印象就是容易卡顿&#xff0c;而谷歌则一直在为此事苦恼&#x…

java12关键字var_Java 10:“ var”关键字

java12关键字varJava 10使用关键字var引入了局部变量类型推断 。 这意味着无需编写&#xff1a; Map<Department, List<Employee>> map new HashMap<>(); // ... for (Entry<Department, List<Employee>> dept : map.entrySet()) {List<Emp…

IntelliJ IDEA for Mac自定义动态代码模板快捷键(Live Templates Shortcut)

文章目录查看更多的快捷键常用的代码模板自定义代码模板快捷键格式化等号文档注释代码模板快捷键应用示例声明定义引用类型变量数组的 for 循环指定循环次数的 for 循环增强 for 循环倒序 for 循环自动生成普通 for 循环语句自动生成main 方法自动生成输出语句自动生成增强for循…

android udp 设备发现,两台Android设备之间进行UDP连接(使用多播地址)~~求大神指点...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼首先 发送端&#xff1a;package com.example.multicastclient;import android.support.v7.app.ActionBarActivity;import java.io.IOException;import java.net.DatagramPacket;import java.net.InetAddress;import java.net.Mult…

java serial_Java的@Serial批注

java serialJDK可能正在使用JDK 11 &#xff1a; Serial获得另一个标准&#xff08;预定义&#xff09;注释 。 JDK-8202385 [“标记与序列相关的字段和方法的注释”]的目的是添加“某种“ SerialRelated”注释&#xff0c;以促进对序列字段和方法的声明的自动检查。” 这种想法…

IntelliJ IDEA 选中变量名,高亮显示其它地方的这个变量名,高亮颜色如何设置呢?

选中了一个变量名&#xff0c;会高亮显示位于别的地方的这个变量名&#xff0c;那么怎么修改其他地方的高亮颜色&#xff1f; 按下 Command , 打开偏好设置窗口&#xff0c;接着看下图&#xff1a;

rest和rest ful_还有更多REST技巧

rest和rest ful在以前的博客文章中&#xff0c;我介绍了一些实现REST体系结构的想法和技巧。 在这篇文章中&#xff0c;我将介绍更多的想法和技巧。 快取 缓存是原始论文的很大一部分。 见5.1.4节 策略包括验证&#xff08; 客户端检查它是否具有最新版本 &#xff09;和过期…

html实心圆点特殊符号,和平精英名称添加圆点符号的方法 和平精英圆点符号代码分享...

和平精英怎么在名字中添加圆点符号呢&#xff1f;昵称中是可以加入圆点符号的&#xff0c;很多小伙伴们都想要一个性一点的名字&#xff0c;那么就可以用到各种各样的特殊符号&#xff0c;圆点符号复制的代码小编已经分享到下面了&#xff0c;有需要这个圆点符号的玩家快带走吧…

Java包装类和基本数据类型的对照

int --> Integer byte --> Byte short --> Short long --> Long boolean --> Boolean char --> Character double --> Double float --> Float 注&#xff1a;基本类型自动转换成对应的包装类型&#xff0c;叫自动装箱&#xff1b;包装类型转换成对应…

java 8 stream_Java 8 Stream示例

java 8 stream这篇文章将帮助您了解Java 8中一些重要且经常使用的Stream操作&#xff0c;这使您使用Java编程变得容易。 让我们以传统示例为例&#xff0c;“员工和部门”。 public class Employee {private String name;private Integer age;private String city;private De…

html怎么设置图片隐藏,css3如何隐藏图片?

css3隐藏图片的方法&#xff1a;1、为图片元素设置display:none;样式来隐藏。2、使用visibility:hidden;样式隐藏图片。3、使用opacity:0;样式通过设置图片完全透明来设置图片不可见。css中可以使用下面几种样式隐藏图片&#xff1a;display:none;visibility:hidden;opacity:0;…

IntelliJ IDEA修改项目的根目录名称_修改包目录的名称_修改模块名称_修改项目名称

文章目录修改项目根目录的名称修改包目录的名称模块重命名修改了项目根目录后&#xff0c;必须删除项目和 .idea 文件&#xff0c;重新导入&#xff08;重点&#xff09;新版本的 IDEA 取消了 Import Project 入口修改项目根目录的名称 如果仅仅修改项目的名称&#xff0c;而不…

容器rocker_用Rocker制作模板

容器rocker在本文中&#xff0c;我们将快速介绍Rocker &#xff0c;这是一个静态类型化的快速Java 8模板引擎。 必需的依赖项 要开始使用Rocker&#xff0c;我们需要在项目中添加以下依赖项&#xff1a; <dependency><groupId>com.fizzed</groupId><art…

android 开源 示波器,上个老外的开源虚拟示波器

这个老贵~&#xff01;Price USD (US Dollar) $ 1595.00Network BitScope 442 ( BS442N )(原文件名:bs445n.png)(原文件名:bs440e.jpg)BS442NBS325NBS325UBS100UBS50UThe correct appearance of this website is only visible in graphical browsers that support web standard…

Java子类的成员方法可以直接调用父类的成员方法和成员变量

public class Teacher extends Employee {public static void main(String[] args) {}public void method() {super.method(); // 可以直接调父类的成员方法super.name; // 访问父类的成员变量System.out.println("子类方法执行&#xff01;");} }我的理解&#xff1…