Permalink
Browse files

! routing: CompletionMagnet: gone, streamlining completion API: accom…

…plished

This change comes from the insight that with the new marshalling
infrastructure in place CompletionMagnet doesn't serve any higher
purpose.

By removing the now useless magnet layer composition is reinstantiated and
unification as shown in the accompanying test works (with a little help
from type annotations)
  • Loading branch information...
jrudolph committed Oct 16, 2013
1 parent 50128fb commit 7a36de5498e189088e293f29f378fc3355e18bd0
@@ -116,9 +116,45 @@ object ToResponseMarshaller extends LowPriorityToResponseMarshallerImplicits wit
mb(f(value, contentType), ctx.withContentTypeOverriding(contentType))
}
}
+ implicit def fromResponse: ToResponseMarshaller[HttpResponse] =
+ new ToResponseMarshaller[HttpResponse] {
+ def apply(value: HttpResponse, ctx: ToResponseMarshallingContext): Unit = ctx.marshalTo(value)
+ }
+ // No implicit conversion to StatusCode allowed here: in `complete(i: Int)`, `i` shouldn't be marshalled
+ // as a StatusCode
+ implicit def fromStatusCode: ToResponseMarshaller[StatusCode] =
+ new ToResponseMarshaller[StatusCode] {
+ def apply(value: StatusCode, ctx: ToResponseMarshallingContext): Unit = ctx.marshalTo(HttpResponse(value))
+ }
+ implicit def fromStatusCodeAndT[S, T](implicit sConv: S StatusCode, tMarshaller: Marshaller[T]): ToResponseMarshaller[(S, T)] =
+ new ToResponseMarshaller[(S, T)] {
+ def apply(value: (S, T), ctx: ToResponseMarshallingContext): Unit =
+ fromMarshaller(sConv(value._1), Nil).apply(value._2, ctx)
+ }
+ implicit def fromStatusCodeAndHeadersAndT[S, T](implicit sConv: S StatusCode, tMarshaller: Marshaller[T]): ToResponseMarshaller[(S, Seq[HttpHeader], T)] =
+ new ToResponseMarshaller[(S, Seq[HttpHeader], T)] {
+ def apply(value: (S, Seq[HttpHeader], T), ctx: ToResponseMarshallingContext): Unit =
+ fromMarshaller(sConv(value._1), value._2).apply(value._3, ctx)
+ }
}
sealed abstract class LowPriorityToResponseMarshallerImplicits {
implicit def liftMarshaller[T](implicit m: Marshaller[T]): ToResponseMarshaller[T] =
ToResponseMarshaller.fromMarshaller()
-}
+}
+
+/** Something that can later be marshalled into a response */
+trait ToResponseMarshallable {
+ def marshal(ctx: ToResponseMarshallingContext): Unit
+}
+object ToResponseMarshallable {
+ implicit def isMarshallable[T](value: T)(implicit marshaller: ToResponseMarshaller[T]): ToResponseMarshallable =
+ new ToResponseMarshallable {
+ def marshal(ctx: ToResponseMarshallingContext): Unit = marshaller(value, ctx)
+ }
+ implicit def marshallableIsMarshallable: ToResponseMarshaller[ToResponseMarshallable] =
+ new ToResponseMarshaller[ToResponseMarshallable] {
+ def apply(value: ToResponseMarshallable, ctx: ToResponseMarshallingContext): Unit = value.marshal(ctx)
+ }
+}
+
@@ -16,11 +16,12 @@
package spray.routing
-import scala.concurrent.Promise
+import scala.concurrent.{ Future, Promise }
import spray.http._
import HttpHeaders._
import StatusCodes._
import MediaTypes._
+import spray.httpx.marshalling.ToResponseMarshallable
class RouteDirectivesSpec extends RoutingSpec {
@@ -48,6 +49,40 @@ class RouteDirectivesSpec extends RoutingSpec {
get & complete(Promise.successful(HttpResponse(entity = "yup")).future)
} ~> check { responseAs[String] === "yup" }
}
+ "allow easy handling of futured ToResponseMarshallers" in {
+ trait RegistrationStatus
+ case class Registered(name: String) extends RegistrationStatus
+ case object AlreadyRegistered extends RegistrationStatus
+
+ val route =
+ get {
+ path("register" / Segment) { name
+ def registerUser(name: String): Future[RegistrationStatus] = Future.successful {
+ name match {
+ case "otto" AlreadyRegistered
+ case _ Registered(name)
+ }
+ }
+ complete {
+ registerUser(name).map[ToResponseMarshallable] {
+ case Registered(_) HttpData.Empty
+ case AlreadyRegistered
+ import spray.json.DefaultJsonProtocol._
+ import spray.httpx.SprayJsonSupport._
+ (StatusCodes.BadRequest, Map("error" -> "User already Registered"))
+ }
+ }
+ }
+ }
+
+ Get("/register/otto") ~> route ~> check {
+ status === StatusCodes.BadRequest
+ }
+ Get("/register/karl") ~> route ~> check {
+ status === StatusCodes.OK
+ entity === HttpEntity.Empty
+ }
+ }
}
"the redirect directive" should {
@@ -68,4 +103,4 @@ class RouteDirectivesSpec extends RoutingSpec {
}
}
-}
+}
@@ -18,7 +18,7 @@ package spray.routing
package directives
import scala.concurrent.{ ExecutionContext, Future }
-import spray.httpx.marshalling.{ Marshaller, ToResponseMarshaller }
+import spray.httpx.marshalling.{ ToResponseMarshaller, ToResponseMarshallable }
import spray.http._
import StatusCodes._
@@ -46,8 +46,8 @@ trait RouteDirectives {
/**
* Completes the request using the given arguments.
*/
- def complete: ( CompletionMagnet) StandardRoute = magnet new StandardRoute {
- def apply(ctx: RequestContext): Unit = magnet.apply(ctx)
+ def complete: ( ToResponseMarshallable) StandardRoute = marshallable new StandardRoute {
+ def apply(ctx: RequestContext): Unit = ctx.complete(marshallable)
}
/**
@@ -64,35 +64,3 @@ object RouteDirectives extends RouteDirectives {
def apply(ctx: RequestContext): Unit = ctx.reject()
}
}
-
-sealed abstract class CompletionMagnet extends Route
-
-object CompletionMagnet {
- implicit def fromObject[T: ToResponseMarshaller](obj: T): CompletionMagnet =
- new CompletionRoute(obj)
-
- implicit def fromStatusObject[T: Marshaller](tuple: (StatusCode, T)): CompletionMagnet =
- fromStatusHeadersObject((tuple._1, Nil, tuple._2))
-
- implicit def fromStatusHeadersObject[T: Marshaller](tuple: (StatusCode, List[HttpHeader], T)): CompletionMagnet =
- new CompletionRoute(tuple._3)(ToResponseMarshaller.fromMarshaller(tuple._1, tuple._2))
-
- implicit def fromHttpResponse(response: HttpResponse): CompletionMagnet =
- new CompletionMagnet {
- def apply(ctx: RequestContext): Unit = ctx.complete(response)
- }
- implicit def fromStatus(status: StatusCode): CompletionMagnet =
- new CompletionMagnet {
- def apply(ctx: RequestContext): Unit = ctx.complete(status)
- }
- implicit def fromHttpResponseFuture(future: Future[HttpResponse])(implicit ec: ExecutionContext): CompletionMagnet =
- new CompletionMagnet {
- def apply(ctx: RequestContext): Unit = ctx.complete(future)
- }
- implicit def fromStatusCodeFuture(future: Future[StatusCode])(implicit ec: ExecutionContext): CompletionMagnet =
- future.map(status HttpResponse(status, entity = status.defaultMessage))
-
- private class CompletionRoute[T: ToResponseMarshaller](obj: T) extends CompletionMagnet {
- def apply(ctx: RequestContext): Unit = ctx.complete(obj)
- }
-}

0 comments on commit 7a36de5

Please sign in to comment.