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;
@Componentpublic 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;
@Componentpublic 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;
@SpringBootApplicationpublic 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
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