赞
踩
组件对外提供了一个Rest用于传递输入的GQL语句与入参,如图所示,展示了一个按协议类型查询端口id和名称的例子:
查询语句:
{
"query": "query{filterLtp(key:\"layer\",value:[\"IP\"]){ltp{id,name}}}",
"variables": {}
}
返回结果如图:
定义需要返回展示的数据模型,由于gql的schema模型不直接支持map结构,所以建议在设计模型时避免使用map结构。否则需要借助gql的列表和union来组装实现,多了一层模型的封装。以下为返回的Link模型部分定义:
type GraphLink {
link: LinkEx
srcLtp: LtpEx
dstLtp: LtpEx
}
type LinkEx { id: String from: From name: String layer: Layer controlDomain: String manageDomain: String key: String modelType: ModelType i18nLabel: I18nLabel moc: String displayName: String fromId: String srcTopoId: String srcNodeId: String srcTpId: String dstTopoId: String dstNodeId: String dstTpId: String direction: Direction state: State faultAlert: FaultAlert grFlag: Boolean isMultiDomain: Boolean linkExtensions: [LinkExtension] }
union LinkExtension = IpLinkExtension | EthLinkExtension
type IpLinkExtension {
igpMetric: Int
performance: Performance
capacity: Capacity
routeDomain: String
srlg: [Int]
adjSid: String
peerNodeSid: String
peerAdjSid: String
linkMaxStackDepth: String
affinity: Int
linkMtId: Int
}
type Performance {
id: String
modelType: ModelType
metric: Int
delay: Int
jitter: Int
wander: Int
queueDelay: String
averageRate: Float
originMetric: Int
}
针对Link模型封装了一层LinkEx,其主要的原则即是标准的Link模型中使用了map结构
@ApiModelProperty(value = "扩展属性")
private Map<String, LinkExtension> extensions = new ConcurrentHashMap<String, LinkExtension>();
GQL中不支持对于extension直接描述,所以封装了一层,使用 linkExtensions: [LinkExtension]作了适配,更进一步,如果extensions定义成List<LinkExtension>则可以直接使用Link模型。而目录不得已需要使用LinkEx模型,如下:
public class LinkEx extends Link implements Res{
private List<LinkExtension> linkExtensions;
}
schema {
query: graphTopoQuery
}
type graphTopoQuery {
filterLink(key:String,value:[String],offset:Int,limit:Int) : [GraphLink]
}
定义一个4个入参的返回为GraphLink列表的接口。
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java</artifactId>
<version>8.0</version>
</dependency>
<dependency>
<groupId>org.reactivestreams</groupId>
<artifactId>reactive-streams</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
<version>4.7.2</version>
</dependency>
TypeDefinitionRegistry typeRegistry = TopologyTypeDefinitionRegistry.load("graphLink.graphqls");
public static TypeDefinitionRegistry load(String gql) {
InputStream inputStream = TopologyTypeDefinitionRegistry.class.getClassLoader().getResourceAsStream(gql);
SchemaParser schemaParser = new SchemaParser();
try (InputStreamReader inputStreamReader = new InputStreamReader(inputStream)) {
return schemaParser.parse(inputStreamReader);
} catch (IOException e) {
logger.error("TopologyTypeDefinitionRegistry error.", e);
}
return null;
}
RuntimeWiring wiring = TopologyRuntimeWiring.builder()
.type("Res", typeWiring -> typeWiring.typeResolver(getTypeResolverOfRes()))
.type("graphTopoQuery", typeWiring -> typeWiring
.dataFetcher("filterLink", graphLinkFilterDataFetcher).type("LinkEx", typeWiring -> typeWiring.dataFetcher("linkExtensions", graphIpLinkExtensionFilterDataFetcher)).type("GraphLink", typeWiring -> typeWiring.dataFetcher("srcLtp", srcLtpDataFetcher).dataFetcher("srcLtp", dstLtpDataFetcher))
.build();
public static TypeResolver getTypeResolverOfRes() {
return new TypeResolver() {
@Override
public GraphQLObjectType getType(TypeResolutionEnvironment env) {
Object javaObject = env.getObject();
if (javaObject instanceof NodeEx) {
return env.getSchema().getObjectType("NodeEx");
} else if (javaObject instanceof LinkEx) {
return env.getSchema().getObjectType("LinkEx");
}
}
};
}
针对需要二次查询的都需要定义DataFetecher
SchemaGenerator schemaGenerator = new SchemaGenerator();
GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeRegistry, wiring);
graphQL = GraphQL.newGraphQL(graphQLSchema).build();
对外接口:
public String query(GraphInput input) {
long currentTime = System.currentTimeMillis();
ExecutionInput executionInput = ExecutionInput.newExecutionInput().variables(input.getVariables())
.query(input.getQuery())
.build();
Map<String, Object> result = graphQL.execute(executionInput).toSpecification();
logger.info("Rest Invoke graphql query with input:[{}] cost:{} ms", input, System.currentTimeMillis() - currentTime);
return GraphResult.serialize(result);
}
入参定义:
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
@JsonNaming(PropertyNamingStrategy.KebabCaseStrategy.class)
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiModel(description = "com.zte.sdn.oscp.topology.model.graph.input.GraphInput")
public class GraphInput {
private String query;
private Map<String, Object> variables;
}
接口定义:
@POST
@Path("graphql")
@ApiOperation(value = "基于Graph查询接口")
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 400, message = "operation got an error")
})
String query(
GraphInput input) throws TopologyException;
效果图如下:
为了你应用能与GraphiQL集成,要求在GraphiQL的输入URL后默认的schema查询有正确返回,此时接收GQL语句的查询query,如下所示:
query{
__schema{
types {
name
description
}
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。