1. Overview
1.概述
GraphQL is a relatively new concept for building web services as an alternative to REST. A few Java libraries have recently emerged for creating and calling GraphQL services.
GraphQL是一个相对较新的概念,用于构建作为REST替代品的Web服务。最近出现了一些用于创建和调用GraphQL服务的Java库。
In this tutorial, we’ll look at GraphQL schema, queries, and mutations. We’ll see how to create and mock a simple GraphQL server in plain Java. Then, we’ll explore how to make calls to GraphQL services using well-known HTTP libraries.
在本教程中,我们将研究GraphQL模式、查询和变异。我们将看到如何在普通Java中创建和模拟一个简单的GraphQL服务器。然后,我们将探讨如何使用著名的HTTP库来调用GraphQL服务。
Finally, we’ll also explore the available 3rd party libraries for making GraphQL service calls.
最后,我们还将探索可用的第三方库,以进行GraphQL服务调用。
2. GraphQL
2.GraphQL
GraphQL is a query language for web services and a server-side runtime for executing queries using a type system.
GraphQL是一种网络服务的查询语言和使用类型系统执行查询的服务器端运行时间。
A GraphQL server specifies the API capabilities using a GraphQL schema. This allows the GraphQL client to specify exactly which data to retrieve from the API. This may include child resources and multiple queries in a single request.
GraphQL服务器使用GraphQL模式来指定API的能力。这使得GraphQL客户端可以准确地指定从API中检索的数据。这可能包括单一请求中的子资源和多个查询。
2.1. GraphQL Schema
2.1 GraphQL方案
A GraphQL server defines services with a set of types. Those types describe the set of possible data you can query using the service.
GraphQL服务器用一组类型来定义服务。这些类型描述了你可以使用该服务查询的可能数据集。
GraphQL services can be written in any language. However, GraphQL schemas need to be defined using a DSL called GraphQL schema language.
GraphQL服务可以用任何语言编写。然而,GraphQL模式需要使用一种叫做GraphQL模式语言的DSL来定义。
In our example GraphQL schema, we’ll define two types (Book and Author) and a single query operation to fetch all books (allBooks):
在我们的GraphQL模式示例中,我们将定义两种类型(Book和Author)和一个获取所有书籍的单一查询操作(allBooks)。
type Book {
title: String!
author: Author
}
type Author {
name: String!
surname: String!
}
type Query {
allBooks: [Book]
}
schema {
query: Query
}
The Query type is special because it defines the entry point of a GraphQL query.
Query类型很特别,因为它定义了GraphQL查询的入口点。
2.2. Queries and Mutations
2.2.查询和突变
A GraphQL service is created by defining types and fields, as well as providing functions for different fields.
一个GraphQL服务是通过定义类型和字段,以及为不同字段提供函数来创建的。
In its simplest form, GraphQL is about asking for specific fields on objects. For example, we might query to fetch all book titles:
在其最简单的形式中,GraphQL是关于询问对象的特定字段。例如,我们可以查询获取所有书名。
{
"allBooks" {
"title"
}
}
Even though it looks similar, this is not JSON. It’s a special GraphQL query format that supports arguments, aliases, variables, and more.
尽管它看起来很相似,但这不是JSON。它是一种特殊的GraphQL查询格式,支持参数、别名、变量等。
A GraphQL service would respond to the above query with a JSON formatted response like this:
一个GraphQL服务将以JSON格式的响应来回应上述查询,就像这样。
{
"data": {
"allBooks": [
{
"title": "Title 1"
},
{
"title": "Title 2"
}
]
}
}
In this tutorial, we’ll focus on data fetching using queries. However, it’s important to mention another special concept within GraphQL – mutation.
在本教程中,我们将专注于使用查询来获取数据。然而,有必要提及GraphQL中的另一个特殊概念–突变。
Any operation that can cause modification is sent using a mutation type.
任何能引起修改的操作都要使用突变类型来发送。
3. GraphQL Server
3.图形QL服务器
Let’s create a simple GraphQL server in Java using the schema we defined above. We’ll make use of the GraphQL Java library for our GraphQL server implementation.
让我们使用我们上面定义的模式在Java中创建一个简单的GraphQL服务器。我们将利用GraphQL Java库来实现我们的GraphQL服务器。
We’ll start by defining our GraphQL query and implement the allBooks method specified in our example GraphQL schema:
我们将首先定义我们的GraphQL查询,并实现示例GraphQL模式中指定的allBooks方法。
public class GraphQLQuery implements GraphQLQueryResolver {
private BookRepository repository;
public GraphQLQuery(BookRepository repository) {
this.repository = repository;
}
public List<Book> allBooks() {
return repository.getAllBooks();
}
}
Next, in order to expose our GraphQL endpoint, we’ll create a web servlet:
接下来,为了暴露我们的GraphQL端点,我们将创建一个Web servlet。
@WebServlet(urlPatterns = "/graphql")
public class GraphQLEndpoint extends HttpServlet {
private SimpleGraphQLHttpServlet graphQLServlet;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
graphQLServlet.service(req, resp);
}
@Override
public void init() {
GraphQLSchema schema = SchemaParser.newParser()
.resolvers(new GraphQLQuery(new BookRepository()))
.file("schema.graphqls")
.build()
.makeExecutableSchema();
graphQLServlet = SimpleGraphQLHttpServlet
.newBuilder(schema)
.build();
}
}
In the servlet init method, we’ll parse our GraphQL schema located in the resources folder. Finally, using the parsed schema, we can create an instance of a SimpleGraphQLHttpServlet.
在Servlet的init方法中,我们将解析位于资源文件夹中的GraphQL模式。最后,使用解析后的模式,我们可以创建一个SimpleGraphQLHttpServlet的实例。
We’ll make use of the maven-war-plugin to package our application and jetty-maven-plugin to run it:
我们将利用maven-war-plugin来打包我们的应用程序, jetty-maven-plugin来运行它。
mvn jetty:run
Now we are ready to run and test our GraphQL service by sending a request to:
现在我们已经准备好运行和测试我们的GraphQL服务,发送一个请求到。
http://localhost:8080/graphql?query={allBooks{title}}
4. HTTP Client
4.HTTP客户端
As with REST services, GraphQL services are exposed via the HTTP protocol. Therefore, we can use any Java HTTP client to make a call to a GraphQL service.
与REST服务一样,GraphQL服务是通过HTTP协议公开的。因此,我们可以使用任何Java HTTP客户端来对GraphQL服务进行调用。
4.1. Sending Requests
4.1.发送请求
Let’s try to send a request to a GraphQL service we created in the previous section:
让我们尝试向我们在上一节创建的GraphQL服务发送一个请求。
public static HttpResponse callGraphQLService(String url, String query)
throws URISyntaxException, IOException {
HttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(url);
URI uri = new URIBuilder(request.getURI())
.addParameter("query", query)
.build();
request.setURI(uri);
return client.execute(request);
}
In our example, we used Apache HttpClient. However, any Java HTTP client can be used.
在我们的例子中,我们使用了Apache HttpClient>。然而,任何Java HTTP客户端都可以被使用。
4.2. Parsing Responses
4.2.解析回应
Next, let’s parse the response from a GraphQL service. GraphQL services send JSON formatted responses, same as REST services:
接下来,让我们解析来自GraphQL服务的响应。GraphQL服务发送JSON格式的响应,与REST服务相同。
HttpResponse httpResponse = callGraphQLService(serviceUrl, "{allBooks{title}}");
String actualResponse = IOUtils.toString(httpResponse.getEntity().getContent(), StandardCharsets.UTF_8.name());
Response parsedResponse = objectMapper.readValue(actualResponse, Response.class);
assertThat(parsedResponse.getData().getAllBooks()).hasSize(2);
In our example, we used ObjectMapper from the popular Jackson library. However, we may use any Java library for JSON serialization/deserialization.
在我们的例子中,我们使用了ObjectMapper,来自流行的Jackson库。然而,我们可以使用任何Java库进行JSON序列化/反序列化。
4.3. Mocking Responses
4.3.嘲弄的回应
As with any other service exposed via HTTP, we can mock GraphQL server responses for testing purposes.
与其他通过HTTP暴露的服务一样,我们可以模拟GraphQL服务器响应,以达到测试目的。
We can make use of the MockServer library for stubbing external GraphQL HTTP services:
我们可以利用MockServer库来存根外部GraphQL HTTP服务。
String requestQuery = "{allBooks{title}}";
String responseJson = "{\"data\":{\"allBooks\":[{\"title\":\"Title 1\"},{\"title\":\"Title 2\"}]}}";
new MockServerClient(SERVER_ADDRESS, serverPort)
.when(
request()
.withPath(PATH)
.withQueryStringParameter("query", requestQuery),
exactly(1)
)
.respond(
response()
.withStatusCode(HttpStatusCode.OK_200.code())
.withBody(responseJson)
);
Our example mock server will accept a GraphQL query as a parameter and respond with a JSON response in the body.
我们的示例模拟服务器将接受一个GraphQL查询作为参数,并在正文中响应一个JSON响应。
5. External Libraries
5.外部图书馆
A couple of Java GraphQL libraries that allow even simpler GraphQL service calls have emerged recently.
最近出现了几个Java GraphQL库,允许更简单的GraphQL服务调用。
5.1. American Express Nodes
5.1.美国运通节点
Nodes is a GraphQL client from American Express designed for constructing queries from standard model definitions. To start using it, we should first add the required dependency:
Nodes是一个来自美国运通的GraphQL客户端,旨在从标准模型定义中构建查询。要开始使用它,我们应该首先添加所需的依赖性。
<dependency>
<groupId>com.github.americanexpress.nodes</groupId>
<artifactId>nodes</artifactId>
<version>0.5.0</version>>
</dependency>
The library is currently hosted on JitPack, which we should also add to our Maven installation repositories:
该库目前托管在JitPack上,我们也应该把它添加到我们的Maven安装库中。
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
Once the dependency is resolved, we can make use of the GraphQLTemplate to construct a query and call our GraphQL service:
一旦解决了依赖关系,我们就可以利用GraphQLTemplate来构建查询并调用我们的GraphQL服务。
public static GraphQLResponseEntity<Data> callGraphQLService(String url, String query)
throws IOException {
GraphQLTemplate graphQLTemplate = new GraphQLTemplate();
GraphQLRequestEntity requestEntity = GraphQLRequestEntity.Builder()
.url(StringUtils.join(url, "?query=", query))
.request(Data.class)
.build();
return graphQLTemplate.query(requestEntity, Data.class);
}
Nodes will parse a response from the GraphQL service using the class we specified:
Nodes将使用我们指定的类来解析来自GraphQL服务的响应。
GraphQLResponseEntity<Data> responseEntity = callGraphQLService(serviceUrl, "{allBooks{title}}");
assertThat(responseEntity.getResponse().getAllBooks()).hasSize(2);
We should note that Nodes still requires us to construct our own DTO classes for parsing the response.
我们应该注意,Nodes仍然需要我们构建自己的DTO类来解析响应。
5.2. GraphQL Java Generator
5.2.GraphQL Java生成器
The GraphQL Java Generator library makes use of the ability to generate Java code based on GraphQL schema.
GraphQL Java Generator库利用了基于GraphQL模式生成Java代码的能力。
This approach is similar to WSDL code generators used in SOAP services. To start using it, we should first add the required dependency:
这种方法类似于SOAP服务中使用的WSDL代码生成器。要开始使用它,我们应该首先添加所需的依赖性。
<dependency>
<groupId>com.graphql-java-generator</groupId>
<artifactId>graphql-java-runtime</artifactId>
<version>1.18</version>
</dependency>
Next, we can configure graphql-maven-plugin to execute a generateClientCode goal:
接下来,我们可以配置 graphql-maven-plugin来执行generateClientCode目标。
<plugin>
<groupId>com.graphql-java-generator</groupId>
<artifactId>graphql-maven-plugin</artifactId>
<version>1.18</version>
<executions>
<execution>
<goals>
<goal>generateClientCode</goal>
</goals>
</execution>
</executions>
<configuration>
<packageName>com.baeldung.graphql.generated</packageName>
<copyRuntimeSources>false</copyRuntimeSources>
<generateDeprecatedRequestResponse>false</generateDeprecatedRequestResponse>
<separateUtilityClasses>true</separateUtilityClasses>
</configuration>
</plugin>
Once we run the Maven build command, the plugin will generate both DTOs and utility classes required for calling our GraphQL service.
一旦我们运行Maven构建命令,该插件将生成调用GraphQL服务所需的DTO和实用类。
The generated QueryExecutor component will contain methods for calling our GraphQL service and parsing its response:
生成的QueryExecutor组件将包含调用我们的GraphQL服务和解析其响应的方法。
public List<Book> allBooks(String queryResponseDef, Object... paramsAndValues)
throws GraphQLRequestExecutionException, GraphQLRequestPreparationException {
logger.debug("Executing query 'allBooks': {} ", queryResponseDef);
ObjectResponse objectResponse = getAllBooksResponseBuilder()
.withQueryResponseDef(queryResponseDef).build();
return allBooksWithBindValues(objectResponse,
graphqlClientUtils.generatesBindVariableValuesMap(paramsAndValues));
}
However, it’s built for use with the Spring framework.
然而,它是为与Spring框架一起使用而构建的。
6. Conclusion
6.结语
In this article, we explored how to make a call to a GraphQL service from a Java application.
在这篇文章中,我们探讨了如何从Java应用中调用GraphQL服务。
We learned how to create and mock a simple GraphQL server. Next, we saw how to send a request and retrieve a response from a GraphQL server using a standard HTTP library. We also saw how to parse the GraphQL service responses from JSON to a Java object.
我们学习了如何创建和模拟一个简单的GraphQL服务器。接下来,我们看到了如何使用标准的HTTP库从GraphQL服务器发送请求和检索响应。我们还看到了如何将GraphQL服务的响应从JSON解析为一个Java对象。
Finally, we looked at two available 3rd party libraries for making GraphQL service calls, Nodes and GraphQL Java Generator.
最后,我们看了两个可用的第三方库,用于进行GraphQL服务调用,Nodes和GraphQL Java Generator。
As always, the complete source code is available over on GitHub.
一如既往,完整的源代码可在GitHub上获得,。