Build a basic CRUD backend application in Java Spring Boot with GraphQL & MySQL.
Setup an empty project using Spring Initializr.
- 
Update the field "Artifact" as java-graphql-sample.
- 
Update the field "Package name" as com.example.jgs.
- 
Press ADD DEPENDENCIES...button to add the following dependency:Spring Web.
Please use Maven Project in Java 8, packaging as JAR for this tutorial.
Press the GENERATE button to download an empty project template.
Extract the zip folder to start editing.
Create the following file src/main/java/com/example/jgs/controller/HealthController.java.
package com.example.jgs.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HealthController {
    @GetMapping
    public String check() {
        return "OK";
    }
}Start server with below command:
mvnw spring-boot:runGoto http://localhost:8080 You should see the OK message.
Update the pom.xml as follow.
    <properties>
        ...
        <graphql-java-kickstart.version>7.1.0</graphql-java-kickstart.version>
        <graphql-spqr.version>0.10.1</graphql-spqr.version>
    </properties>
    <dependencies>
        ...
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.graphql-java-kickstart</groupId>
            <artifactId>graphql-spring-boot-starter</artifactId>
            <version>${graphql-java-kickstart.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>com.graphql-java</groupId>
                    <artifactId>graphql-java</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.graphql-java-kickstart</groupId>
            <artifactId>playground-spring-boot-starter</artifactId>
            <version>${graphql-java-kickstart.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.leangen.graphql</groupId>
            <artifactId>spqr</artifactId>
            <version>${graphql-spqr.version}</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
    </dependencies>
...Create the following file src/main/java/com/example/jgs/input/CreateUser.java.
package com.example.jgs.input;
import io.leangen.graphql.annotations.GraphQLNonNull;
import lombok.Data;
@Data
public class CreateUser {
    @GraphQLNonNull
    private String name;
    private String nickName;
}Create the following file src/main/java/com/example/jgs/model/User.java.
package com.example.jgs.model;
import com.example.jgs.input.CreateUser;
import io.leangen.graphql.annotations.GraphQLNonNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Type;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import java.util.UUID;
@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {
    @Id
    @GeneratedValue
    @Type(type = "uuid-char")
    @GraphQLNonNull
    @Column(length = 36)
    private UUID id;
    @GraphQLNonNull
    private String name;
    private String nickName;
    public static User from(CreateUser createUser) {
        return User.builder().name(createUser.getName())
                .nickName(createUser.getNickName())
                .build();
    }
}Create the following file src/main/java/com/example/jgs/repository/UserRepository.java.
package com.example.jgs.repository;
import com.example.jgs.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.UUID;
@Repository
public interface UserRepository extends JpaRepository<User, UUID> {
}Create the following file src/main/java/com/example/jgs/service/UserService.java.
package com.example.jgs.service;
import com.example.jgs.input.CreateUser;
import com.example.jgs.model.User;
import com.example.jgs.repository.UserRepository;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.UUID;
@Service
@AllArgsConstructor
public class UserService {
    private final UserRepository userRepository;
    public List<User> find() {
        return this.userRepository.findAll();
    }
    public User findOneById(UUID id) {
        return this.userRepository.findById(id).orElse(null);
    }
    public User create(CreateUser createUser) {
        return this.userRepository.save(User.from(createUser));
    }
    public boolean delete(UUID id) {
        if (this.userRepository.existsById(id)) {
            this.userRepository.deleteById(id);
            return true;
        }
        return false;
    }
}Create the following file src/main/java/com/example/jgs/resolver/UserResolver.java.
package com.example.jgs.resolver;
import com.example.jgs.input.CreateUser;
import com.example.jgs.model.User;
import com.example.jgs.service.UserService;
import io.leangen.graphql.annotations.GraphQLArgument;
import io.leangen.graphql.annotations.GraphQLMutation;
import io.leangen.graphql.annotations.GraphQLNonNull;
import io.leangen.graphql.annotations.GraphQLQuery;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Controller;
import java.util.List;
import java.util.UUID;
@Controller
@AllArgsConstructor
public class UserResolver {
    private final UserService userService;
    @GraphQLQuery
    @GraphQLNonNull
    public List<@GraphQLNonNull User> users() {
        return this.userService.find();
    }
    @GraphQLQuery
    public User user(
            @GraphQLArgument(name = "id") UUID id) {
        return this.userService.findOneById(id);
    }
    @GraphQLMutation
    @GraphQLNonNull
    public User createUser(
            @GraphQLArgument(name = "input") @GraphQLNonNull CreateUser createUser) {
        return this.userService.create(createUser);
    }
    @GraphQLMutation
    public UUID deleteUser(
            @GraphQLArgument(name = "id") UUID id) {
        return this.userService.delete(id) ? id : null;
    }
}Create the following file src/main/java/com/example/jgs/config/GraphqlConfig.java.
package com.example.jgs.config;
import com.example.jgs.resolver.UserResolver;
import graphql.schema.GraphQLSchema;
import io.leangen.graphql.GraphQLSchemaGenerator;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@AllArgsConstructor
public class GraphqlConfig {
    private final UserResolver userResolver;
    @Bean
    GraphQLSchema schema() {
        return new GraphQLSchemaGenerator()
                .withBasePackages("com.example.jgs")
                .withOperationsFromSingleton(this.userResolver)
                .generate();
    }
}Rename src/main/resources/application.properties to src/main/resources/application.yml. Then Add the following:
spring:
  datasource:
    url: jdbc:h2:mem:testdbStart the server.
mvnw spring-boot:runGoto the GraphQL Playground - http://localhost:8080/playground.
- 
Create a new user mutation { createUser(input: { name: "Tommy" }) { id } } Output : { "data": { "createUser": { "id": "8ec8105e-1ffc-4fe3-81fb-882b3dd33f82" } } }
- 
Query the users query { users { id name } } Output : { "data": { "users": [ { "id": "8ec8105e-1ffc-4fe3-81fb-882b3dd33f82", "name": "Tommy" } ] } }
Update the following file pom.xml
...
    <properties>
        ...
        <mybatis-migrations-autoconfigure.version>0.0.2</mybatis-migrations-autoconfigure.version>
    </properties>
    <dependencies>
        ...
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>de.bessonov</groupId>
            <artifactId>mybatis-migrations-spring-boot-autoconfigure</artifactId>
            <version>${mybatis-migrations-autoconfigure.version}</version>
        </dependency>
    </dependencies>
...Update the following file src/main/resources/application.yml.
spring:
  datasource:
    url: jdbc:${DATABASE_URL:mysql://usr:User12345@localhost:3306/development}
logging:
  level:
    org.hibernate.SQL: DEBUG
    org.hibernate.type.descriptor.sql.BasicBinder: TRACE
server:
  port: 4000Create a folder scripts under src/main/resources
Create the following file src/main/resources/scripts/<yyyymmddHHmmss>_create_changelog.sql 
 (e.g. 20200728095409_create_changelog.sql )
-- // Create Changelog
-- Default DDL for changelog table that will keep
-- a record of the migrations that have been run.
-- You can modify this to suit your database before
-- running your first migration.
-- Be sure that ID and DESCRIPTION fields exist in
-- BigInteger and String compatible fields respectively.
CREATE TABLE ${changelog} (
  ID NUMERIC(20,0) NOT NULL,
  APPLIED_AT VARCHAR(25) NOT NULL,
  DESCRIPTION VARCHAR(255) NOT NULL,
  PRIMARY KEY(ID)
);
-- //@UNDO
DROP TABLE ${changelog};Create the following file src/main/resources/scripts/<yyyymmddHHmmss>_first_migration.sql 
 (e.g. 20200728095410_first_migration.sql )
-- // First migration.
-- Migration SQL that makes the change goes here.
CREATE TABLE user (
  id VARCHAR(36) NOT NULL,
  name VARCHAR(255) NOT NULL,
  nick_name VARCHAR(255) NULL,
  PRIMARY KEY(id)
);
-- //@UNDO
-- SQL to undo the change goes here.
DROP TABLE user;Please note the following points when creating new script:
1. The naming convention is<yyyymmddHHmmss>_<description>.sql
2. Put undo SQL under-- //@UNDOsection.
Create the following file src/test/resources/application.yml.
spring:
  datasource:
    url: jdbc:h2:mem:testdb
graphql:
  servlet:
    websocket:
      enabled: falseUpdate the dependency of com.h2database in pom.xml as follow:
...
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>test</scope>
		</dependency>
...Package the jar by command:
mvnw packageStart a MySQL docker instance.
docker run -d -e "MYSQL_ROOT_PASSWORD=Admin12345" -e "MYSQL_USER=usr" -e "MYSQL_PASSWORD=User12345" -e "MYSQL_DATABASE=development" -p 3306:3306 --name some-mysql bitnami/mysql:5.7.27Run the below command and look at migration status before executing the scripts:
>java -jar target/java-graphql-sample-0.0.1-SNAPSHOT.jar migrations status
ID             Applied At          Description
================================================================================
20200812020020    ...pending...    create changelog
20200812020021    ...pending...    first migrationExecution of the migration script:
java -jar target/java-graphql-sample-0.0.1-SNAPSHOT.jar migrations upRun the below command again to check the applied time:
>java -jar target/java-graphql-sample-0.0.1-SNAPSHOT.jar migrations status
ID             Applied At          Description
================================================================================
20200812020020 2020-08-12 11:43:46 create changelog
20200812020021 2020-08-12 11:43:46 first migrationStart the server.
mvnw spring-boot:runGoto the GraphQL Playground - http://localhost:4000/playground.
- 
Create some users mutation { a: createUser(input: { name: "John" }) { id } b: createUser(input: { name: "Mary" }) { id } } Output: { "data": { "a": { "id": "94ae9dd3-c739-4c04-8bfb-6a7c94552cd6" }, "b": { "id": "2aa8e496-0c9d-41b4-a0c8-467beaf14247" } } }
- 
Query the users query { users { id name } } Output : { "data": { "users": [ { "id": "2aa8e496-0c9d-41b4-a0c8-467beaf14247", "name": "Mary" }, { "id": "94ae9dd3-c739-4c04-8bfb-6a7c94552cd6", "name": "John" } ] } }
- 
Delete one of the user by the id mutation { deleteUser(id: "94ae9dd3-c739-4c04-8bfb-6a7c94552cd6") } Output : { "data": { "deleteUser": "94ae9dd3-c739-4c04-8bfb-6a7c94552cd6" } }
- 
Test the MySQL database Run the mysql command using the same docker instance. docker exec -it some-mysql mysql -uroot -p"Admin12345" Select the data from user table. mysql> use development; mysql> select * from user; +--------------------------------------+------+----------+ | id | name | nickName | +--------------------------------------+------+----------+ | 2aa8e496-0c9d-41b4-a0c8-467beaf14247 | Mary | NULL | +--------------------------------------+------+----------+