Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GraphQL example #14

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ based on our experience in different actual small and large scale projects.
- [Caching](/examples/caching)
- [Panache JPA with Repository Pattern](/examples/data-jpa-repository)
- [Fault Tolerance](/examples/fault-tolerance)
- [GraphQL](/examples/graphql)
- [MongoDB](/examples/mongodb)
- [Reactive-App](/examples/reactive-app)
6 changes: 6 additions & 0 deletions examples/graphql/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Quarkus GraphQL

This module demonstrates how to create and test a [GraphQL](https://graphql.org/) interface
with [Quarkus](https://quarkus.io/).

For more information see [Quarkus Smallrye GraphQL](https://quarkus.io/guides/smallrye-graphql).
11 changes: 11 additions & 0 deletions examples/graphql/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
val testcontainersVersion: String by project

dependencies {
implementation("io.quarkus:quarkus-smallrye-graphql")

testImplementation("io.quarkus:quarkus-smallrye-graphql-client")
}

noArg {
annotation("cnt.graphql.business.configuration.AddDefaultNoArgConstructor")
}
33 changes: 33 additions & 0 deletions examples/graphql/src/main/kotlin/cnt/graphql/InitializeData.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package cnt.graphql

import cnt.graphql.business.Movie
import cnt.graphql.business.MovieService
import io.quarkus.runtime.Startup
import javax.enterprise.context.ApplicationScoped

@Startup
@ApplicationScoped
class InitializeData {
private val movieService: MovieService

constructor(movieService: MovieService) {
this.movieService = movieService
// initializeMovies() // uncomment this to create a list of movies on app startup
}

private fun initializeMovies() =
listOf(
Movie(
title = "Pulp Fiction",
director = "Quentin Tarantino",
publishYear = 1994
),
Movie(
title = "Jackie Brown",
director = "Quentin Tarantino",
publishYear = 1997
)
).forEach {
movieService.add(it)
}
}
36 changes: 36 additions & 0 deletions examples/graphql/src/main/kotlin/cnt/graphql/api/MovieResource.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cnt.graphql.api

import cnt.graphql.business.Movie
import cnt.graphql.business.MovieService
import org.eclipse.microprofile.graphql.Description
import org.eclipse.microprofile.graphql.GraphQLApi
import org.eclipse.microprofile.graphql.Mutation
import org.eclipse.microprofile.graphql.Query
import java.util.*


@GraphQLApi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Detekt trained me: too many blank lines ;)

class MovieResource(
private val movieService: MovieService
) {

@Query
@Description("Get all movies")
fun getAllMovies() = movieService.getAll()

@Query
@Description("Get a specific movie by its ID")
fun getMovie(id: UUID) = movieService.getSingle(id)

@Mutation
@Description("Create and save a new movie")
fun createMovie(movie: Movie) = movieService.add(movie)

@Mutation
@Description("Delete a movie by its ID")
fun deleteMovie(id: UUID) = movieService.delete(id)

// @Query("allActors")
// @Description("Get all Actors")
// fun getAllActors() = movieService.getAllActors()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove?

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package cnt.graphql.business

annotation class AddDefaultNoArgConstructor
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package cnt.graphql.business

import java.util.*
import javax.enterprise.context.ApplicationScoped

@ApplicationScoped
class IdGenerator {
fun generateId(): UUID = UUID.randomUUID()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package cnt.graphql.business

import cnt.graphql.persistence.MovieRepository
import java.util.*
import javax.enterprise.context.ApplicationScoped

@ApplicationScoped
class MovieService(
private val idGenerator: IdGenerator,
private val movieRepository: MovieRepository
) {

fun add(movie: Movie): Movie {
val id = idGenerator.generateId()
return movieRepository.save(movie.copy(id = id))
}

fun getAll(): List<Movie> = movieRepository.getAll()

fun getSingle(id: UUID): Movie? = movieRepository.getById(id)

fun delete(id: UUID): Boolean = movieRepository.deleteById(id)

}
11 changes: 11 additions & 0 deletions examples/graphql/src/main/kotlin/cnt/graphql/business/model.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package cnt.graphql.business

import java.util.*

@AddDefaultNoArgConstructor
data class Movie(
var id: UUID? = null,
var title: String,
var director: String,
var publishYear: Int
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package cnt.graphql.persistence

import cnt.graphql.business.Movie
import java.util.*
import javax.enterprise.context.ApplicationScoped

@ApplicationScoped
class MovieRepository {

private val database = mutableMapOf<UUID, Movie>()

fun save(movie: Movie): Movie {
val id = movie.id ?: error("id of movie [$movie] was not set!")
database[id] = movie
return movie
}

fun deleteById(id: UUID) = database.remove(id) != null

fun getById(id: UUID): Movie? = database[id]

fun getAll(): List<Movie> = database.values.toMutableList()

fun deleteAll() = database.clear()
}
284 changes: 284 additions & 0 deletions examples/graphql/src/main/resources/META-INF/resources/index.html

Large diffs are not rendered by default.

Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package cnt.graphql

import cnt.graphql.business.Movie
import io.quarkus.test.junit.QuarkusTest
import io.smallrye.graphql.client.GraphQLClient
import io.smallrye.graphql.client.core.Argument.arg
import io.smallrye.graphql.client.core.Argument.args
import io.smallrye.graphql.client.core.Document.document
import io.smallrye.graphql.client.core.Field.field
import io.smallrye.graphql.client.core.InputObject.inputObject
import io.smallrye.graphql.client.core.InputObjectField.prop
import io.smallrye.graphql.client.core.Operation.operation
import io.smallrye.graphql.client.core.OperationType.MUTATION
import io.smallrye.graphql.client.dynamic.api.DynamicGraphQLClient
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import java.util.*
import javax.inject.Inject

@QuarkusTest
class ApplicationEndToEndTests {

@Inject
@GraphQLClient("movie-test-client")
private lateinit var dynamicClient: DynamicGraphQLClient

@Test
fun `create a movie and retrieve it afterwards`() {
val createQuery = document(
operation(
MUTATION,
field(
"createMovie",
args(
arg(
"movie", inputObject(
prop("title", "Inception"),
prop("director", "Christopher Nolan"),
prop("publishYear", 2010)
)
)
),
field("id"),
field("title"),
field("director"),
field("publishYear")
)
)
)
val createdMovie = dynamicClient.executeSync(createQuery).getObject(Movie::class.java, "createMovie")
assertMovie(createdMovie, createdMovie.id)

val retrieveQuery = document(
operation(
field(
"movie",
args(arg("id", createdMovie.id)),
field("id"),
field("title"),
field("director"),
field("publishYear")
)
)
)
val retrievedMovie = dynamicClient.executeSync(retrieveQuery).getObject(Movie::class.java, "movie")
assertMovie(retrievedMovie, retrievedMovie.id)
}

private fun assertMovie(movie: Movie?, id: UUID?) {
assertThat(movie).isNotNull
with(movie!!) {
assertThat(id).isEqualTo(id)
assertThat(title).isEqualTo("Inception")
assertThat(director).isEqualTo("Christopher Nolan")
assertThat(publishYear).isEqualTo(2010)
}
}
}
Loading