sangria v0.5.0 Release Notes

Release Date: 2015-12-03 // over 8 years ago
    • ๐ŸŽ A lot of performance improvements across the whole library
    • โž• Added basic subscription support as defined in the spec (https://github.com/facebook/graphql/pull/109) and reference implementation (#89). At the moment subscriptions are pretty basic, so it's meant more for experiments rather than for use in real applications. It is very likely that this feature will experience breaking changes in the near future (spec change)
    • ๐Ÿ‘ Much better handling of input objects (#37, #70). A new type-class is introduced: FromInput. It provides high-level and low-level way to deserialize arbitrary input objects, just like ToInput.

    In order to use this feature, you need to provide a type parameter to the InputObjectType:

      case class Article(title: String, text: Option[String])
    
      val ArticleType = InputObjectType[Article]("Article", List(
        InputField("title", StringType),
        InputField("text", OptionInputType(StringType))))
    
      val arg = Argument("article", ArticleType)
    

    This code will not compile unless you define an implicit instance of FromInput for Article case class:

      implicit val manual = new FromInput[Article] {
        val marshaller = CoercedScalaResultMarshaller.default
        def fromResult(node: marshaller.Node) = {
          val ad = node.asInstanceOf[Map[String, Any]]
    
          Article(
            title = ad("title").asInstanceOf[String],
            text = ad.get("text").flatMap(_.asInstanceOf[Option[String]])
        }
      }
    

    As you can see, you need to provide a ResultMarshaller for desired format and then use a marshaled value to create a domain object based on it. Many instances of FromInput are already provided out-of-the-box. For instance FromInput[Map[String, Any]] was added to support existing map-like data-structure format. All supported Json libraries also provide FromInput[JsValue] so that you can use Json AST instead of working with Map[String, Any].

    Moreover, play-json and spray-json integration provide support for Reads and JsonFormat. This means that your domain objects are automatically supported as long as you have Reads or JsonFormat defined for them. For instance this example should compile and work just fine without explicit FromInput declaration:

      import sangria.integration.playJson._
      import play.api.libs.json._
    
      case class Article(title: String, text: Option[String])
    
      implicit val articleFormat = Json.format[Article]
    
      val ArticleType = InputObjectType[Article]("Article", List(
        InputField("title", StringType),
        InputField("text", OptionInputType(StringType))))
    
      val arg = Argument("article", ArticleType)
    

    CAUTION: this is minor breaking change. Together with null value support, this feature changes the way input objects are deserialized into map-like structures (which still happens by default). Optional input fields will now produce input objects like:

      // for JSON input: {"op1": "foo", "opt2": null} 
      Map("opt1" -> Some("foo"), "opt2" -> None)
    
      // for JSON input: {"op1": "foo"} 
      Map("opt1" -> Some("foo"))
    

    instead of (old format):

      // for JSON input: {"op1": "foo", "opt2": null} 
      Map("opt1" -> "foo")
    
      // for JSON input: {"op1": "foo"} 
      Map("opt1" -> "foo")
    

    As you can see, this allows you to distinguish between "undefined" json object fields and json object fields that are set to null.

    • ๐Ÿ‘ null value support (as defined in the spec change: https://github.com/facebook/graphql/pull/83) (#55) (spec change)
    • ๐Ÿ“œ Extracted input value parsing and made it a first-class citizen (#103). So now you can parse and render any ast.Value independently from GraphQL query. There is even a new graphqlInput macros available: ```scala import sangria.renderer.QueryRenderer import sangria.macros._ import sangria.ast

    val parsed: ast.Value = graphqlInput""" { id: "1234345" version: 2 # changed 2 times deliveries: [ {id: 123, received: false, note: null, state: OPEN} ] } """

    val rendered: String = QueryRenderer.render(parsed, QueryRenderer.PrettyInput)

    println(rendered)

      It will print something like this:
      ```js
      {
        id: "1234345"
        version: 2
        deliveries: [{
          id: 123
          received: false
          note: null
          state: OPEN
        }]
      }
    

    InputUnmarshaller and ResultMarshaller are also now available for it, so you can use ast.Value as a variables or it can be a result of GraphQL query execution (instead of more traditional JSON).

    • ๐Ÿ“ฆ ToInput, InputUnmarshaller and ResultMarshaller are moved to sangria.marshalling package.
    • ๐Ÿ‘Œ Improved error messages for input values (#86). Now they will contain the reason why particular value is invalid.
    • Implementations of interfaces can include additional field args (#90) (spec change)
    • Loosen overlapping field validation rules (#94) (spec change)
    • False positive validation error from fragment cycle when unknown fragment (#95)
    • Interfaces with covariant return types (#96)
    • ๐ŸŽ A lot of minor changes and performance improvements in validation rules and query validator (#97) (spec change)
    • โž• Add error handling in the SchemaRenderer (#100)
    • Ambiguous implicit when using a UnionType bug (#101)
    • ๐Ÿ”จ A lot of internal refactorings (especially in variable and argument processing) to make everything above possible