I'm currently working on an sbt plugin that generates Scala case classes at compile time to model JSON API responses for easy deserialization especially with the Scala play-json library.
The plugin makes it possible to access JSON documents in a statically typed way including auto-completion. It takes a sample JSON document as input (either from a file or a URL) and generates Scala types that can be used to read data with the same structure.
Let's look at a basic example, an app that prints the current Bitcoin price to the console.
Install the plugin and add the play-json library dependency.
project/plugins.sbt and add the following line:
addSbtPlugin("com.github.battermann" % "sbt-json" % "0.2.4")
build.sbt file we have to enable the plugin by adding this line:
Add the dependency to the play-json library:
libraryDependencies += "com.typesafe.play" %% "play-json" % "2.6.0"
You might want to run
reload if sbt is running.
Specify JSON source
By default the plugin analyzes all files in
src/main/resources/json with a
.json extension and generates Scala case classes that represent the corresponding JSON schema.
It is also possible to specify URLs that serve JSON data for case class generation.
Let's add a public URL from the coinddesk API to retrieve the current Bitcoin price to the
jsonUrls += "https://api.coindesk.com/v1/bpi/currentprice.json"
compile in sbt.
On the sbt compile task the Scala case classes are generated in the package
Writing the app
First we have to import the play-json library and the generated JSON models:
import models.json.currentprice._ import play.api.libs.json.Json
Now we can get the API response like this:
val url = "https://api.coindesk.com/v1/bpi/currentprice.json" val rawJson = scala.io.Source.fromURL(url).mkString
Because sbt-json generates play-json formats by default, we can parse the result to a
JsValue and implicitly cast it to the generated Scala case class:
val currentPrice = Json.parse(rawJson).as[Currentprice]
Finally we can access the required fields as they are represented as plain old Scala case classes with auto-completion enabled and print the current Bitcoin price in EURO on the console:
val info = currentPrice.bpi.EUR.description val priceInEuro = currentPrice.bpi.EUR.rate_float val date = currentPrice.time.updated println(s"Current Bitcoin price ($info): $priceInEuro (timestamp: $date)")
Running the program produces the following output:
Current Bitcoin price (Euro): 3691.8746 (timestamp: Aug 27, 2017 18:54:00 UTC)
There are a few more settings that can be used to configure the case class generation process and there are features that are not discussed here.
E.g. the generator will unify similar schemas and tries to find unique names that won't clash with any Scala reserved words. Fore more details see the GitHub README page.
Contributions are very welcome and highly appreciated. You can contribute by sending pull request, by reporting bugs and feature requests here, or by giving feedback and suggestions for improvement.