Over a million developers have joined DZone.

Control-Allow-Origin in Spray

· Performance Zone

Download Forrester’s “Vendor Landscape, Application Performance Management” report that examines the evolving role of APM as a key driver of customer satisfaction and business success, brought to you in partnership with BMC.

It is 2013, we have modern browsers. And these browsers do not like to load resources from origin that’s different from the resource being displayed. So, if you have a page at http://www.foo.com and want to make a request to http://api.bar.com, the browsers will (and should) reject it, unless you explicitly allow it.

We use the Access-Control-Allow-Origin HTTP header to do just that. Now, if you have a Spray route that uses the Spray JSON support to marshal the responses, you’re a bit stuck. You have something like

path("transactions" / JavaUUID) { id: TransactionId =>
  get {
    complete {
       (actor ? Messsage(id)).mapTo[Response]

Now what? You still want to use the convenient marshallers (e.g. Spray JSON), but you want to specify the HTTP header. I have created the CrossLocationRouteDirectives, which lets you do just that. The only downside is that there is another block inside complete.

... with CrossLocationRouteDirectives {

  val origin = "http://www.foo.com"

  path("transactions" / JavaUUID) { id: TransactionId =>
    get {
      complete {
        fromObjectCross(origin) {
          (actor ? Messsage(id)).mapTo[Response]

This makes everything tick along quite nicely: you still have the marshalling infrastructure, and you can now allow the remote origin by setting the value of the Access-Control-Allow-Origin HTTP header. To skin the can it yet another way (a charming British saying!), you can now have some jQuery AJAX in your pages on http://www.foo.com that make requests to http://api.bar.com.

    type: "GET",
    url: "http://api.bar.com/transactions/...",
}).done(function(data) {
   // ponies & unicorns
}).fail(function(jqXHR, textStatus, errorThrown) {
   // PHP!

The code of CrossLocationRouteDirectives is quite simply

trait CrossLocationRouteDirectives extends RouteDirectives {

  implicit def fromObjectCross[T: Marshaller](origin: String)(obj: T) =
    new CompletionMagnet {
      def route: StandardRoute = 
        new CompletionRoute(OK, 
              RawHeader("Access-Control-Allow-Origin", origin) :: Nil, obj)

  private class CompletionRoute[T: Marshaller](status: StatusCode, 
                                               headers: List[HttpHeader], 
                                               obj: T)
    extends StandardRoute {

    def apply(ctx: RequestContext) {
      ctx.complete(status, headers, obj)

See Forrester’s Report, “Vendor Landscape, Application Performance Management” to identify the right vendor to help IT deliver better service at a lower cost, brought to you in partnership with BMC.


Published at DZone with permission of Jan Machacek, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}