Статьи

Пример GraphQL Java для начинающих [Spring Boot]

Такие цыпочки, как GraphQL Java Примеры с Spring Boot тоже!

GraphQL — это язык запросов для API, который позволяет клиентам запрашивать ограниченные данные, в которых они нуждаются, что позволяет клиентам собирать данные в ограниченном количестве запросов. GraphQL — это строго типизированный протокол, и все операции с данными проверяются по схеме GraphQL.

В этой статье мы рассмотрим пример GraphQL Java и создадим простой сервер GraphQL с Spring Boot.


Вам также может понравиться:
Выход за пределы REST с GraphQL

Добавление зависимостей Maven

Создайте пример приложения Spring Boot и добавьте следующие зависимости.

  1. graphql-spring-boot-starter используется для включения сервлета GraphQL и становится доступным по пути / graphql. Инициализирует  GraphQLSchemaбин.
  2. graphql-java позволяет нам писать схемы на языке схем GraphQL, который прост для понимания.
  3. graphiql-spring-boot-starter предоставляет пользовательский интерфейс, с помощью которого мы можем тестировать наши запросы 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, чтобы избежать написания шаблонов, таких как геттеры, сеттеры и так далее.

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.

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

GraphQL поставляется с собственным языком для написания схем GraphQL, называемым языком определения схем (SDL). Определение схемы состоит из всех функций 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
}

Создайте  папку graphql  в src / main / resources и создайте в  ней файл vehicleql.graphqls  . Скопируйте вышеуказанное содержимое и вставьте его в файл vehicleql.graphqls . Обратите внимание, что именем файла может быть любое имя по вашему выбору. Просто сохраните расширение файла как .graphqls.

В приведенной выше схеме каждый объект определен с типом. Система типов в GraphQL является самым базовым компонентом, и она представляет собой объект, который можно извлечь из службы и полей, которые содержит объект.

В нашей схеме у нас есть объект Vehicle,  который является нашим доменным объектом. Запрос типа  представляет собой запрос , который может быть сделан на сервер GraphQL для извлечения данных. Этот запрос является интерактивным, их можно изменить, и можно увидеть новые результаты. Структура запроса и результат одинаковы. Это важно в мире GraphQL, потому что мы всегда получаем ожидаемый результат.

Мы увидим рабочий пример в этой статье позже.

Мутация типа  представляет запросы, которые используются для выполнения операции записи на данных.

Root Query

Объекты Query или Mutation являются корневыми объектами GraphQL. У них нет связанных классов данных. В таких случаях классы распознавателя будут реализовывать GraphQLQueryResolver или GraphQLMutationResolver . Эти распознаватели будут искать методы, которые сопоставляются с полями в их соответствующих корневых типах.

Давайте определим корневые преобразователи для 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 . Обратите внимание, что мы определили эти методы в нашей схеме выше.

Теперь давайте определим преобразователь мутаций.

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: // localhost: 8080 / graphiql  — в браузере. Мы увидим хороший пользовательский интерфейс, как показано ниже.

Пользовательский интерфейс GraphQL

В правой части пользовательского интерфейса мы также можем изучить документацию.

Проводник документации

Теперь запустите следующий запрос.

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

Это создаст строку в таблице транспортных средств . Результат должен быть:

{
  "data": {
    "createVehicle": {
      "id": "1"
    }
  }
}

Давайте теперь запустим запрос, чтобы получить данные.

query {
  vehicles(count: 1) 
  {
    id, 
    type, 
    modelCode
}
}

Выход будет:

{
  "data": {
    "vehicles": [
      {
        "id": "1",
        "type": "bus",
        "modelCode": "XYZ123"
      }
    ]
  }
}

Обратите внимание, что мы запрашиваем только ограниченное количество полей, мы можем изменить наш запрос, добавив или удалив поля и увидев новые результаты.

Заключение

В этой статье мы рассмотрели базовый пример GraphQL Java с Spring Boot. Ознакомьтесь с подробной документацией здесь .

Полный исходный код этого руководства можно найти на GitHub .

Дальнейшее чтение

Введение в GraphQL

GraphQL: основные характеристики, архитектура, плюсы и минусы


Если вам понравилась эта статья и вы хотите больше узнать о GraphQL, ознакомьтесь с этой коллекцией руководств и статей  по всем вопросам, связанным с GraphQL.