app/controllers/PreferencesProxy.scala (53 lines of code) (raw):

package controllers import com.gu.pandomainauth.PanDomainAuthSettingsRefresher import com.gu.permissions.PermissionsProvider import com.gu.workflow.util.{Code, Dev} import config.Config import play.api.Logging import play.api.libs.ws.{EmptyBody, InMemoryBody, WSClient} import play.api.mvc.{BaseController, ControllerComponents} import scala.concurrent.ExecutionContext.Implicits.global /* Proxy for editorial-preferences, to help with latency since workflow-frontend sits behind CloudFront*/ class PreferencesProxy( override val config: Config, override val controllerComponents: ControllerComponents, override val wsClient: WSClient, override val panDomainSettings: PanDomainAuthSettingsRefresher, override val permissions: PermissionsProvider, ) extends BaseController with PanDomainAuthActions with Logging { private def proxyRequest(relativePath: String) = APIAuthAction(parse.byteString).async { request => val url = s"${config.preferencesUrl}/$relativePath" val requestHeaders = request.headers.toSimpleMap + ( "Host" -> config.preferencesHost ) val requestBody = if (request.hasBody) { InMemoryBody(request.body) } else { EmptyBody } wsClient.url(url) .withHttpHeaders(requestHeaders.toSeq: _*) .withBody(requestBody) .withFollowRedirects(false) // ensure browser handles all redirects NOT this proxy .execute(request.method) .map { response => val responseHeaders = response.headers.view.mapValues(_.head).toMap + ( "Cache-Control" -> "private, no-cache, no-store, must-revalidate, max-age=0", // do not cache whatsoever ) new Status(response.status)(response.bodyAsBytes) .withHeaders(responseHeaders.removed("Content-Type").toSeq: _*) .as(responseHeaders.getOrElse("Content-Type", "application/octet-stream")) } .recover { case _ if config.isDev => TemporaryRedirect( // this ensures PUT doesn't get transformed to GET, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections#temporary_redirections url.replaceAll(Dev.appDomain, Code.appDomain) ) case e => logger.error(s"Error proxying request to $url", e) InternalServerError } } def userPref(userId: String, app: String) = proxyRequest(s"$userId/$app") def setPreference(userId: String, app: String, prefKey: String) = proxyRequest(s"$userId/$app/$prefKey") def getPreference(userId: String, app: String, prefKey: String) = proxyRequest(s"$userId/$prefKey") }