[译]使用Spring Boot搭建简单GraphQL服务指南

原文地址java

GraphQL 是一种用于 API 的查询语言,使得客户端可以准确地得到它须要的数据,并且没有任何冗余。GraphQL是一种强类型协议,全部数据操做都会根据 GraphQL Schema 来进行校验。git

在本文中,咱们将使用Spring Boot构建一个简单的GraphQL服务器。

添加Maven依赖项

建立示例Spring Boot应用程序并添加如下依赖项。github

  • graphql-spring-boot-starterweb

    用于启用 GraphQL 控制器,并使其在 path/graphql 中可用。它将初始化GraphQL Schema bean。
    复制代码
  • graphql-javaspring

    可使用易于理解的Graphql Schema 语言来编写 schema。
    复制代码
  • graphiql-spring-boot-starterapache

    提供图形界面,咱们可使用它来测试 GraphQL 查询和查看查询定义。
    复制代码
<dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-spring-boot-starter</artifactId>
            <version>5.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-java-tools</artifactId>
            <version>5.2.4</version>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphiql-spring-boot-starter</artifactId>
            <version>5.0.2</version>
        </dependency>
复制代码

如下完整的POM文件内容。浏览器

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.techshard.graphql</groupId>
    <artifactId>springboot-graphql</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath />
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-spring-boot-starter</artifactId>
            <version>5.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-java-tools</artifactId>
            <version>5.2.4</version>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphiql-spring-boot-starter</artifactId>
            <version>5.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
复制代码

建立JPA实体和存储库

接下来让咱们建立一个名为Vehicle的简单实体和相应的JPA存储库。咱们将使用Lombok来编写,这样能够避免编写诸如getter和setter等等的样板文件。springboot

package com.techshard.graphql.dao.entity;

import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDate;

@Data
@EqualsAndHashCode
@Entity
public class Vehicle implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "ID", nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Column(name = "type", nullable = false)
    private String type;

    @Column(name = "model_code", nullable = false)
    private String modelCode;

    @Column(name = "brand_name")
    private String brandName;

    @Column(name = "launch_date")
    private LocalDate launchDate;

    private transient  String formattedDate;

    // Getter and setter
    public String getFormattedDate() {
        return getLaunchDate().toString();
    }
}
复制代码

而后是相应的JPA存储库。bash

package com.techshard.graphql.dao.repository;
import com.techshard.graphql.dao.entity.Vehicle;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface VehicleRepository extends JpaRepository<Vehicle, Integer> {
}
复制代码

GraphQL Schema

GraphQL 用有本身的独特语言来编写GraphQL Schema,称为Schema Definition Language(SDL)。schema 的定义,是由端点上全部可用的 API 功能组成的。服务器

GraphQL架构的典型示例以下所示:

type Vehicle {
	id: ID!,
	type: String,
	modelCode: String,
	brandName: String,
	launchDate: String
}

type Query {
	vehicles(count: Int):[Vehicle]
	vehicle(id: ID):Vehicle
}

type Mutation {
	createVehicle(type: String!, modelCode: String!, brandName: String, launchDate: String):Vehicle
}
复制代码

接下来,在 src/main/resources 下建立一个文件夹,名为 graphql,并在该文件夹下建立vehicleql.graphqls文件。复制上面的内容并将其粘贴到vehicleql.graphqls文件中。须要注意的是,文件名称是可自定义的。以.graphqls做为文件扩展名便可。

在上面的 schema 中,每一个对象都是用类型定义的。 GraphQL 中的类型系统是最基本的组件,它表示能够从服务获取的对象以及该对象所包含的字段。

在咱们的 schema 中,咱们有一个名为 Vehicle 的对象,做为域对象。 Query 类型表示可经过 GraphQL 服务器获取数据的查询。query 是交互式的,可修改,修改后便可看到新的结果。query 和结果的结构是同样的。这一点在 GraphQL 中很重要,由于所见即所得。

在稍后的文章中,咱们能够看到一些真正运行的例子。

Mutation 类型用来表示那些用于对数据执行写入操做的 query。

Root Query

Query 或 Mutation对象是基本 GraphQL 对象,它们没有任何关联的数据类。在这种状况下,解析器类将实现 GraphQLQueryResolver 或 GraphQLMutationResolver。These resolvers will be searched for methods that map to fields in their respective root types.(这段不是很懂,因此先贴原文)

接下来,让咱们为Vehicle定义根解析器。

package com.techshard.graphql.query;
import com.coxautodev.graphql.tools.GraphQLQueryResolver;
import com.techshard.graphql.dao.entity.Vehicle;
import com.techshard.graphql.service.VehicleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional;
@Component
public class VehicleQuery implements GraphQLQueryResolver {
    @Autowired
    private VehicleService vehicleService;
    public List<Vehicle> getVehicles(final int count) {
        return this.vehicleService.getAllVehicles(count);
    }
    public Optional<Vehicle> getVehicle(final int id) {
        return this.vehicleService.getVehicle(id);
    }
}
复制代码

在这个类中,咱们有方法来获取单个Vehicle对象和Vehicle对象列表。请注意,咱们在上面的模式中定义了这些方法。

如今,让咱们定义一个Mutation解析器。

package com.techshard.graphql.mutation;
import com.coxautodev.graphql.tools.GraphQLMutationResolver;
import com.techshard.graphql.dao.entity.Vehicle;
import com.techshard.graphql.service.VehicleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
@Component
public class VehicleMutation implements GraphQLMutationResolver {
    @Autowired
    private VehicleService vehicleService;
    public Vehicle createVehicle(final String type, final String modelCode, final String brandName, final String launchDate) {
        return this.vehicleService.createVehicle(type, modelCode, brandName, launchDate);
    }
}
复制代码

在这个类中,咱们只有一个方法来建立一个Vehicle对象,这对应于咱们的模式定义中的Mutation类型。

咱们如今将定义一个能够进行实际交互的服务。

package com.techshard.graphql.service;
import com.techshard.graphql.dao.entity.Vehicle;
import com.techshard.graphql.dao.repository.VehicleRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
public class VehicleService {
    private final VehicleRepository vehicleRepository ;
    public VehicleService(final VehicleRepository vehicleRepository) {
        this.vehicleRepository = vehicleRepository ;
    }
    @Transactional
    public Vehicle createVehicle(final String type,final String modelCode, final String brandName, final String launchDate) {
        final Vehicle vehicle = new Vehicle();
        vehicle.setType(type);
        vehicle.setModelCode(modelCode);
        vehicle.setBrandName(brandName);
        vehicle.setLaunchDate(LocalDate.parse(launchDate));
        return this.vehicleRepository.save(vehicle);
    }
    @Transactional(readOnly = true)
    public List<Vehicle> getAllVehicles(final int count) {
        return this.vehicleRepository.findAll().stream().limit(count).collect(Collectors.toList());
    }
    @Transactional(readOnly = true)
    public Optional<Vehicle> getVehicle(final int id) {
        return this.vehicleRepository.findById(id);
    }
}
复制代码

测试应用

如今,咱们能够来测试一下这个应用了。运行Spring Boot 应用程序。在浏览器中打开 http//localhost8080/graphiql 连接。咱们将看到一个友好的图形见面,以下图所示。

在用户界面的右侧,咱们还能够看到文档。

如今,咱们能够尝试运行如下查询。

mutation {
  createVehicle(type: "car", modelCode: "XYZ0192", brandName: "XYZ", launchDate: "2016-08-16") 
  {
    id
  }
}
复制代码

这将在Vehicle表中建立一行数据。结果为:

{
  "data": {
    "createVehicle": {
      "id": "1"
    }
  }
}
复制代码

如今让咱们运行查询来获取数据。

query {
  vehicles(count: 1) 
  {
    id, 
    type, 
    modelCode
	}
}
复制代码

而后咱们将获得结果

{
  "data": {
    "vehicles": [
      {
        "id": "1",
        "type": "bus",
        "modelCode": "XYZ123"
      }
    ]
  }
}
复制代码

请注意,咱们仅请求有限数量的字段。咱们能够经过添加或删除字段来更改查询,并查看新结果。

结论

在本文中,咱们研究了GraphQL的基本概念。查看详细文档

能够在GitHub上找到本教程的完整源代码。

相关文章
相关标签/搜索