Jay Taylor's notes

back to listing index

spray | Documentation » 1.1-SNAPSHOT » spray-routing

[web search]
Original source (spray.io)
Tags: scala jvm open-source code oss spray spray.io
Clipped on: 2014-02-21

spray-routing

The spray-routing module provides a high-level, very flexible routing DSL for elegantly defining RESTful web services. Normally you would use it either on top of a spray-can HTTP Server or inside of a servlet container together with spray-servlet.

Minimal Example

This is a complete, very basic spray-routing application:

import spray.routing.SimpleRoutingApp

object Main extends App with SimpleRoutingApp {
  implicit val system = ActorSystem("my-system")

  startServer(interface = "localhost", port = 8080) {
    path("hello") {
      get {
        complete {
          <h1>Say hello to spray</h1>
        }
      }
    }
  }
}

It starts a spray-can HTTP Server on localhost and replies to GET requests to /hello with a simple response.

Longer Example

The following is a spray-routing route definition that tries to show off a few features. The resulting service does not really do anything useful but its definition should give you a feel for what an actual API definition with spray-routing will look like:

import scala.concurrent.duration.Duration
import spray.routing.HttpService
import spray.routing.authentication.BasicAuth
import spray.routing.directives.CachingDirectives._
import spray.httpx.encoding._

trait LongerService extends HttpService with MyApp {

  val simpleCache = routeCache(maxCapacity = 1000, timeToIdle = Duration("30 min"))

  val route = {
    path("orders") {
      authenticate(BasicAuth(realm = "admin area")) { user =>
        get {
          cache(simpleCache) {
            encodeResponse(Deflate) {
              complete {
                // marshal custom object with in-scope marshaller
                getOrdersFromDB
              }
            }
          }
        } ~
        post {
          // decompresses the request with Gzip or Deflate when required
          decompressRequest() {
            // unmarshal with in-scope unmarshaller
            entity(as[Order]) { order =>
              // transfer to newly spawned actor
              detach() {
                complete {
                  // ... write order to DB
                  "Order received"
                }
              }
            }
          }
        }
      }
    } ~
    // extract URI path element as Int
    pathPrefix("order" / IntNumber) { orderId =>
      pathEnd {
        // method tunneling via query param
        (put | parameter('method ! "put")) {
          // form extraction from multipart or www-url-encoded forms
          formFields('email, 'total.as[Money]).as(Order) { order =>
            complete {
              // complete with serialized Future result
              (myDbActor ? Update(order)).mapTo[TransactionResult]
            }
          }
        } ~
        get {
          // JSONP support
          jsonpWithParameter("callback") {
            // use in-scope marshaller to create completer function
            produce(instanceOf[Order]) { completer => ctx =>
              processOrderRequest(orderId, completer)
            }
          }
        }
      } ~
      path("items") {
        get {
          // parameters to case class extraction
          parameters('size.as[Int], 'color ?, 'dangerous ? "no")
                  .as(OrderItem) { orderItem =>
            // ... route using case class instance created from
            // required and optional query parameters
          }
        }
      }
    } ~
    path("documentation") {
      // cache responses to GET requests
      cache(simpleCache) {
        // optionally compresses the response with Gzip or Deflate
        // if the client accepts compressed responses
        compressResponse() {
          // serve up static content from a JAR resource
          getFromResourceDirectory("docs")
        }
      }
    } ~
    path("oldApi" / Rest) { pathRest =>
      redirect("http://oldapi.example.com/" + pathRest, StatusCodes.MovedPermanently)
    }
  }
}