“This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!”
introduce
GraphQL is a query language for the API, which is a server-side runtime that executes queries using a type system defined by your data. GraphQL isn’t tied to any particular database or storage engine, but relies on your existing code and data to support it. 1
GraphQL is both a query language for apis and a runtime that satisfies your data queries. GraphQL provides a complete and easy to understand description of the data in your API, allowing the client to get exactly what it needs without redundancy, making it easier for the API to evolve over time, and for building powerful developer tools. 2
Server to provide a defined schema (data types, representative can provide what formats of data), the client is decided by the query to actively want data format, data format of the initiative is in the front, similar to the relationship between the tables in the database and SQL, you can query the single table of one or more fields, joint field or more tables
- GraphQL can make the front end in the development process is not strongly dependent on the back-end service interface and data format, front and back end development is decoupled, can greatly reduce the front and back end developers’ communication costs
- GraphQL automatically generates API documents based on the schema
practice
This example is based on Spring Boot 2.2.6 and Graphql Java 16.1
If Spring Boot is later than 2.2 and GraphQL Java Tools is later than 5.4.x, you need to specify the version of Kotlin
WARNING: NoClassDefFoundError when using GraphQL Java Tools > 5.4.x
Introduction of depend on
<! -- com.graphql-java-kickstart for the latest groupId, com.graphql-java has stopped updating -->
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>11.0.0</version>
</dependency>
<! -- Altair -->
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>altair-spring-boot-starter</artifactId>
<version>11.0.0</version>
<scope>runtime</scope>
</dependency>
Copy the code
The maven repository shows that com.GraphqL-Java is still updated in 2018
Creating a Schema file
Create different Graphqls files for different business objects and place the Query and Mutation related schemas in the root.graphqls file
Default: **/*.graphqls file in classpath
# All other configurations are out of the box by default, there is no need to adjust
graphql:
tools:
schemaLocationPattern: graphqls/*.graphqls
Copy the code
The JS Graphql plugin supports identifying *.graphQL /*.graphqls files, and can quickly jump between declared query and type. The plugin supports WebStorm, IDEA and many other related products
The Query (read)
schema
# root.graphqls schema {query: query} type query {# [AuthorVO] getAuthor(id: Int): AuthorVO } # author.graphqls type AuthorVO { id: Int name: String title: String school: String } input AuthorQuery { name: String title: String school: String }Copy the code
Code
@Service
public class AuthorQueryResolver implements GraphQLQueryResolver {
private final AuthorRepository repository;
public AuthorQueryResolver(AuthorRepository repository) {
this.repository = repository;
}
public List<AuthorVO> listAuthors(AuthorQuery query) {
List<AuthorDO> list = repository.select(query);
return convertAll(list, AuthorVO.class);
}
public AuthorVO getAuthor(Integer id) {
AuthorDO entity = repository.selectById(id);
returnconvert(entity, AuthorVO.class); }}Copy the code
Run
QUERY {getAuthor(id: 1){id name title school}}Copy the code
Mutation (write)
schema
mutation{
saveAuthor(author: {
name: "Tomy"
title: "Teacher"
school: "BU"
})
}
Copy the code
Code
@Service
public class AuthorMutationResolver implements GraphQLMutationResolver {
private final AuthorRepository repository;
public AuthorMutationResolver(AuthorRepository repository) {
this.repository = repository;
}
public Integer saveAuthor(AuthorDTO dto) {
AuthorDO entity = convert(dto, AuthorDO.class);
repository.insert(entity);
return entity.getId();
}
public Boolean updateAuthor(Integer id, AuthorDTO dto) {
AuthorDO entity = convert(dto, AuthorDO.class);
entity.setId(id);
returnrepository.update(entity); }}Copy the code
Paging query
schema
# root.graphqls type Query { # .. other query pageBook(query: BookQuery): BookConnection } type PageInfo { hasNextPage: Boolean! hasPreviousPage: Boolean! } # book.graphqls type BookEdge { node: BookVO! cursor: String! } type BookConnection { edges: [BookEdge!] ! pageInfo: PageInfo! }Copy the code
Code
// com.jingwu.example.graphql.BookQueryResolver#pageBook
public Connection<BookVO> pageBook(BookQuery query) {
IPage<BookDO> page = repository.selectPage(query);
List<Edge<BookVO>> edges = page.getRecords()
.stream()
.map(book -> new DefaultEdge<>(
convert(book, BookVO.class),
new DefaultConnectionCursor(String.valueOf(book.getId())))
)
.collect(Collectors.toList());
PageInfo pageInfo =
new DefaultPageInfo(
GraphqlUtils.getStartCursorFrom(edges),
GraphqlUtils.getEndCursorFrom(edges),
page.getCurrent() > 1 && page.getCurrent() <= page.getPages(),
page.getPages() > page.getCurrent());
return new DefaultConnection<>(edges, pageInfo);
}
Copy the code
The usage here is treated like a normal paging query, which seems fine as long as the Connection object is returned
I don’t understand Connection, and I haven’t found the reason for using it. The official explanation is simple. You can still customize the Page Response object to return paging data
Other references:
- Spring Boot integrates GraphQL paging
- Pagination|Graphql
- Spring Boot GraphQL practices 03_ paging, global exception handling, and asynchronous loading
other
Interceptors/filters, global exception handling, Validation Validation, and so on are used in WebMVC in much the same way
Certification filter
@Component
public class AuthFilter extends OncePerRequestFilter {
@Autowired
private ObjectMapper objectMapper;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (doAuth(request)) {
response.setContentType("application/json; charset=UTF-8");
response.setCharacterEncoding("UTF-8");
ExecutionResultImpl build = ExecutionResultImpl.newExecutionResult()
.addError(new GenericGraphQLError("Authentication failed"))
.data(null)
.build();
response.getWriter().write(objectMapper.writeValueAsString(build.toSpecification()));
return;
}
filterChain.doFilter(request, response);
}
private boolean doAuth(HttpServletRequest request) {
// mock auth result
returnRandomUtil.randomBoolean(); }}Copy the code
A debugging tool
Altair, in addition to the Maven dependency introduction, also has a corresponding Chrome plugin, which I feel is more stable and useful than the Maven dependency
Altair GraphQL Client
In addition to the Altair, there are two
<! -- to embed GraphiQL tool -->
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphiql-spring-boot-starter</artifactId>
<version>11.0.0</version>
<scope>runtime</scope>
</dependency>
<! -- to embed Voyager tool -->
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>voyager-spring-boot-starter</artifactId>
<version>11.0.0</version>
<scope>runtime</scope>
</dependency>
Copy the code
Project address: gitee.com/jingwua/spr…
reference
- Introduction to GraphQL ↩
- A query language for the API ↩