graphql api java_记录初学Spring boot中使用GraphQL编写API的几种方式

Spring boot+graphql

一、使用graphql-java-tools方式

com.graphql-java-kickstart

graphql-java-tools

5.6.0

com.graphql-java-kickstart

graphiql-spring-boot-starter

5.0.4

schema.graphqls

type Query {

books: [Book!]

}

type Book {

id: Int!

name: String!

author: Author!

}

type Author {

id: Int!

name: String!

}

对应的java class

class Book {

private int id;

private String name;

private int authorId;

// constructor

// getId

// getName

// getAuthorId

}

class Author {

private int id;

private String name;

// constructor

// getId

// getName

}

Book-Resolver

class BookResolver implements GraphQLResolver {

private AuthorRepository authorRepository;

public BookResolver(AuthorRepository authorRepository) {

this.authorRepository = authorRepository;

}

public Author author(Book book) {

return authorRepository.findById(book.getAuthorId());

}

}

Query-Resolver

class Query implements GraphQLQueryResolver {

private BookRepository bookRepository;

public Query(BookRepository bookRepository) {

this.bookRepository = bookRepository;

}

public List books() {

return bookRepository.findAll();

}

}

Type Query 没有对应的java class,如果type 中的所有字段和java class成员变量一致,则该type可以不用定义Resolver.

graphql type中的字段映射Java class字段的优先级

对于graphql objectType中的字段映射为java class字段顺序如下:

method (*fieldArgs [, DataFetchingEnvironment])

method is(*fieldArgs [, DataFetchingEnvironment]), only if the field returns a Boolean

method get(*fieldArgs [, DataFetchingEnvironment])

method getField(*fieldArgs [, DataFetchingEnvironment])

field

例如:

上述type Book中的name字段的映射顺序为:

在java Book类中找name(参数)方法。

如果Book类中没有name(参数)方法,则继续找isName(参数)方法。

如果Book中没有isName(参数)方法,则继续在Book中找getName(参数)方法。

如果Book中没有getName()方法,则继续在Book中找getFieldName(参数)方法。

如果Book中没有getFieldName(参数)方法,在继续在Book中找name成员变量。

如果Book中没有name成员变量,则报错。

graphql type中的字段映射Resolver的优先级:

method (dataClassInstance, *fieldArgs [, DataFetchingEnvironment])

method is(dataClassInstance, *fieldArgs [, DataFetchingEnvironment]), only if the field returns a Boolean

method get(dataClassInstance, *fieldArgs [, DataFetchingEnvironment])

method getField(dataClassInstance, *fieldArgs [, DataFetchingEnvironment])

注:Resolver的映射优先级高于Java Class,首先在Resolver中查找,如果没找到,才会在Java class中查找 :例如上述type Book中的author字段,会首先映射为BookResolver重的author(Book)方法。

解析schema.graphqls,创建Graphql对象:

import com.coxautodev.graphql.tools.SchemaParser;

GraphQLSchema schema = SchemaParser.newParser().file("schema.graphqls")

.resolvers(new QueryResolver(), new BookResolver())

.build()

.makeExecutableSchema();

GraphQL graphQL = GraphQL.newGraphQL(schema).build();

// 执行查询

ExecutionResult result = graphQL.execute(query);

Map map = result.toSpecification();

二、不使用Resolver

schema.graphqls:

type Query {

bookById(id: ID): Book

}

type Book {

id: ID

name: String

pageCount: Int

author: Author

}

type Author {

id: ID

firstName: String

lastName: String

}

加载schema.graphqls,创建GraphQL对象:

import graphql.schema.idl.SchemaParser;

@Value("classpath:schema.graphqls")

Resource resource;

@PostConstruct

private void loadSchema() throws Exception {

File schemaFile = resource.getFile();

GraphQLSchema schema = buildSchema(schemaFile);

graphQL = GraphQL.newGraphQL(schema).build();

}

private GraphQLSchema buildSchema(File file) throws Exception {

TypeDefinitionRegistry registry = new SchemaParser().parse(file);

RuntimeWiring runtimeWiring = buildWiring();

SchemaGenerator schemaGenerator = new SchemaGenerator();

return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring);

}

private RuntimeWiring buildWiring() {

return RuntimeWiring.newRuntimeWiring()

// 为每个graphql type的字段提供DataFetcher

.type(newTypeWiring("Query")

.dataFetcher("bookById", graphQLDataFetchers.getBookByIdDataFetcher()))

.type(newTypeWiring("Book")

.dataFetcher("author", graphQLDataFetchers.getAuthorDataFetcher()))

.build();

}

DataFetcher:

@Component

public class GraphQLDataFetchers {

private static List> books = Arrays.asList(

ImmutableMap.of("id", "book-1",

"name", "Harry Potter and the Philosopher's Stone",

"pageCount", "223",

"authorId", "author-1"),

ImmutableMap.of("id", "book-2",

"name", "Moby Dick",

"pageCount", "635",

"authorId", "author-2"),

ImmutableMap.of("id", "book-3",

"name", "Interview with the vampire",

"pageCount", "371",

"authorId", "author-3")

);

private static List> authors = Arrays.asList(

ImmutableMap.of("id", "author-1",

"firstName", "Joanne",

"lastName", "Rowling"),

ImmutableMap.of("id", "author-2",

"firstName", "Herman",

"lastName", "Melville"),

ImmutableMap.of("id", "author-3",

"firstName", "Anne",

"lastName", "Rice")

);

public DataFetcher getBookByIdDataFetcher() {

return dataFetchingEnvironment -> {

String bookId = dataFetchingEnvironment.getArgument("id");

return books

.stream()

.filter(book -> book.get("id").equals(bookId))

.findFirst()

.orElse(null);

};

}

public DataFetcher getAuthorDataFetcher() {

return dataFetchingEnvironment -> {

Map book = dataFetchingEnvironment.getSource();

String authorId = book.get("authorId");

return authors

.stream()

.filter(author -> author.get("id").equals(authorId))

.findFirst()

.orElse(null);

};

}

}

注:这种方式,并不要求一定要提供type对应的java class,只要在对应的DataFetcher中返回符合type的数据格式即可

三、方式三,不使用graphql-java-tools

不定义schema.graphqls,以编码的方式创建graphql type。

定义graphql type:

GraphQLObjectType fooType = newObject()

.name("Foo")

.field(newFieldDefinition()

.name("bar")

.type(GraphQLString))

.build();

上述代码相当于使用schema方式创建了如下graphql type:

type Foo {

bar: String

}

为类型的field指定DataFetcher:

DataFetcher fooDataFetcher = environment -> {

// environment.getSource() is the value of the surrounding

// object. In this case described by objectType

Foo value = perhapsFromDatabase(); // Perhaps getting from a DB or whatever

return value;

}

GraphQLObjectType objectType = newObject()

.name("ObjectType")

.field(newFieldDefinition()

.name("foo")

.type(GraphQLString)

.dataFetcher(fooDataFetcher))

.build();

完整的代码:

// 定义一个type Query

/**

* 相当于 type QueryType{ hello: String }

*/

GraphQLObjectType queryType = newObject()

.name("QueryType")

.field(newFieldDefinition()

.name("hello")

.type(GraphQLString)

.dataFetcher(new StaticDataFetcher("world!"))

.build();

// 创建GraphQLSchema

GraphQLSchema schema = GraphQLSchema.newSchema()

.query(queryType)

.build();

// Make the schema executable

GraphQL executor = GraphQL.newGraphQL(graphQLSchema).build();

ExecutionResult executionResult = executor.execute("{hello}");

四、参考链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值