Search code examples
scalagraphqlsangriagraphql-schema

Can't figure out how Sangria does conversion from GraphQL type to Scala type


Context

I have setup like so:

case class Foo(
  option_enum_vector_field: Option[Vector[Bar]] // Bar is complicated object which can't be easily expressed with sangria default scalars, but can be created by using Bar.apply(enum_str: String)
)

// My expected GraphQL input type for Bar
implicit val FooEnumFieldType = EnumType(
  "FooEnumFieldType",
  Some("description"),
  List(
    EnumValue("high", value = "high"),
    EnumValue("medium", value = "medium"),
    EnumValue("low", value = "low")
  )
)

val FooType = ObjectType(
  "FooType",
  "description",
  fields[Unit, Foo](
    Field("option_enum_vector_field", OptionType(ListType(FooEnumFieldType)), resolve = _.value.???),
  )
)

In resolve = ctx => ctx.value.option_enum_vector_field is what the result should be so it expects Option[Vector[Bar]] type. Because I put OptionType(ListType(FooEnumFieldType)) as my GraphQL type there is a mismatch between types and compiler is swearing at me.

What I do not understand is where and how I should tell Sangria how to go from FooEnumFieldType GraphQL input to Bar type by taking enum value from client and doing Bar.apply("high") for example.

Questions

  1. How to define mappings from GraphQL enum types to Scala types in sangria?
  2. How to get values passed from client in resolve function?

Solution

  • You need a ObjectType for Bar to allow sangria to use it as an output type. The simplest method would be to derive the object type for Bar automatically.

    implicit val BarType =
      deriveObjectType[Unit, Bar]()
    

    This requires sangria to be able to convert all the elements of Bar so if that is not possible then a custom object may be required.

    implicit val BarType: ObjectType[Unit, Bar] = ObjectType(
      "Bar",
      "Bar",
      fields[Unit, Bar](
        Field("id", IDType, resolve = _.value.id),
        // other fields
      )
    )
    

    Sangria use this implicit value to convert Bar values to BarType values which, in turn, can be used to generate the JSON output as required. ObjectType is a typeclass that can be used in other sangria methods to process objects of type Bar.

    Finally the "option_enum_vector_field" field needs to have the appropriate type:

    Field("option_enum_vector_field", OptionType(ListType(BarType)), resolve = _.value.option_enum_vector_field),
    

    [ If you are actually implementing a mutation then you need to create an instance of InputObjectType that performs the reverse mapping ]