Chapter 2 Set up your environment

2.1 Download the project

Clone the repository.

git clone https://github.com/wesovilabs-workshops/workshop-graphql-java.git
cd workshop-graphql-java

2.2 Project structure

Project follows the guidelines for structuring a Java project with Gradle.

2.2.1 ./src/main/java

  • com.wesovilabs.workshops.graphql.domain: It contains the classes that represent the GraphQL domain model.

  • com.wesovilabs.workshops.graphql.database: This package contains two sub-packages model and repository. The first onw contains the database model and the second one the DAO layer.

  • com.wesovilabs.workshops.graphql.converter: This package contains classes that will help in order to make transformation between objects. Basically for transforming the GraphQL domain objects into entities that will be persisted into the database.

  • com.wesovilabs.workshops.graphql.publisher: Pub-sub implementations that will be used by subscription operations.

  • com.wesovilabs.workshops.graphql.resolver: It contains the resolver for our application: queries, mutations and subscriptions but also the resolver of the output types when it is required.

  • com.wesovilabs.workshops.graphql.service: This is the business layer which is call from the resolver package and It delegates the request to the repository.

  • com.wesovilabs.workshops.graphql.directive: Empty package that will be used during the workshop.

  • com.wesovilabs.workshops.graphql.scalar: Empty package that will be used during the workshop.

2.2.2 ./src/main/resources

  • workshop.graphqls: GraphQL schema that is implemented by our application.

  • application.yaml: Default configuration file used by spring-boot when running the application locally.

  • docker/Dockerfile: Docker descriptor for out application.

  • docker-compose/docker-compose.yml: Descriptor for launching bot database and our application.

  • docker-compose/api: Configuration files used by api container.

  • docker-compose/postgres: Configuration files used by postgres container.

2.3 Running the server

From the root directory you just need to execute

make deploy

or in case of you don’t have make command installed

./gradlew build;
docker build -f src/main/resources/docker/Dockerfile -t=wesovilabs/workshop-graphql-java:local .;
docker-compose -f src/main/resources/docker-compose/docker-compose.yml run --rm -p9001:9001 api

To verify that application was launched correctly, just open Graphiql

To clean the containers you just need to run

make docker-stop

or

docker-compose -f src/main/resources/docker-compose/docker-compose.yml down -v

2.3.1 While you’re coding

The above commands launch the full environment: database and api. On the other hand, when we’re coding we usually prefer restart the API to reload the changes.

  1. Launching database container from docker-compose
make database

or

docker-compose -f src/main/resources/docker-compose/docker-compose.yml run --rm -p5456:5432 database
  1. Run the application from your IDE or by command line
./gradlew bootRun

2.4 Workshop Application

The application is a movie cataloging tool.

The purpose of this workshop is to enrich the application with new functionality that will be required in upcoming chapters.

2.4.1 Database

Workshop database model

Workshop database model

Databases will be populated with below data when postgres container is launched.

directors
id full_name country
1 Tim Burton USA
2 James Cameron Canada
3 Steven Spielberg USA
4 Martin Scorsese UK
5 Alfred Hitchcock USA
6 Clint Eastwood UK
actors
id full_name country male
1 Johnny Depp USA true
2 Winona Ryder USA false
3 Russell Crowe Australia true
4 Joaquin Phoenix USA true
5 Al Pacino USA true
6 Robert de Niro USA true
movies
id title release_year genre budget trailer director_id
1 Edward Scissorhands 1990 SciFi 20 https://www.yout 1
2 Gladiator 2000 Drama 103 https://www.yout 7
movies_actors
movie_id actor_id
1 1
1 2
2 3
2 4

2.4.2 API

The below operations are already implemented in our project.

2.4.2.1 Queries

  • listDirectors:[Director!]: It returns the list of directors.
  • listActors:[Actor!]:It returns the list of actors.
  • listMovies:[Movie!]: It returns the list of movies.
  • getMovie(movieId:ID!):Movie: It returns the movie with given id.

2.4.2.2 Mutations

  • addMovie(request:MovieRequest):Movie!: It adds a new movie.
  • addDirector(request:DirectorRequest):Director!: It adds a new director.
  • deleteDirector(“Identifier of the director” direction:ID!):[Director!]: It deletes the director with the given id.

2.4.2.3 Subscriptions

  • listenDirectorMovies(directorId:ID!):Movie!: It opens a communication with the server and is notified when a new movie is created for the passed directorId in the request.

2.4.3 GraphQL schema

The graphql schema for our application looks like this:

schema {
    # The query root of Workshop GraphQL interface.
    query: Query
    # The root query for implementing GraphQL mutations.
    mutation: Mutation
    # The root query for implementing GraphQL subscriptions.
    subscription: Subscription

}

"""Available queries for Workshop API"""
type Query {
    """It returns the list of directors."""
    listDirectors:[Director!]
    """It returns the list of actors."""
    listActors:[Actor!]
    """It returns the list of movies."""
    listMovies:[Movie!]
    """It returns the movie with the fiven id"""
    getMovie("Movie identifier" movieId:ID!):Movie
}

"""Available mutations for Workshop API"""
type Mutation {
    """I adds a new movie"""
    addMovie(request:MovieRequest):Movie!
    """I adds a new actor"""
    addDirector(request:DirectorRequest):Director!
    """I deletes the director with the fiven identifier"""
    deleteDirector("Identifier of the director" directorId:ID!):[Director!]
}

"""Available subscriptions for Workshop API"""
type Subscription {
    """It returns the movies for a given director"""
    listenDirectorMovies(directorId:ID!):Movie!
}


"""Request info for creating a movie"""
input MovieRequest {
    "Name of the movie"
    title: String!
    "Year when the movie was released"
    year: Int
    "Genre for the movie, supported values should be: SciFi, Drama, Comedy or Action"
    genre: String
    "Budget for the movie, the value is provided in Euro"
    budget: Float!
    "URL in which we can watch the trailer of this movie"
    trailer: String
    "Identifier of director"
    directorId: ID!
}

"""Movie details"""
type Movie {
    "Unique identifier for each movie"
    id: ID!
    "Name of the movie"
    title: String!
    "Year when the movie was released"
    year: Int
    "Genre for the movie, supported values should be: SciFi, Drama, Comedy or Action"
    genre: String
    "Budget for the movie, the value is provided in Euro"
    budget: Float!
    "URL in which we can watch the trailer of this movie"
    trailer: String
    "The director details of the movie"
    director: Director!
    "List of actors for the movie"
    actors("Total of returned actors" total:Int=1): [Actor!]
}

"""Director details"""
type Director{
    "Unique identifier for each director"
    id: ID!
    "Full name of the director"
    fullName: String!
    "Country in which the director was born"
    country: String
}

"""Director creation request"""
input DirectorRequest{
    "Full name of the director"
    fullName: String!
    "Country in which the director was born"
    country: String
}

"""Actor details"""
type Actor {
    "Unique identifier for each actor"
    id: ID!
    "Full name of the actor"
    fullName: String!
    "Country in which the actor was born"
    country: String
    "Gender of actor: Supported values are male or female"
    gender: String
}