How to match specific accept headers in a route?
Asked Answered
G

2

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.

Garnish answered 2/10, 2013 at 6:57 Comment(0)
M
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

Mcwherter answered 2/10, 2013 at 7:47 Comment(2)
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.Garnish
@Garnish Sorry, didn't know that, thanks. You can replace ${mr: _*} with ${mr.mkString(", ")}Mcwherter
C
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.

Constantinople answered 2/10, 2013 at 7:27 Comment(1)
thank you that should work. Although I probably should change if actual == required to if actual.split(",") contains required or something like that.Garnish

© 2022 - 2024 — McMap. All rights reserved.