example camel rest request playframework-2.0 post-processing

camel - Play 2.0 RESTful request post-processing



apache camel rest consumer (3)

Con respecto a esta pregunta, tengo curiosidad de cómo se puede hacer un procesamiento REST a la solicitud (crudo) después de la solicitud:

def postProcessor[T](content: T) = { request match { case Accepts.Json() => asJson(content) case Accepts.Xml() => asXml(content) case _ => content } }

anular onRouteRequest en Global config no parece proporcionar acceso al cuerpo de la respuesta, por lo que parecería que la composición de Acción es la manera de ir para interceptar la respuesta y realizar tarea (s) de post-procesamiento.

Pregunta: ¿es esta una buena idea, o es mejor hacer fundición de contenido directamente dentro de un método de controlador (u otra clase) donde se conoce el tipo de conversión?

Actualmente estoy haciendo este tipo de cosas en todas partes:

toJson( i18n("account not found") ) toJson( Map(''orderNum-> orderNum) )

mientras que me gustaría que la conversión de toJson / toXml suceda en función de la solicitud previa del encabezado.


Una opción podría ser crear una especie de envoltorio para eso.

Debería ser algo como lo siguiente:

//THE WRAPPER that takes the action computation and the formatter def acceptEnabledAction[A]: (RequestHeader => A, (RequestHeader, A) => Result) => Action[AnyContent] = (a, f) => Action { request => f(request, a(request)) } //a sample formatter val encoder = (r, r) => r.accept /*or smthg*/ match { case x if x == "text/json" || x == "application/json" => Ok(toJson(r)) /*dummy to json*/ case x if x == "text/xml" || x == "application/xml" => Ok(toXml(r)) /*dummy to xml*/ case _ => BadRequest("not accepted") } //an action using it def index = acceptEnabledAction[Map[String, Boolean]]( rh => /*the real action content is here*/Map("a" -> true), encoder )


Desea poder calcular un Result contenga una representación de un objeto de un tipo A acuerdo con el valor del encabezado Accept la solicitud. Puede codificar esta capacidad con el siguiente rasgo de tipo :

trait Repr[-A] { def render(a: A, request: RequestHeader): Result }

A continuación, puede representar cualquier recurso de su controlador utilizando el siguiente rasgo de ayuda:

trait ReprSupport { def repr[A](a: A)(implicit request: RequestHeader, repr: Repr[A]) = repr.render(a, request) } object MyApp extends Controller with ReprSupport { def index = Action { implicit request => repr(Foo("bar")) } }

Donde Foo es una clase de caso simple definida de la siguiente manera:

case class Foo(bar: String)

Para poder compilar el código anterior, debe tener un valor de tipo Repr[Foo] en su alcance implícito. Una primera implementación podría escribirse de la siguiente manera:

object Foo extends AcceptExtractors { implicit val fooRepr = new Repr[Foo] { def render(foo: Foo, request: RequestHeader): Result = request match { case Accepts.Html() => Ok(views.html.foo(foo)) // Assumes there is a foo.scala.html template taking just one parameter of type Foo case Accepts.Json() => Ok(Json.obj("bar" -> foo.bar)) case _ => NotAcceptable } } }

Pero para cada tipo de datos para el que desee escribir una instancia de Repr , el método de render seguirá el mismo patrón:

implicit val somethingRepr = new Repr[Something] { def render(value: Something, request: RequestHeader): Result = request match { // <Some interesting code> (e.g. case Accepts.Html() => Ok(views.html.something(value))) case _ => NotAcceptable } }

Probablemente desee reducir el texto repetitivo y evitar que los usuarios olviden la última declaración de "caso" al resumir sobre este patrón. Por ejemplo, puede escribir el siguiente método de ayuda para crear un Repr[Something] :

object Repr { def apply[A](f: PartialFunction[RequestHeader, A => Result]): Repr[A] = new Repr[A] { def render(a: A, request: RequestHeader): Result = if (f.isDefinedAt(request)) f(request)(a) else NotAcceptable } }

Por lo tanto, solo necesita escribir lo siguiente para obtener un Repr[Foo] :

implicit val fooRepr = Repr[Foo] { case Accepts.Html() => foo => Ok(views.html.foo(foo)) case Accepts.Json() => foo => Ok(Json.obj("bar" -> foo.bar)) }


Otra opción es usar el módulo mimerender (divulgación: lo escribí). Usted define el mapeo una vez:

val m = mapping( "text/html" -> { s: String => views.html.index(s) }, "application/xml" -> { s: String => <message>{s}</message> }, "application/json" -> { s: String => toJson(Map("message" -> toJson(s))) }, "text/plain" -> identity[String]_ )

y solo reutilízala en todos tus controladores:

object Application extends Controller { def index = Action { implicit request => m.status(200)("Hello, world!") } }

Nota: es una versión muy temprana y solo se ha probado en Play 2.0.4