Play Framework: составление нескольких ActionTransformers - могу ли я добавить поля в несколько преобразователей и получить доступ ко всем из них в invokeBlock? - PullRequest
0 голосов
/ 03 апреля 2020

Используя композицию действий Play, мне интересно, есть ли способ добавить поля в запрос за несколько ActionTransformer с, чтобы я мог получить доступ к обоим полям в запросе.

Простой пример, который не не работает:

import scala.concurrent.{ExecutionContext, Future}
import play.api.mvc.{Action, ActionTransformer, Request, Results, WrappedRequest}

class RequestWithName[A](request: Request[A], val name: String) extends WrappedRequest[A](request)
def addName(implicit ec: ExecutionContext) = new ActionTransformer[Request, RequestWithName] {
  override def executionContext: ExecutionContext = ec
  override def transform[A](request: Request[A]): Future[RequestWithName[A]] = ???
}

class RequestWithUserId[A](request: Request[A], val userId: String) extends WrappedRequest[A](request)
def addUserId(implicit ec: ExecutionContext) = new ActionTransformer[Request, RequestWithUserId] {
  override def executionContext: ExecutionContext = ec
  override def transform[A](request: Request[A]): Future[RequestWithUserId[A]] = ???
}

Action.andThen(addName).andThen(addUserId) { req =>
  Results.Ok(req.name + req.userId) // compile error: name not available
}

Action.andThen(addUserId).andThen(addName) { req =>
  Results.Ok(req.name + req.userId) // compile error: userId not available
}

Имеет смысл, почему происходят эти ошибки компиляции - последний andThen возвращает ActionTransformer, который имеет только одно из двух полей. Но есть ли способ совершить одно и то же, не сообщая им друг о друге? Например. Я мог бы добавить RequestWithUserIdAndName - но тогда я не могу составить это с другими преобразованиями, которые добавляют еще больше полей.

1 Ответ

1 голос
/ 04 апреля 2020

Как насчет написания чего-то вроде EnrichedRequest, у которого есть коллекция обогащений (реализованных в виде некоторой запечатанной иерархии), чтобы вы сначала подняли ее, а затем добавили обогащения по своему усмотрению?

sealed trait Enrichment
case class UserName(name: String) extends Enrichment
case class UserId(name: String) extends Enrichment

class EnrichedRequest[A](
  request: Request[A],
  val enrichments: List[Enrichment]
) extends WrappedRequest[A](request)
def asEnriched(implicit ec: ExecutionContext) = new ActionTransformer[Request, EnrichedRequest] {
  ...
}

def addName(implicit ec: ExecutionContext) = new ActionTransformer[EnrichedRequest, EnrichedRequest] {
  ...
}

def addUserId(implicit ec: ExecutionContext) = new ActionTransformer[EnrichedRequest, EnrichedRequest] {
  ...
}

Action.andThen(asEnriched).andThen(addName).andThen(addUserId) { ... }
Action.andThen(asEnriched).andThen(addUserId).andThen(addName) { ... }

Это было бы легко реализовать и свободно расширять. Единственным недостатком является то, что для извлечения данных вам нужно сделать что-то вроде:

enrichments.collect {
  case UserName(name) => name
}.head

, чтобы извлечь данные обратно.

...