/springboot-graphql-databases

The goal of this project is to explore GraphQL. For it, we will implement two microservices: author-book-api and book-review-api.

Primary LanguageJava

springboot-graphql-databases

The goal of this project is to explore GraphQL. For it, we will implement two Spring Boot Web Java applications: author-book-api and book-review-api.

Note: In kubernetes-minikube-environment repository, it's shown how to deploy this project in Kubernetes (Minikube)

Project Diagram

project-diagram

Applications

  • author-book-api

    Spring Boot Web Java application that handles authors and books. It exposes a GraphQL endpoint and traditional REST API endpoints. author-book-api uses MySQL as storage and calls book-review-api to get the reviews of the books. It uses Feign to easily create a client for book-review-api and Resilience4j (fault tolerance library) to handle fallback when book-review-api is down. The book ISBN is what connects books stored in author-book-api with the ones stored in book-review-api.

  • book-review-api

    Spring Boot Web Java application that handles books and their reviews. It only exposes a GraphQL API and uses MongoDB as storage.

Frontend applications

In the repository react-graphql-databases, I have implemented two ReactJS applications author-book-ui and book-review-ui that are frontend applications for author-book-api and book-review-api, respectively.

If you want to see the complete communication frontend-backend using GraphQL, clone the react-graphql-databases and follow the README instructions.

Prerequisites

Start Environment

  • Open a terminal and inside springboot-graphql-databases root folder run

    docker-compose up -d
    
  • Wait for containers to be with status running (healthy). To check it, run

    docker-compose ps
    

Run applications with Maven

Inside springboot-graphql-databases, run the following Maven commands in different terminals

  • author-book-api

    ./mvnw clean spring-boot:run --projects author-book-api \
    -Dspring-boot.run.jvmArguments="-Dspring.datasource.username=authorbookuser -Dspring.datasource.password=authorbookpass"
    
  • book-review-api

    ./mvnw clean spring-boot:run --projects book-review-api \
    -Dspring-boot.run.jvmArguments="-Dspring.data.mongodb.username=bookreviewuser -Dspring.data.mongodb.password=bookreviewpass"
    

Run Applications as Docker containers

Build Application's Docker Images

  • Open a terminal and make sure you are in springboot-graphql-databases root folder

  • In order to build the docker images, run the following script

    ./docker-build.sh
    

Application's environment variables

  • author-book-api

    Environment Variable Description
    MYSQL_HOST Specify host of the MySQL database to use (default localhost)
    MYSQL_PORT Specify port of the MySQL database to use (default 3306)
    ZIPKIN_HOST Specify host of the Zipkin distributed tracing system to use (default localhost)
    ZIPKIN_PORT Specify port of the Zipkin distributed tracing system to use (default 9411)
    BOOK_REVIEW_API_HOST Specify host of the book-review-api service (default localhost)
    BOOK_REVIEW_API_PORT Specify port of the book-review-api service (default 9080)
  • book-review-api

    Environment Variable Description
    MONGODB_HOST Specify host of the MongoDB database to use (default localhost)
    MONGODB_PORT Specify port of the MongoDB database to use (default 27017)
    ZIPKIN_HOST Specify host of the Zipkin distributed tracing system to use (default localhost)
    ZIPKIN_PORT Specify port of the Zipkin distributed tracing system to use (default 9411)

Start Applications as Docker containers

  • In a terminal, make sure you are inside springboot-graphql-databases root folder

  • Run following script

    ./start-apps.sh
    

Application's Link

Application URL Type URL
author-book-api Swagger http://localhost:8080/swagger-ui.html
author-book-api GraphiQL http://localhost:8080/graphiql
book-review-api GraphiQL http://localhost:9080/graphiql

How to use GraphiQL

  • book-review-api

    1. In a browser, access http://localhost:9080/graphiql

    2. Create a book and return its id

      mutation {
        createBook(bookInput: {title: "Learning GraphQL and Relay", isbn: "9781786465757"}) {
         id
        }
      }
      
    3. Add one review for the book created above, suppose the id is 5bd4bd4790e9f641b7388f23

      mutation {
        addBookReview(bookId: "5bd4bd4790e9f641b7388f23", reviewInput: {reviewer: "Ivan Franchin", comment: "It is a very good book", rating: 5}) {
          id
        }
      }
      
    4. Get all books stored in book-review-api, including their reviews

      {
        getAllBooks {
          id
          title
          isbn
          reviews {
            comment
            rating
            reviewer
            createdAt
          }
        }
      }
      
  • author-book-api

    1. In a browser, access http://localhost:8080/graphiql

    2. Create an author and return its id

      mutation {
        createAuthor(authorInput: {name: "Samer Buna"}) {
          id
        }
      }
      
    3. Create a book and return the book id and author name

      Note: while creating this book in author-book-api, we are setting the same ISBN, 9781786465757, as we did when creating the book in book-review-api.

      mutation {
        createBook(bookInput: {authorId: 1, isbn: "9781786465757", title: "Learning GraphQL and Relay", year: 2016}) {
          id
          author {
            name
          }
        }
      }
      
    4. Get author by id and return some information about his/her books including reviews of the book from book-review-api.

      Note: as the book stored in author-book-api and book-review-api has the same ISBN, 9781786465757, it's possible to retrieve the reviews of the book. Otherwise, an empty list will be returned in case book-review-api does not have a specific ISBN or the service is down.

      {
        getAuthorById(authorId: 1) {
          name
          books {
            isbn
            title
            bookReview {
              reviews {
                reviewer
                rating
                comment
                createdAt
              }
            }
          }
        }
      }
      
    5. Update book title and return its id and new title

      mutation {
        updateBook(bookId: 1, bookInput: {title: "Learning GraphQL and Relay 2"}) {
          id
          title
        }
      }
      
    6. Delete the author and return his/her id

      mutation {
        deleteAuthor(authorId: 1) {
          id
        }
      }
      

Useful links & commands

  • Zipkin

    It can be accessed at http://localhost:9411

  • MySQL monitor

    docker exec -it mysql mysql -uauthorbookuser -pauthorbookpass --database=authorbookdb
    show tables;
    select * from authors;
    select * from books;
    

    Type exit to get out of MySQL monitor

  • MongoDB shell

    docker exec -it mongodb mongo -ubookreviewuser -pbookreviewpass --authenticationDatabase bookreviewdb
    use bookreviewdb;
    db.books.find().pretty();
    

    Type exit to get out of MongoDB shell

Shutdown

  • To stop applications
    • If they were started with Maven, go to the terminals where they are running and press Ctrl+C
    • If they were started as a Docker container, go to a terminal and, inside springboot-graphql-databases root folder, run the script below
      ./stop-apps.sh
      
  • To stop and remove docker-compose containers, network and volumes, go to a terminal and, inside springboot-graphql-databases root folder, run the following command
    docker-compose down -v
    

Cleanup

To remove the Docker images created by this project, go to a terminal and, inside springboot-graphql-databases root folder, run the following script

./remove-docker-images.sh

TODO

  • study how to implement authentication/authorization to GraphQL endpoint;
  • implement graphql subscription;

References