背景
在和语言弱关联的这种框架或者结构下,一般都会有两种形式去实现某个功能,比如FaceBook 开源的thrift RPC框架,接口使用IDL来编写,可以用IDL生成特定语言的代码,也可以使用语言本身去编写相关的代码,其实GraphQL也是这样,你可以使用某种语言去解析SDL,帮你生成相关的Schema,你也可以手动去写代码生成相关的Schema。
SDL方式
schema.graphqls
type Query {
# 根据id查询书籍
bookById(id: ID): Book
# 根据id查询作者
authorById(id:ID):Author
# 查询所有的作者
allAuthor:[Author]!
# 查询所有的书籍
allBooks:[Book]!
}
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}
GraphQLProvider
package com.tangbaobao.graphql;
import com.google.common.base.Charsets;
import com.google.common.io.Resources;
import graphql.GraphQL;
import graphql.schema.GraphQLSchema;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.net.URL;
import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring;
/**
* @author tangxuejun
* @version 2020/4/1 12:40 上午
*/
@Component
public class GraphQLProvider {
final GraphQLDataFetchers graphQLDataFetchers;
private GraphQL graphQL;
public GraphQLProvider(GraphQLDataFetchers graphQLDataFetchers) {
this.graphQLDataFetchers = graphQLDataFetchers;
}
@PostConstruct
public void init() throws IOException {
URL url = Resources.getResource("schema.graphqls");
String sdl = Resources.toString(url, Charsets.UTF_8);
GraphQLSchema graphQLSchema = buildSchema(sdl);
this.graphQL = GraphQL.newGraphQL(graphQLSchema).build();
}
private GraphQLSchema buildSchema(String sdl) {
TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl);
RuntimeWiring runtimeWiring = buildWiring();
SchemaGenerator schemaGenerator = new SchemaGenerator();
return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring);
}
private RuntimeWiring buildWiring() {
return RuntimeWiring.newRuntimeWiring()
.type("Query",
builder -> builder.dataFetcher("bookById", graphQLDataFetchers.getBookByIdDataFetcher())
.dataFetcher("allAuthor", graphQLDataFetchers.allAuthor())
.dataFetcher("authorById", graphQLDataFetchers.getBookByIdDataFetcherWithId())
.dataFetcher("allBooks", graphQLDataFetchers.getAllBook())
)
.type(newTypeWiring("Book")
.dataFetcher("author", graphQLDataFetchers.getAuthorDataFetcher()))
.build();
}
@Bean
public GraphQL graphQL() {
return graphQL;
}
}
GraphQLDataFetchers
package com.tangbaobao.graphql;
import graphql.schema.DataFetcher;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* @author tangxuejun
* @version 2020/4/1 12:39 上午
*/
@Component
public class GraphQLDataFetchers {
private static List<Map<String, String>> books = Arrays.asList(
Map.of("id", "book-1",
"name", "Harry Potter and the Philosopher's Stone",
"pageCount", "223",
"authorId", "author-1"),
Map.of("id", "book-2",
"name", "Moby Dick",
"pageCount", "635",
"authorId", "author-2"),
Map.of("id", "book-3",
"name", "Interview with the vampire",
"pageCount", "371",
"authorId", "author-3")
);
private static List<Map<String, String>> authors = Arrays.asList(
Map.of("id", "author-1",
"firstName", "Joanne",
"lastName", "Rowling"),
Map.of("id", "author-2",
"firstName", "Herman",
"lastName", "Melville"),
Map.of("id", "author-3",
"firstName", "Anne",
"lastName", "Rice")
);
/**
* 获取所有作根据id查询书籍
* @return
*/
public DataFetcher getBookByIdDataFetcher() {
return dataFetchingEnvironment -> {
String bookId = dataFetchingEnvironment.getArgument("id");
return books
.stream()
.filter(book -> book.get("id").equals(bookId))
.findFirst()
.orElse(null);
};
}
/**
* 根据id查询作者
* @return
*/
public DataFetcher getAuthorByIdDataFetcherWithId() {
return dataFetchingEnvironment -> {
String authorId = dataFetchingEnvironment.getArgument("id");
return authors
.stream()
.filter(author -> author.get("id").equals(authorId))
.findFirst()
.orElse(null);
};
}
/**
* 根据作者id查询
* @return
*/
public DataFetcher getAuthorDataFetcher() {
return dataFetchingEnvironment -> {
Map<String, String> book = dataFetchingEnvironment.getSource();
String authorId = book.get("authorId");
return authors
.stream()
.filter(author -> author.get("id").equals(authorId))
.findFirst()
.orElse(null);
};
}
/**
* 获取所有作者
* @return
*/
public DataFetcher allAuthor() {
return dataFetchingEnvironment -> authors;
}
/**
* 获取所有书籍
* @return
*/
public DataFetcher getAllBook() {
return dataFetchingEnvironment -> books;
}
}
JavaType 方式
GraphQLProviderWithOutSDL
package com.tangbaobao.graphql;
import graphql.GraphQL;
import graphql.schema.GraphQLList;
import graphql.schema.GraphQLObjectType;
import graphql.schema.GraphQLSchema;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import static graphql.Scalars.*;
import static graphql.schema.GraphQLArgument.newArgument;
import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
import static graphql.schema.GraphQLObjectType.newObject;
/**
* @author tangxuejun
* @version 2020/4/1 2:43 下午
*/
@Component
public class GraphQLProviderWithOutSDL {
final GraphQLDataFetchers graphQLDataFetchers;
private GraphQL graphQL;
public GraphQLProviderWithOutSDL(GraphQLDataFetchers graphQLDataFetchers) {
this.graphQLDataFetchers = graphQLDataFetchers;
}
@Bean
public GraphQL graphQL() {
return graphQL;
}
@PostConstruct
public void init() {
GraphQLObjectType graphQLObjectType = this.getGraphQLObjectType();
GraphQLSchema schema = GraphQLSchema.newSchema()
.query(graphQLObjectType)
.build();
graphQL = GraphQL.newGraphQL(schema).build();
}
public GraphQLObjectType getGraphQLObjectType() {
// 定义GraphQL类型
GraphQLObjectType authorType = newObject().name("Author")
.field(newFieldDefinition().name("id").type(GraphQLID))
.field(newFieldDefinition().name("firstName").type(GraphQLString))
.field(newFieldDefinition().name("lastName").type(GraphQLString)).build();
GraphQLObjectType bookType = newObject().name("Book")
.field(newFieldDefinition().name("id").type(GraphQLID))
.field(newFieldDefinition().name("name").type(GraphQLString))
.field(newFieldDefinition().name("pageCount").type(GraphQLInt))
.field(newFieldDefinition().name("author").type(authorType)
.dataFetcher(graphQLDataFetchers.getAuthorDataFetcher()))
.build();
//编写GraphQL query
GraphQLObjectType queryType = newObject()
.name("Query")
.field(newFieldDefinition()
.type(authorType)
.name("authorById")
.dataFetcher(graphQLDataFetchers.getAuthorByIdDataFetcherWithId())
.argument(newArgument().name("id").type(GraphQLID).build()))
.field(newFieldDefinition()
.type(bookType)
.name("bookById")
.dataFetcher(graphQLDataFetchers.getBookByIdDataFetcher())
.argument(newArgument().name("id").type(GraphQLID).build()))
.field(newFieldDefinition()
.type(GraphQLList.list(authorType))
.name("allAuthor")
.dataFetcher(graphQLDataFetchers.allAuthor()))
.field(newFieldDefinition()
.type(GraphQLList.list(bookType))
.name("allBooks")
.dataFetcher(graphQLDataFetchers.getAllBook()))
.build();
return queryType;
}
}