Spray: sanitize query params with shapeless

Overkill imports

  import spray.routing._
  import shapeless._
  import poly._

Define sanity check

def sanitize(x: String): String = 
  (escapeJavascript compose escapeHtmlTags compose ...)(x)

Put polymorphic sanity adder

trait DefaultSanity extends Poly1 {
  implicit def saneDefault[A] = at[A](identity)
}

Override sanity for strings

object Sanity extends DefaultSanity {
  implicit def saneString = at[String](sanitize(_))
  implicit def saneOptString = at[Option[String]](_.map(sanitize))
}

Define query params wrapper classes (2 classes just for fun, could be single class)

case class InsaneParams(
  a: Int,
  b: String,
  c: Option[String]
)

case class SaneParams(
  a: Int,
  b: String,
  c: Option[String]
)

Apply sanity to wrapper class

  def sanitizeParams(x: InsaneParams): SaneParams = {
    val saneTuple = InsaneParams.unapply(x).get.map(Sanity)
    (SaneParams.apply _) tupled saneTuple
  }

Upgrade spray parameters directive with some sanity

  val saneParameters = 
    parameters(('a, 'b, 'c.?)).as(InsaneParams).map(sanitizeParams)

At last, define spray route with params sanity check

   import spray.http.StatusCodes.OK

   val route = 
     get("sanity") {
       saneParameters { params =>
      	   // only sane params allowed here!
      	   complete(OK)
      	 }
     }

Igor Shymko

Igor Shymko
Lives and works in Kiev, Ukraine. Writes scala programs as full time job, enjoys good electronic music, tasty coffee, good mood, loves snowboarding!

Package by feature

Links regarding packaging best practice Continue reading

Ubiquitous language

Published on February 18, 2017

Multi-kill

Published on December 04, 2016