GraphQL- Java实战入门

http://www.zhaiqianfeng.com/2017/06/learn-graphql-action-by-java.html

本篇主要使用graphql-java来演示如何使用Java来构建GraphQL API,文中使了Gradle作为构建工具,但未使用其特性,因此你也可以使用Maven,只是简单添加依赖即可。主要涉及到枚举(enum)、输入类型(input)、参数(argument)、接口(interface)、联合(union)等服务端,以及客户端查询测试。本例代码存放在 https://github.com/zhaiqianfeng/GraphQL-Demo/tree/master/java

GraphQL
添加依赖

gradle

 
    
compile 'com.graphql-java:graphql-java:3.0.0'

maven

 
    
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java</artifactId>
<version>3.0.0</version>
</dependency>

本文示例使用的构建工具是Gradle。

示例代码结构

示例结构目录如下

 
    
├── advance 高级示例
│   ├── GraphQL_argument.java 传入参数示例
│   ├── GraphQL_interface.java 接口示例
│   └── GraphQL_union.java 联合示例
├── get_start 入门示例
│   └── GraphQL_Simple.java 简单入门示例
└── model Java实体
├── Dog4Interface.java 为接口示例准备的Dog实现
├── Dog4Union.java 为联合示例准备的Dog
├── Fish4Interface.java 为接口示例准备的Fish实现
├── Fish4Union.java 为联合示例准备的Fish
├── IAnimal.java 为接口示例准备的Animal接口
└── User.java 为示例准备的User

每个示例基本遵循流程:提供带查询的示例数据-> 定义GrapQL数据类型 -> 定义暴露给客户端的query api和mutaion api -> 创建GraphQL Schema -> 测试输出

简单示例

示例代码如下

 
    
// com.zqf.get_start.GraphQL_Simple
//服务端示例数据
User user=new User();
user.setName("zhaiqianfeng");
user.setSex("男");
user.setIntro("博主,专注于Linux,Java,nodeJs,Web前端:Html5,JavaScript,CSS3");
//定义GraphQL类型
GraphQLObjectType userType = newObject()
.name("User")
.field(newFieldDefinition().name("name").type(GraphQLString))
.field(newFieldDefinition().name("sex").type(GraphQLString))
.field(newFieldDefinition().name("intro").type(GraphQLString))
.build();
//定义暴露给客户端的查询query api
GraphQLObjectType queryType = newObject()
.name("userQuery")
.field(newFieldDefinition().type(userType).name("user").staticValue(user))
.build();
//创建Schema
GraphQLSchema schema = GraphQLSchema.newSchema()
.query(queryType)
.build();
//测试输出
GraphQL graphQL = GraphQL.newGraphQL(schema).build();
Map<String, Object> result = graphQL.execute("{user{name,sex,intro}}").getData();
System.out.println(result);

执行输出

 
    
{user={name=zhaiqianfeng, sex=男, intro=博主,专注于Linux,Java,nodeJs,Web前端:Html5,JavaScript,CSS3}}

参数(argument)示例

参数示例代码比较多,请参考github上的源码:GraphQL_argument.java,做如下几点说明。

定义形参

传输参数是通过argument方法传入并指定类型,如

 
    
.argument(newArgument()
.name("id")
.type(new GraphQLNonNull(GraphQLInt)))

接收参数

获取参数使用DataFetchingEnvironment,如

 
    
int id=environment.getArgument("id");

获取参数有如下两个重构

 
    
Map<String, Object> getArguments();
<T> T getArgument(String name);

但当我使用后者把传入的userInfo转换为User时,异常

 
    
java.util.LinkedHashMap cannot be cast to com.zqf.model.User

因此不得不如下蹩脚书写

 
    
Map<String,Object> userInfoMap=environment.getArgument("userInfo");
User userInfo=new User();
for (String key : userInfoMap.keySet()){
switch (key){
case "name":
userInfo.setName(userInfoMap.get("name").toString());
break;
case "sex":
userInfo.setSex(userInfoMap.get("sex").toString());
break;
case "intro":
userInfo.setIntro(userInfoMap.get("intro").toString());
break;
case "skills":
ArrayList<String> skillsList=(ArrayList<String>) userInfoMap.get("skills");
String[] skills=new String[skillsList.size()];
userInfo.setSkills(skillsList.toArray(skills));
break;
}
}

Resolver

解析数据使用的是DataFetcher,如

 
    
.dataFetcher(new DataFetcher() {
@Override
public Object get(DataFetchingEnvironment environment) {
int id=environment.getArgument("id");
return users.get(id);
}
}))

为了简洁,你可以使用lambda表达式

 
    
.dataFetcher(environment -> {
int id=environment.getArgument("id");
return users.get(id);
}))

联合(union)示例

这部分没说明好说的,如果了解了union的概念代码示例非常清晰,请参考github上的源码:GraphQL_union.java。使用GraphQLUnionType定义union类型,其中possibleType指定可以union的类型,重点是关注typeResolver来做类型转换,但个人觉得这里实现有待改进,对于Java这种强类型语言自动处理比较人性化。

 
    
GraphQLUnionType animalUnion = newUnionType()//定义联合类型(union)
.name("IAnimal")
.possibleType(dogType)
.possibleType(fishType)
.description("动物联合")
.typeResolver(env -> {
if(env.getObject() instanceof Dog4Union){
return dogType;
}if(env.getObject() instanceof Fish4Union){
return fishType;
}
return null;
})
.build();

接口(interface)示例

graphql-java对GraphQL的接口实现确实使用的Java接口,但个人觉得使用集成或许更合适。定义接口使用的GraphQLInterfaceType关键字,实现接口使用的withInterface关键字。

坑:对象为定义

上面的关键字都不难理解,蛋疼的是把如下的定义放在方法体中却提示为定义

 
    
GraphQLInterfaceType animalInterface = newInterface()//定义接口(interface)类型
.name("IAnimal")
.description("动物接口")
.field(newFieldDefinition()
.name("name")
.type(GraphQLString))
.typeResolver(new TypeResolver() {
@Override
public GraphQLObjectType getType(TypeResolutionEnvironment env) {
if (env.getObject() instanceof Dog4Interface) {
return dogType; //提示 dogType 未定义
}
if (env.getObject() instanceof Fish4Interface) {
return fishType; //提示 fishType 未定义
}
return null;
}
})
.build();
GraphQLObjectType dogType = newObject()//定义Dog类型
.name("Dog4Interface")
.field(newFieldDefinition().name("name").type(GraphQLString))
.field(newFieldDefinition().name("legs").type(GraphQLInt))
.withInterface(animalInterface)
.build();
GraphQLObjectType fishType = newObject()//定义Fish类型
.name("Fish4Interface")
.field(newFieldDefinition().name("name").type(GraphQLString))
.field(newFieldDefinition().name("tailColor").type(GraphQLString))
.withInterface(animalInterface)
.build();

也看到了有开发者提了issue:Circularity between object and interface type definitions,但依然没看到有效的解决方案,只好顺着作者愿意,把上面的定义作为字段才能解决,具体代码可参考github上的源码:GraphQL_interface.java

Schema加入额外类型

最后还要提示下,由于查询返回的接口,但实现并没有自动添加到Schema中,因此需要在创建Schema时间,将其手动加入

 
    
//额外的GraphQL类型
Set<GraphQLType> types=new HashSet<>();
types.add(dogType);
types.add(fishType);
//创建Schema
GraphQLSchema schema = GraphQLSchema.newSchema()
.query(queryType)
.build(types);

结束语

虽然遇到了许多坑,但最后还是把需要的功能演示出来了,但无论是那种类库,基本的流程一般不会改变:基本遵循流程:定义GrapQL数据类型 -> 定义暴露给客户端的query api和mutaion api -> 创建GraphQL Schema

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
graphql-java 是 GraphQL 的 Java 实现。这个库的目标是用于真实的生产环境。graphql-java 解析和执行查询 GraphQL 。它并不真正获取任何数据的:数据来源于执行回调或提供静态数据。graphql-java 的 "hello world":import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLSchema; import static graphql.Scalars.GraphQLString; import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition; import static graphql.schema.GraphQLObjectType.newObject; public class HelloWorld {     public static void main(String[] args) {         GraphQLObjectType queryType = newObject()                         .name("helloWorldQuery")                         .field(newFieldDefinition()                                 .type(GraphQLString)                                 .name("hello")                                 .staticValue("world")                                 .build())                         .build();         GraphQLSchema schema = GraphQLSchema.newSchema()                         .query(queryType)                         .build();         Map result = new GraphQL(schema).execute("{hello}").getData();         System.out.println(result);         // Prints: {hello=world}     } } 标签:graphql

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值