Show List

Building a GraphQL Server

Here are steps for building GraphQL server using Java and Spring Boot:

Start with Spring Boot project with Spring for GraphQL and Spring Web dependencies

The GraphQL server we are building will be storing the information of books and their authors. We are going to use H2 database and JPA for DB operations. 

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>3.1.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.boot</groupId>
<artifactId>graphql</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>graphql</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graphql</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

</dependencies>

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

</project>
Create Schema: schema.graphql
type Query {
bookById(id: ID): Book
}

type Book {
id: ID
name: String
author: Author
}

type Author {
id: ID
firstName: String
lastName: String
}

type Mutation {
addAuthor(firstName: String!, lastName: String!): Author!
addBook(name: String!, authorId: ID!): Book!
updateBook(id: ID!, name: String, authorId: ID): Book!
deleteBook(id: ID!): Boolean
}

Add Book and Author entity classes:
package com.boot.graphql.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

import java.util.Arrays;
import java.util.List;

@Entity
public class Book {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private int authorId;

public Book(){

}

public Book(int id, String name, int authorId) {
this.id = id;
this.name = name;
this.authorId = authorId;
}

public Book(String name, int authorId) {
this.name = name;
this.authorId = authorId;
}

public int getId() {
return id;
}

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

public String getName() {
return name;
}

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

public int getAuthorId() {
return authorId;
}

public void setAuthorId(int authorId) {
this.authorId = authorId;
}
}
package com.boot.graphql.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Author {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String firstName;
private String lastName;

public Author(){

}
public Author(int id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}

public Author( String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

public int getId() {
return id;
}

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

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Add Repositories:
package com.boot.graphql.repo;

import com.boot.graphql.model.Book;
import org.springframework.data.repository.CrudRepository;

@Repository
public interface BookRepo extends CrudRepository <Book, Integer> {}
package com.boot.graphql.repo;

import com.boot.graphql.model.Author;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface AuthorRepo extends CrudRepository<Author, Integer> {}
Add controller:
package com.boot.graphql.controller;

import com.boot.graphql.model.Author;
import com.boot.graphql.model.Book;
import com.boot.graphql.repo.AuthorRepo;
import com.boot.graphql.repo.BookRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.graphql.data.method.annotation.*;
import org.springframework.stereotype.Controller;

import java.util.Optional;

@Controller
public class BookController {

@Autowired
AuthorRepo authorRepo;
@Autowired
BookRepo bookRepo;

@QueryMapping
public Optional<Book> bookById(@Argument int id) {
return bookRepo.findById(id);
}

@SchemaMapping
public Optional<Author> author(Book book) {
return authorRepo.findById(book.getAuthorId());
}

@MutationMapping
public Author addAuthor(@Argument String firstName, @Argument String lastName){
return authorRepo.save(new Author(firstName, lastName));
}

@MutationMapping
public Book addBook(@Argument String name, @Argument int authorId){
return bookRepo.save(new Book(name, authorId));
}

@MutationMapping
public Book updateBook(@Argument int id, @Argument String name, @Argument int authorId){

Optional<Book> optBook = bookRepo.findById(id);
Book book1 = optBook.get();
book1.setName(name);
book1.setAuthorId(authorId);
return bookRepo.save(book1);
}
}
application.properties:
spring.graphql.graphiql.enabled=true
spring.jpa.show-sql=true
In the local test, we are going to call the Spring Boot application from React front end application. Adding the cors policy to allow the connection.

package com.boot.graphql.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*"); // Allow requests from any origin (you can specify specific origins)
corsConfiguration.addAllowedMethod("*"); // Allow all HTTP methods (e.g., GET, POST, PUT, DELETE)
corsConfiguration.addAllowedHeader("*"); // Allow all headers

UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);

return new CorsFilter(source);
}
}
Using ApplicationRunner to load the initial data in the H2 database:
package com.boot.graphql;

import com.boot.graphql.model.Author;
import com.boot.graphql.model.Book;
import com.boot.graphql.repo.AuthorRepo;
import com.boot.graphql.repo.BookRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class GraphqlApplication implements ApplicationRunner {

@Autowired
AuthorRepo authorRepo;

@Autowired
BookRepo bookRepo;

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

@Override
public void run(ApplicationArguments args) throws Exception {
authorRepo.save(new Author(1,"FN1","LN1" ));
authorRepo.save(new Author(2,"FN2","LN2" ));
bookRepo.save(new Book(1,"BookName1", 1));
bookRepo.save(new Book(2,"BookName2", 2));
}
}

Running the application

When the application is run, the GraphQL server can be called from the integrated UI available at /graphiql?path=/graphql end point or other client (such as in Postman)


Using Postman:

Access GraphQL client
Build the query and select the fields for response:



Source Code:

https://github.com/it-code-lab/graphqlh3/tree/master

    Leave a Comment


  • captcha text