scalasprayspray-dsl

is it possible to write a directive to match "any other query params"?


To ensure people don't append random query parameters (e.g. appending &r=234522.123 or similar) to avoid hitting our cache I want to have a way to reject any queries that are not handled explicitly. I can of course create one that contains a whitelist, but that would have to be separately maintained and I hate maintaining two things that needs to stay in synch. (Though, it would aid in failing faster.) Is this possible with Spray routing?


Solution

  • I ended up with this:

    // This contains a white-list of allowed query parameters. This is useful to
    // ensure people don't try to use &r=234234 to bust your caches.
    def allowedParameters(params: String*): Directive0 = parameterSeq.flatMap {
      case xs =>
        val illegal = xs.collect {
          case (k, _) if !params.contains(k) => k
        }
        if (illegal.nonEmpty)
          reject(ValidationRejection("Illegal query parameters: " + illegal.mkString("", ", ", "\nAllowed ones are: ") + params.mkString(", ")))
        else
          pass
    }
    

    For usage, have a look at the unit tests:

    val allowedRoute = {
      allowedParameters("foo", "bar") {
        complete("OK")
      }
    }
    
    "Allowed Parameter Directive" should "reject parameters not in its whitelist" in {
      Get("/?foo&bar&quux") ~> allowedRoute ~> check {
        handled should equal(false)
        rejection should be(ValidationRejection("Illegal query parameters: quux\nAllowed ones are: foo, bar"))
      }
    }
    
    it should "allow properly sorted parameters through" in {
      Get("/?bar&foo") ~> allowedRoute ~> check {
        handled should equal(true)
        responseAs[String] should equal("OK")
      }
    }