Rison: URI friendly strucured data representation

Rison is a data format which is similar to JSON but extremely URI friendly. There is no need to explanation. First of all, see the following examples to know the basis of Rison:

// Object
(name:Lacazette,age:27,stats:(appearances:20,goals:7,assists:5))
// Array
!(Aubameyang,Lacazette,Ozil)

This Rison is same as JSONs below:

// Object
{
"name": "Lacazette",
"age": 27,
"stats": {
"appearances": 20,
"goals": 7,
"assists": 5
}
}
// Array
[
"Aubameyang",
"Lacazette",
"Ozil"
]

(...) is object and !(...) is array in Rison, and no need to quote strings if they are not contain whitespaces or delimiter like :,, ,( or ).

All above Risons can be put into URI as the query string without URI encoding. Of course, if your Rison contains charactors necessary to be encoded, you need to encode them. But Rison is designed to minimize the chance of encoding. And some charactors which are usually needed to be encoded aren’t encoded in Rison.

Rison also has more compact version named “O-rison” and “A-rison”. They are representation just without outermost parentheses like below:

// O-rison
name:Lacazette,age:27
// A-rison
Aubameyang,Lacazette,Ozil

As you may know, Rison has been already used in Elastic’s Kibana etc.

There are already Rison parsers for some programming languages like JavaScript, Python or Golang, but I couldn’t find one for Scala, so I started to write Rison parser for Scala using Scala’s parser combinator library.

This scalara-rison library is very easy to use. Here is an example:

import com.github.takezoe.rison._

val parser = new RisonParser()

// parse
parser.parse("(name:Lacazette,age:27)") match {
case Right(node) => println(node.toScala) // => Map(name -> Lacazette, age -> 27)
case Left(error) => println(error)
}

// convert from Scala's Map
val node: RisonNode = RisonNode.fromScala(
Map(
"name" -> "Alexandre Lacazette",
"twitter" -> "@LacazetteAlex"
)
)
println(node.toRisonString) // => (name:'Alexandre Lacazette',twitter:'@LacazetteAlex')

// URL encode
val encoded: String = node.toUrlEncodedString
println(encoded) // => (name:'Alexandre+Lacazette',twitter:'@LacazetteAlex')

Also O-rison and A-rison can be handled very easily.

// O-rison
val orison: ObjectNode = parser.parseObject("name:Lacazette,age:27")
println(orison.toObjectString) // => name:Lacazette,age:27

// A-rison
val arison: ArrayNode = parser.parseArray("Lacazette,Aubameyang,Ozil")
println(arison.toArrayString) // => Lacazette,Aubameyang,Ozil

Currently, scala-rison supports convert from / to Map or Array, but I have a plan to support case classes (using Shapeless?).

Anyway, if you are looking for a good way to embed structured data into URI, Rison is worth to take a look.