Skip to content

natton2k/GraphQL-kickstater-springboot-tutorial

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GraphQL-kickstater-springboot-tutorial

GraphQL with SpringBoot demo

Table of Contents

  1. About The Tutorial
  2. Getting Started
  3. Let's begin
  4. Contact

About The Tutorial

![Product Name Screen Shot][product-screenshot] This is a tutorial for building GraphQL server with Spring Boot using GraphQL Java Kickstart and Spring Data JPA

Built With

Getting Started

What you need

  • A text editor or IDE - We use Inteliji in this tutorial but you can choose your own preferred IDE
  • JDK 1.8 or later
  • Maven 3.2+

Prior knowledge

How to complete this tutorial

  • Start from scratch, you can follow all the steps below, building your own application.
  • If you don't have time, clone this repo and load it on your IDE and discovery it in your free time
git clone https://github.com/TienTruong98/GraphQL-kickstater-springboot-tutorial

Let's begin

Step 1: Create your Spring Boot application

spring initializer image

  • Go to Spring Initializer and create your Spring Boot app with the following configurations:
    • Project: maven project
    • Language: java
    • Spring Boot: latest stable version (at the time of this tutorial, the lastest one is 2.4.1)
    • Project metatadata:
      • Group: your own group name - usual practice is com.[yourname]
      • Artifact: your project name
      • Name: use the generated default name
      • Description: use the generated default name
      • Pakage name: use the generated default name
      • Packaging: choose JAR
      • Java: choose your current JDK version
  • Add dependencies:
    • Lombok
    • Spring Web
    • MS SQL Server Driver
    • Spring Data JPA
  • Click Generate, download the project zip file and extract it to your directory.
  • Check the pom.xml - your pom.xml file should look like this
<?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.4.1</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.tientt</groupId>
	<artifactId>graphql-tutorial</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>graphql-tutorial</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</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.microsoft.sqlserver</groupId>
			<artifactId>mssql-jdbc</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Step 2: Add additional dependencies

<dependency>  
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>  
	<version>2.11.0</version>  
</dependency>
<dependency>  
	<groupId>com.graphql-java-kickstart</groupId>  
	<artifactId>graphql-spring-boot-starter</artifactId>  
	<version>8.0.0</version>  
</dependency>  
<dependency>  
	<groupId>com.graphql-java-kickstart</groupId>  
	<artifactId>graphiql-spring-boot-starter</artifactId>  
	<version>8.0.0</version>  
	<scope>runtime</scope>  
</dependency>

Step 3: create new database

  • Here we use Microsoft SQL Server but you can you any database - that the point of JPA
/*Step 1: create database*/
create database BookManagement
use BookManagement

/*Step 2: create tables*/
create table Author(
	id bigint primary key,
	fullname nvarchar(100)
)

create table Book(
	isbn char(13) primary key,
	title nvarchar(100) not null,
	edition int,
	publishedYear int,
	authorId bigint foreign key references Author(id)
)

/*Step 3: create some data*/
insert into Author values(1, N'Paulo Coelho');
insert into Author values(2, N'Rosie Nguyễn');
insert into Author values(3, N'Robin Sharma');

insert into Book values ('2518407786529', N'The Alchemist (Nhà giả kim)', 1, 2013, 1);
insert into Book values ('6911225907262', N'Tuổi Trẻ Đáng Giá Bao Nhiêu', 2, 2018, 2);
insert into Book values ('2425402340697', N'Đời Ngắn Đừng Ngủ Dài', 2, 2014, 3);

Step 4: add Spring Boot configurations in application.properties

#JPA configuration  
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver  
spring.datasource.url=jdbc:sqlserver://localhost:1433;databaseName=BookManagement  
spring.datasource.username=sa  
spring.datasource.password=123  
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl  
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl  
#Server configuration  
server.servlet.context-path=/demo-graphQL  
#GraphQL configuration  
graphql.servlet.enabled=true  
graphql.servlet.mapping=/graphql  
graphql.tools.schema-location-pattern=**/*.graphql

Step 5: create Entity classes and their Repositories

  • Class Author
import com.fasterxml.jackson.annotation.JsonManagedReference;  
import lombok.Data;  
import javax.persistence.*;  
import java.io.Serializable;  
import java.util.List;  
  
@Entity  
@Data  
public class Author implements Serializable{  
	@Id  
	private Long id;  
	private String fullname;  
	@JsonManagedReference  
	@OneToMany(mappedBy = "author", fetch = FetchType.EAGER, cascade = CascadeType.ALL)  
	private List<Book> books;  
}
  • Class Book
import com.fasterxml.jackson.annotation.JsonBackReference;  
import lombok.Data;  
import javax.persistence.*;  
import java.io.Serializable;  
  
@Entity  
@Data  
public class Book implements Serializable {  
	@Id  
	private String isbn;  
	private String title;  
	private Integer edition;  
	private Integer publishedYear;  
	@JsonBackReference  
	@ManyToOne(fetch = FetchType.EAGER)  
	@JoinColumn(name = "authorId", insertable = false, updatable = false)  
	private Author author;  
}
  • Interface AuthorRepository
import com.tientt.graphqldemo.pojo.pojo.entities.Author;  
import org.springframework.data.jpa.repository.JpaRepository;  
import org.springframework.stereotype.Repository;  
  
@Repository  
public interface AuthorRepository extends JpaRepository<Author, Long> {  
  
}
  • Interface BookRepository
import com.tientt.graphqldemo.pojo.pojo.entities.Book;  
import org.springframework.data.jpa.repository.JpaRepository;  
import org.springframework.stereotype.Repository;  
  
import java.util.List;  
  
@Repository  
public interface BookRepository extends JpaRepository<Book, String> {  
	List<Book> findAllByAuthor_Id(Long authorID);  
}

Step 6: create schema.graphql for basic query operation

  • [Todo] Add definition for schema.graphql
type Author{
    id: Float!
    fullname: String
    books:[Book]
}

type Book{
    isbn: String!
    title: String
    edition: Int
    publishedYear: Int
    author: Author
}

type Query{
    getAllAuthors:[Author]
    getAuthor(authorID: Float):Author
    getAllBooks:[Book]
    getBooksByAuthor(AuthorID: Float!):[Book]
}

Step 7: create resolver classes for schema type

  • Class QueryResolver
import com.tientt.graphqldemo.pojo.pojo.entities.Author;  
import com.tientt.graphqldemo.pojo.pojo.entities.Book;  
import com.tientt.graphqldemo.repositories.AuthorRepository;  
import com.tientt.graphqldemo.repositories.BookRepository;  
import graphql.kickstart.tools.GraphQLQueryResolver;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Component;  
import java.util.List;  	
  
@Component  
public class QueryResolver implements GraphQLQueryResolver {  
	@Autowired  
	AuthorRepository authorRepository;  
	@Autowired  
	BookRepository bookRepository; 
	 
	public List<Author> getAllAuthors(){  
	        return authorRepository.findAll();  
	}  
	public Author getAuthor(Long authorID){  
	        return authorRepository.findById(authorID).get();  
	}
	public List<Book> getAllBooks(){  
		return bookRepository.findAll();  
	}  
	public List<Book> getBooksByAuthor(Long authorID){  
	        return bookRepository.findAllByAuthor_Id(authorID);  
	}  
        public Book getBookByIsbn(String isbn){  
	        return bookRepository.findById(isbn).get();  
        }  
}
  • Class BookResolver
import com.tientt.graphqldemo.pojo.pojo.entities.Author;  
import com.tientt.graphqldemo.pojo.pojo.entities.Book;  
import graphql.kickstart.tools.GraphQLResolver;  
  
public class BookResolver implements GraphQLResolver<Book> {  
	Author author(Book book){  
	        return book.getAuthor();  
	}  
}
  • Class AuthorResolver
import com.tientt.graphqldemo.pojo.pojo.entities.Author;  
import com.tientt.graphqldemo.pojo.pojo.entities.Book;  
import com.tientt.graphqldemo.repositories.BookRepository;  
import graphql.kickstart.tools.GraphQLResolver;  
import org.springframework.beans.factory.annotation.Autowired;  
import java.util.List;  
  
public class AuthorResolver implements GraphQLResolver<Author> {  
	@Autowired  
	BookRepository bookRepository;  
	
	public List<Book> books(Author author){  
		return bookRepository.findAllByAuthor_Id(author.getId());  
	}  
}

Step 8: add mutation type to schema.graphql

input AuthorInput{
    id: Float!
    fullname: String
}

type Mutation{
    updateAuthor(author: AuthorInput!):Author
    deleteAuthor(authorId: Float!):Boolean
}

Step 9: add Data class for AuthorInput and Mutation Resolver

  • Class AuthorInput
import lombok.Data;  
import lombok.Getter;  
import lombok.NoArgsConstructor;  
import lombok.Setter;  
  
@Data  
public class AuthorInput {  
	private Long id;  
	private String fullname;  
}
  • Class MutatuonResolver
import com.tientt.graphqldemo.pojo.AuthorInput;  
import com.tientt.graphqldemo.pojo.pojo.entities.Author;  
import com.tientt.graphqldemo.repositories.AuthorRepository;  
import graphql.kickstart.tools.GraphQLMutationResolver;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Component;  
  
import javax.transaction.Transactional;  

@Component  
@Transactional  
public class MutationResolver implements GraphQLMutationResolver {  
	@Autowired  
	AuthorRepository authorRepository;  
	
	public Author updateAuthor(AuthorInput input){  
	        Author author = new Author();  
		author.setId(input.getId());  
		author.setFullname(input.getFullname());  
		return authorRepository.saveAndFlush(author);  
	}  
  
	public boolean deleteAuthor(Long authorID){  
	        authorRepository.deleteById(authorID);  
		return true;  
	}  
}

Step 10: Test our GraphQL

  • Run our Spring Boot app - check for the context path
2020-12-16 09:11:08.261  INFO 2892 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer: 
Tomcat started on port(s): 8080 (http) 
with context path '/demo-graphQL'
  • Open Graphiql to test our GraphQL app
http://localhost:8080/demo-graphQL/graphiql
  • Test these query: [TODO add result image]
query{
  getAllBooks{
    isbn
    title
    author{
      fullname
    }
  }
  getAllAuthors{
    id
    fullname
    books{
      title
    }
  }
}
mutation{
  updateAuthor(author:{
    	id:1
    	fullname: "Paulo Coelho1"}
	){
    id
    fullname
  }
}
mutation{
  deleteAuthor(authorId:1)   
}

Contact

Releases

No releases published

Packages

No packages published

Languages