GraphQL在Wildfly群上
“ GraphQL是API的查詢語(yǔ)言,是用于使用現(xiàn)有數(shù)據(jù)完成這些查詢的運(yùn)行時(shí)。 GraphQL為您的API中的數(shù)據(jù)提供了一個(gè)完整且易于理解的描述,使客戶能夠準(zhǔn)確地詢問(wèn)他們所需的內(nèi)容,僅此而已,使隨著時(shí)間的推移更容易開(kāi)發(fā)API并啟用強(qiáng)大的開(kāi)發(fā)人員工具。
–來(lái)自https://graphql.org/
任何已經(jīng)構(gòu)建了可供多個(gè)消費(fèi)者使用的REST服務(wù)的人,例如其他服務(wù),網(wǎng)站或移動(dòng)設(shè)備,都將知道很難構(gòu)建滿足所有需求的完美端點(diǎn)。 對(duì)于所有這些特殊情況,您通常最終都會(huì)獲得相同服務(wù)的變體:)
現(xiàn)在,我們都知道我們應(yīng)該只使用HATEOAS …,它在我的TODO列表中(承諾!),直到我偶然發(fā)現(xiàn)GraphQL為止 。
因此,在此博客文章中,我將解釋如何輕松地將GraphQL添加到現(xiàn)有的JAX-RS應(yīng)用程序中。
示例項(xiàng)目
Github中提供了示例項(xiàng)目,并且非常容易上手。
git clone https://github.com/phillip-kruger/membership.git cd membership mvn clean install這將使用示例應(yīng)用程序http:// localhost:8080 / membership /來(lái)啟動(dòng)fatjar wildfly-swarm
高水平
該示例是基本的成員資格服務(wù),您可以在其中獲得所有成員或特定成員。 您可以添加,編輯和刪除成員。
該應(yīng)用程序是典型的JAX-RS,CDI,EJB,JPA,Bean驗(yàn)證Java EE應(yīng)用程序,并且我們正在添加一個(gè)新的GraphQL端點(diǎn)。
GraphQL部分使用以下庫(kù):
- graphql-java
- graphql-java-servlet
- graphQL-spqr
- 石墨烯
我添加來(lái)將現(xiàn)有的JAX-RS公開(kāi)為GraphQL的唯一Java類:
- MembershipGraphQLListener –注冊(cè)“ / graphql” Servlet偵聽(tīng)器。
- MembershipGraphQLApi – GraphQL端點(diǎn)。 僅包裝現(xiàn)有的@Stateless服務(wù)。
- MembershipErrorHandler –處理異常。
使用graphQL-spqr的注釋, MembershipGraphQLApi類實(shí)際上只是描述和包裝了現(xiàn)有的@Stateless服務(wù):
@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)中提供一個(gè)JAX-QL(或其他東西),以使其變得更加簡(jiǎn)單!
首先是一些REST
我正在使用MicroProfile OpenAPI和Swagger UI為REST端點(diǎn)創(chuàng)建Open API定義。
您可以使用http:// localhost:8080 / membership / rest / openapi-ui /測(cè)試一些查詢
示例 –獲取所有成員資格:
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"}現(xiàn)在讓我們看一下GraphQL
該應(yīng)用程序包括GraphiQL UI(作為Webjar),可以輕松測(cè)試一些GraphQL查詢
您可以使用http:// localhost:8080 / membership / graph / graphiql /測(cè)試一些查詢
因此,讓我們看看GraphQL是否兌現(xiàn)了“不再需要過(guò)度提取和提取不足”的承諾。
獲取所有成員資格和所有字段(與REST相同)
query Memberships {memberships{...fullMembership}}fragment fullMembership on Membership {membershipIdowner{...owner}type}fragment owner on Person {idnamessurname }這將返回所有值,但是,現(xiàn)在很容易定義應(yīng)包括哪些字段…
獲取所有會(huì)員資格,但僅包括id字段
query Memberships {memberships{...membershipIdentifiers}}fragment membershipIdentifiers on Membership {membershipId}現(xiàn)在產(chǎn)生的有效負(fù)載要小得多:
{"data": {"memberships": [{"membershipId": 1},{"membershipId": 2},{"membershipId": 3},{"membershipId": 4}]}}現(xiàn)在,僅獲取特定類型的會(huì)員資格(因此,獲取所有免費(fèi)會(huì)員資格)
query FilteredMemberships {memberships(filter:{type:FREE}){...fullMembership}}fragment fullMembership on Membership {membershipIdowner{...owner}type}fragment owner on Person {idnamessurname }這將僅返回免費(fèi)會(huì)員資格。 好酷!
甚至更好,所有姓氏的成員都以“ Kru”開(kāi)頭
query FilteredMemberships {memberships(filter:{surnameContains: "Kru"}){...fullMembership}}fragment fullMembership on Membership {membershipIdowner{...owner}type}fragment owner on Person {idnamessurname }太好了! 我們找到了兩個(gè)人:
{"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"}}}分頁(yè)
讓我們使用get all查詢,但要分頁(yè)。
query Memberships($itemsPerPage:Int!,$pageNumber:Int!) {memberships(first:$itemsPerPage,skip:$pageNumber) {membershipIdowner{namessurname}type}}變量:
{"itemsPerPage": 2,"pageNumber": 1}這將返回前2個(gè)結(jié)果,然后您可以通過(guò)增加“ pageNumber”值來(lái)進(jìn)行分頁(yè)。
變異
創(chuàng)建
mutation CreateMember {createMembership(membership: {type:FULL,owner: {names: "James",surname:"Small"}}) {membershipId}}這將創(chuàng)建新的成員資格并返回ID。
更新資料
mutation EditMember($membership: MembershipInput!) {createMembership(membership:$membership) {membershipId}}變量:
{"membership": {"membershipId": 2,"owner": {"names": ["Charmaine","Juliet"],"surname": "Krüger"},"type": "FULL"}}(在克魯格大學(xué)添加了變音符號(hào),現(xiàn)在應(yīng)該是克魯格)
刪除
mutation DeleteMembership($id:Int!){deleteMembership(membershipId:$id){membershipId}}變量:
{"id":1}這將刪除成員資格1。
例外。
MembershipErrorHandler轉(zhuǎn)換一個(gè)ConstraintViolationException(在bean驗(yàn)證失敗時(shí)拋出),并為GraphQL創(chuàng)建一個(gè)不錯(cuò)的錯(cuò)誤消息。
因此,讓我們嘗試創(chuàng)建一個(gè)姓氏僅為一個(gè)字母的成員。
mutation CreateMember($membership: MembershipInput!) {createMembership(membership:$membership) {membershipId}}變量:
{"membership": {"owner": {"names": "Christina","surname": "S"},"type": "FULL"}}這將返回bean驗(yàn)證錯(cuò)誤消息:
{"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;內(nèi)省
GraphQL的另一個(gè)好處是,它具有可查詢的架構(gòu)和類型系統(tǒng):
{__schema {queryType {namefields {name}}mutationType{namefields{name}}subscriptionType {namefields{name}}}}上面將描述此端點(diǎn)上可用的查詢和變異。
您還可以描述您的模型:
{__type(name: "Membership") {namekindfields {nameargs {name}}}}摘要
在此示例中,我們沒(méi)有刪除REST,只是添加了GraphQL作為使用者的替代選項(xiàng)。
到現(xiàn)在為止,應(yīng)該清楚的是,客戶端具有更多的選項(xiàng)來(lái)完全根據(jù)需要過(guò)濾和查詢數(shù)據(jù)。 所有這些都無(wú)需服務(wù)器做任何額外的工作。 這樣可以在客戶端進(jìn)行快速的產(chǎn)品迭代。
線上的有效負(fù)載已得到優(yōu)化,我們正在節(jié)省帶寬!
再次,我希望–我們很快將在Java EE(或Jakarta EE或MicroProfile)中提供一個(gè)JAX-QL(或其他東西),以使其變得更加簡(jiǎn)單!
翻譯自: https://www.javacodegeeks.com/2018/05/graphql-on-wildfly-swarm.html
總結(jié)
以上是生活随笔為你收集整理的GraphQL在Wildfly群上的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java微妙_编码Java时的10个微妙
- 下一篇: javafx 示例_示例介绍:JavaF