播放2.0 RESTful请求后处理 [英] Play 2.0 RESTful request post-processing

查看:122
本文介绍了播放2.0 RESTful请求后处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于

In regard to this question I am curious how one can do post-request REST processing a la (crude):

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

全局配置中的

覆盖onRouteRequest 似乎无法提供对主体的访问响应,因此似乎动作组合是拦截响应的方法并执行后处理任务.

overriding onRouteRequest in Global config does not appear to provide access to body of the response, so it would seem that Action composition is the way to go to intercept the response and do post-processing task(s).

问题:这是一个好主意,还是直接在已知要转换类型的控制器(或其他类)方法中直接进行内容类型转换?

Question: is this a good idea, or is it better to do content-type casting directly within a controller (or other class) method where the type to cast is known?

目前,我到处都在做这种事情:

Currently I'm doing this kind of thing everywhere:

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

我希望toJson/toXml转换基于接受标头后请求而发生.

while I'd like the toJson/toXml conversion to happen based on accepts header post-request.

推荐答案

您希望能够根据请求的Accept标头值来计算Result,其中包含类型为A的对象的表示形式.您可以使用以下 type trait

You want to be able to compute a Result containing a representation of an object of a type A according to the request’s Accept header value. You can encode this capability with the following type trait:

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

然后,您可以使用以下帮助程序特征从控制器呈现任何资源:

You could then render any resource from your controller using the following helper trait:

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"))
  }
}

其中Foo是一个简单的案例类,定义如下:

Where Foo is a simple case class defined as follows:

case class Foo(bar: String)

为了能够编译以上代码,您的隐式范围中需要具有类型Repr[Foo]的值.第一种实现可以写成如下:

In order to be able to compile the above code, you need to have a value of type Repr[Foo] in your implicit scope. A first implementation could be written as follows:

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
    }
  }
}

但是对于您要为其编写Repr实例的每种数据类型,render方法将遵循相同的模式:

But for each data type for which you’ll want to write a Repr instance, the render method will follow the same pattern:

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
  }
}

您可能希望减少样板,并通过抽象该模式来避免用户忘记最后一个"case"语句.例如,您可以编写以下帮助程序方法来构建Repr[Something]:

You probably want to reduce the boilerplate and to avoid users to forget the last "case" statement by abstracting over this pattern. You can for example write the following helper method to build a 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
  }
}

因此,您只需要编写以下内容即可获得Repr[Foo]:

Thus you just need to write the following to get a 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))
}

这篇关于播放2.0 RESTful请求后处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆