GraphQL
can return a list of results, but it's always advised all APIs
returning a list of data should implement Pagination
, The data set will grow and will take a lot longer to process by the API server slowing down the API
response time.
Spring Boot GraphQL
can leverage the Spring Data JPA
provided by Spring Ecosystem
and implement the Pagination
, Learn more about Spring Data JPA
.
package org.wesome.graphql.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import org.wesome.graphql.entity.Apple;
import org.wesome.graphql.service.AppleService;
@Controller
public class AppleGraphQLController {
@Autowired
private AppleService appleService;
@QueryMapping("findAllApple")
Iterable<Apple> findAllApple(@Argument int page, @Argument int size) {
PageRequest pageRequest = PageRequest.of(page, size);
Page<Apple> allApple = appleService.findAllApple(pageRequest);
System.out.println("allApple = " + allApple);
return allApple;
}
}
package org.wesome.graphql.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.wesome.graphql.entity.Apple;
import org.wesome.graphql.service.AppleService;
@RestController
public class AppleRestController {
@Autowired
private AppleService appleService;
@GetMapping(path = "/findAllApple", produces = "application/json")
Page<Apple> findAllApple(@RequestParam int page, @RequestParam int size) {
PageRequest pageRequest = PageRequest.of(page, size);
return appleService.findAllApple(pageRequest);
}
}
package org.wesome.graphql.entity;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
public class Apple {
@Id
@GeneratedValue
private int appleId;
private String appleName;
private String appleTaste;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "apple_id", referencedColumnName = "apple_id")
private Vendor vendor;
}
package org.wesome.graphql.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
public class Vendor {
@Id
@GeneratedValue
private int vendorId;
private String vendorName;
}
package org.wesome.graphql.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.wesome.graphql.entity.Apple;
@Repository
public interface AppleRepository extends JpaRepository<Apple, Integer> {
}
package org.wesome.graphql.service;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.wesome.graphql.entity.Apple;
public interface AppleService {
Page<Apple> findAllApple(PageRequest pageRequest);
}
package org.wesome.graphql.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.wesome.graphql.entity.Apple;
import org.wesome.graphql.repository.AppleRepository;
@Service
public class AppleServiceImpl implements AppleService {
@Autowired
private AppleRepository appleRepository;
@Override
public Page<Apple> findAllApple(PageRequest pageRequest) {
return appleRepository.findAll(pageRequest);
}
}
package org.wesome.graphql;
import com.github.javafaker.Faker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.wesome.graphql.entity.Apple;
import org.wesome.graphql.entity.AppleTaste;
import org.wesome.graphql.entity.Vendor;
import org.wesome.graphql.repository.AppleRepository;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@SpringBootApplication
public class GraphqlProjectApplication implements CommandLineRunner {
@Autowired
private AppleRepository appleRepository;
public static void main(String[] args) {
SpringApplication.run(GraphqlProjectApplication.class, args);
}
@Override
public void run(String... args) {
Faker faker = new Faker();
List<Apple> apples = IntStream.rangeClosed(1, 10).mapToObj(value -> new Apple(value, faker.food().fruit(), AppleTaste.values()[faker.random().nextInt(0, 3)].name(), new Vendor(value, faker.name().fullName()))).collect(Collectors.toList());
appleRepository.saveAll(apples);
}
}
# Apple Object
type Apple{
# appleId
appleId:ID!
# apple Name
appleName:String
# apple AppleTaste
appleTaste:String
vendor:Vendor
}
# Apple Vendor
type Vendor{
# vendorId
vendorId:ID!
# vendor Name
vendorName:String
}
# Apple Query
type Query{
# query to get all apples
findAllApple(page:Int!, size:Int!):[Apple]
}
\src\main\resources\application.properties
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://localhost:3306/appleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.datasource.username=root
spring.datasource.password=rootroot
spring.graphql.graphiql.enabled=true
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.5</version>
<relativePath/>
</parent>
<groupId>org.wesome</groupId>
<artifactId>spring-boot-graphql</artifactId>
<version>0.0.1-snapshot</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graphql</artifactId>
</dependency>
<dependency>
<groupId>com.github.javafaker</groupId>
<artifactId>javafaker</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.graphql</groupId>
<artifactId>spring-graphql-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<name>spring boot graphql</name>
<description>implementing graphql in spring boot</description>
<properties>
<java.version>17</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Rest API
curl --location 'http://localhost:8080/findAllApple?page=0&size=10'
GraphiQL
GraphQL
provides an inbuild UserInterface GraphiQL
, which can be accessed via http://localhost:8080/graphiql
or access GraphQL via Postman,
in the query section add the below query
query FindAllApple {
findAllApple(page: 0, size: 10) {
appleId
appleName
appleTaste
vendor {
vendorId
vendorName
}
}
}