Build a CRUD API with Spring Boot and GraphQL

Hello everyone, today we will learn how to build CRUD API using Spring Boot, GraphQL, H2DB and Spring Data JPA.

GraphQL is a specification for how to talk with an API. It's typically used over HTTP where the key conception is to POST a "query" to an HTTP endpoint, instead of hitting different HTTP endpoints for different resources. GraphQL is designed for developers of web/mobile apps to be able to make API calls to fetch precisely the data they require from their backend APIs.More Info https://graphql.org/

We have two data models: Author and Book. So each book must belong to an author and an author may have multiple books under it. So Book will have a many-to-one relationship with Author. For book and author, we will perform Create, Read, Update and Delete operations using GraphQL APIs. 

You can download the complete source code from our GitHub repository.

CRUD GraphQL APIs:

Create Author:


Create Book:


Update Author:


Update Book:


Read all Books:


Read all Authors:


Read Author By Id:


Read Book By Id:


Delete Author By Id:


Delete Book By Id:


Final Project Structure:



Pom.xml

<?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
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>2.5.5</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.knf.dev.demo</groupId>
<artifactId>springboot-graphql-crud-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-graphql-crud-example</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>


Create Entity Author

package com.knf.dev.demo.entity;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "author")
public class Author implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

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

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}


Create Entity Book

package com.knf.dev.demo.entity;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "book")
public class Book implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

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

@Column(name = "price")
private Double price;

@ManyToOne
@JoinColumn(name = "author_id", nullable = false, updatable = false)
private Author author;

public Author getAuthor() {
return author;
}

public void setAuthor(Author author) {
this.author = author;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Double getPrice() {
return price;
}

public void setPrice(Double price) {
this.price = price;
}

}


Create Author Repository

package com.knf.dev.demo.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import com.knf.dev.demo.entity.Author;

public interface AuthorRepository extends JpaRepository<Author, Long> {

}



Create Book Repository

package com.knf.dev.demo.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import com.knf.dev.demo.entity.Book;

public interface BookRepository extends JpaRepository<Book, Long> {

}


Mutation Resolver

Mutations allow us to modify server-side data, and it also returns an object based on the operation performed. It can be used to insert, update, or delete data.
package com.knf.dev.demo.resolver;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.coxautodev.graphql.tools.GraphQLMutationResolver;
import com.knf.dev.demo.entity.Author;
import com.knf.dev.demo.entity.Book;
import com.knf.dev.demo.repository.AuthorRepository;
import com.knf.dev.demo.repository.BookRepository;

@Component
public class Mutation implements GraphQLMutationResolver {
@Autowired
private AuthorRepository authorRepository;

@Autowired
private BookRepository bookRepository;

public Author addAuthor(String name) {
Author author = new Author();
author.setName(name);

return authorRepository.saveAndFlush(author);
}

public Author updateAuthor(Long id, String name) {
Author author = new Author();
author.setId(id);
author.setName(name);

return authorRepository.saveAndFlush(author);
}

public Boolean deleteAuthor(Long id) {
authorRepository.deleteById(id);
return true;
}

public Book addBook(String name, Double price, Long author_id) {
Author author = authorRepository.findById(author_id).
orElseGet(null);
Book book = new Book();
book.setName(name);
book.setPrice(price);
book.setAuthor(author);
return bookRepository.saveAndFlush(book);
}

public Book updateBook(Long id, String name, Double price) {
Book book = new Book();
book.setId(id);
book.setName(name);
book.setPrice(price);
return bookRepository.saveAndFlush(book);
}

public Boolean deleteBook(Long id) {
bookRepository.deleteById(id);
return true;
}

}


Query Resolver

The Query for reading data from GraphQL APIs.
package com.knf.dev.demo.resolver;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.coxautodev.graphql.tools.GraphQLQueryResolver;
import com.knf.dev.demo.entity.Author;
import com.knf.dev.demo.entity.Book;
import com.knf.dev.demo.repository.AuthorRepository;
import com.knf.dev.demo.repository.BookRepository;

@Component
public class Query implements GraphQLQueryResolver {

@Autowired
private AuthorRepository authorRepository;

@Autowired
private BookRepository bookRepository;

public Iterable<Book> allBooks() {
return bookRepository.findAll();
}

public Book book(Long id) {
return bookRepository.findById(id).orElseGet(null);
}

public Iterable<Author> allAuthors() {
return authorRepository.findAll();
}

public Author author(Long id) {
return authorRepository.findById(id).orElseGet(null);
}
}


GraphQL Schema(schema.graphqls)

type Query {
allAuthors: [Author]
allBooks: [Book]
book(id: ID!): Book
author(id: ID!): Author
}

type Mutation {
addAuthor(name: String!): Author!
updateAuthor(id: ID!, name: String!): Author!
deleteAuthor(id: ID!): Boolean
addBook(name: String!, price: Float!, author_id: ID!): Book!
updateBook(id: ID!, name: String!,price: Float!): Book!
deleteBook(id: ID!): Boolean
}

type Author {
id: ID
name: String!
}

type Book {
id: ID
name: String!
price: Float!
author: Author!
}



Spring Boot Main Driver

package com.knf.dev.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringGraphqlCrudExampleApplication {

public static void main(String[] args) {
SpringApplication.
run(SpringGraphqlCrudExampleApplication.class, args);
}

}


Download the complete source code - click here                               

Local Setup and Run the application

Step1: Download or clone the source code from GitHub to the local machine - Click here

Step 2: mvn clean install

Step 3: Run the Spring Boot application - mvn spring-boot:run    

Popular posts from this blog

Learn Java 8 streams with an example - print odd/even numbers from Array and List

Java Stream API - How to convert List of objects to another List of objects using Java streams?

Registration and Login with Spring Boot + Spring Security + Thymeleaf

Java, Spring Boot Mini Project - Library Management System - Download

ReactJS, Spring Boot JWT Authentication Example

Top 5 Java ORM tools - 2024

Java - Blowfish Encryption and decryption Example

Spring boot video streaming example-HTML5

Google Cloud Storage + Spring Boot - File Upload, Download, and Delete