4

I want to create a route that matches only if the client sends a specific Accept header. I use Spray 1.2-20130822.

I'd like to get the route working:

def receive = runRoute {
    get {
      path("") {
        accept("application/json") {
           complete(...)
        }
      }
    }
  }

Here I found a spec using an accept() function, but I can't figure out what to import in my Spray-Handler to make it work as directive. Also, I did not find other doc on header directives but these stubs.

Jacek Laskowski
  • 72,696
  • 27
  • 242
  • 420
rompetroll
  • 4,781
  • 2
  • 37
  • 50

2 Answers2

5

I would do this way:

def acceptOnly(mr: MediaRange*): Directive0 =
  extract(_.request.headers).flatMap[HNil] {
    case headers if headers.contains(Accept(mr)) ⇒ pass
    case _                                       ⇒ reject(MalformedHeaderRejection("Accept", s"Only the following media types are supported: ${mr.mkString(", ")}"))
  } & cancelAllRejections(ofType[MalformedHeaderRejection])

Then just wrap your root:

path("") {
  get {
    acceptOnly(`application/json`) {
      session { creds ⇒
        complete(html.page(creds))
      }
    }
  }
}

And by the way the latest spray 1.2 nightly is 1.2-20130928 if you can, update it

4lex1v
  • 21,367
  • 6
  • 52
  • 86
  • A tiny bug here: the string interpolation of `${mr: _*}` fails if more than one `MediaRange` are passed in and none of them are matched. If I change that to `${mr}` it runs, though the output contains the type of `mr` now which probably is not intended. – rompetroll Oct 02 '13 at 08:38
  • 2
    @rompetroll Sorry, didn't know that, thanks. You can replace `${mr: _*}` with `${mr.mkString(", ")}` – 4lex1v Oct 02 '13 at 08:46
2

There is no pre-defined directive called accept directive. You can see the full list of available directives here.

However, you can use the headerValueByName directive to make a custom directive that does what you desire:

def accept(required: String) = headerValueByName("Accept").flatMap {
  case actual if actual.split(",").contains(required) => pass
  case _ => reject(MalformedHeaderRejection("Accept", "Accept must be equal to " + required))
}

Put this code in scope of your spray Route, then just use as you have shown in your question.

Alvaro Montoro
  • 28,081
  • 7
  • 57
  • 86
theon
  • 14,170
  • 5
  • 51
  • 74
  • 2
    thank you that should work. Although I probably should change `if actual == required` to `if actual.split(",") contains required` or something like that. – rompetroll Oct 02 '13 at 07:46