“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


  1. Introduction to GraphQL ↩
  2. A query language for the API ↩