Skip to content

Instantly share code, notes, and snippets.

@anotherhale
Forked from OlegIlyenko/SangriaMutationExample.scala
Last active September 11, 2018 19:13
Show Gist options
  • Save anotherhale/cc53d8b62650030352b38342369b252b to your computer and use it in GitHub Desktop.
Save anotherhale/cc53d8b62650030352b38342369b252b to your computer and use it in GitHub Desktop.
Simple example of a mutation with complex input type argument
import sangria.schema._
import sangria.execution._
import sangria.macros._
import sangria.macros.derive._
import sangria.marshalling.circe._
import scala.concurrent.ExecutionContext.Implicits.global
import io.circe.generic.auto._
import enumeratum._
sealed trait Genre extends EnumEntry
case object Genre extends Enum[Genre] with CirceEnum[Genre] {
case object FANTASY extends Genre
case object MYSTERY extends Genre
case object FICTION extends Genre
case object SCIENCE_FICTION extends Genre
case object NONFICTION extends Genre
val values = findValues
}
case class Author(name: String, publishedBooks: Int = 0)
case class Book(title: String, authors: Seq[Author], genre: Genre)
// Stub repository to store the value
class Repo {
private var storedBook: Option[Book] = None
def saveBook(book: Book): Unit = {
storedBook = Some(book)
}
def loadBook(): Option[Book] = storedBook
}
// Input object defined explicitly
implicit val AuthorInputType = InputObjectType[Author]("AuthorInput", List(
InputField("name", StringType),
InputField("publishedBooks", IntType, defaultValue = 0)))
// Input object derived with macro
implicit val BookInputType = InputObjectType[Book]("BookInput", List(
InputField("title", StringType),
InputField("genre", GenreEnum),
InputField("author", AuthorInputType)))
// Output objects
implicit val GenreType: EnumType[Genre] = deriveEnumType[Genre]()
implicit val AuthorType = deriveObjectType[Unit, Author]()
implicit val BookType = deriveObjectType[Unit, Book]()
// Schema definition
val BookArg = Argument("book", BookInputType)
val QueryType = ObjectType("Query", fields[Repo, Unit](
Field("book", OptionType(BookType), resolve = _.ctx.loadBook())))
val MutationType = ObjectType("Mutation", fields[Repo, Unit](
Field("saveBook", OptionType(BookType),
arguments = BookArg :: Nil,
resolve = c ⇒ {
val book = c arg BookArg
c.ctx.saveBook(book)
book
})))
val schema = Schema(QueryType, Some(MutationType))
// Test query
val query =
gql"""
mutation {
saveBook(book: {title: "Sapiens", genre: NONFICTION, authors: [{name: "Yuval Noah Harari", publishedBooks: 6}]}) {
title
genre
authors {
name
publishedBooks
}
}
}
"""
val context = new Repo
val result = Executor.execute(schema, query, context)
result.foreach(res ⇒ println(res.spaces2))
// Prints:
//
// {
// "data": {
// "saveBook": {
// "title": "Sapiens",
// "genre": "NONFICTION",
// "authors": [
// {
// "name": "Yuval Harari",
// "publishedBooks": 6
// }
// ]
// }
// }
// }
@anotherhale
Copy link
Author

@OlegIlyenko
I am trying to play with an Enum Input type parameter. If you could provide any insight or direction that would be great.

Here is the error that I am getting right now:

Caused by: java.lang.IllegalStateException: A `null` value was provided instead of type for a field 'genre' of 'BookInput' input object type.
This can happen if you have recursive type definition or circular references within your type graph.
Please use no-arg function to provide fields for such types.

@mandeeeep
Copy link

mandeeeep commented Sep 11, 2018

@anotherhale
I am assuming the Prints: ....outputs ... was before the enums implementations,

Might be because you aren't sending genre value; since its InputField("genre", GenreEnum) not InputField("genre",OptionInputType( GenreEnum)), and genre being a required field.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment