I have a scenario where I want to verify that every request has a valid header attribute. This attribute is a digital signature which essentially is a hash of the request url and the request body, in this case a form-url-encoded body.
So I did the typical thing and created an action filter as follows:
class SomeActionFilter #Inject()(val executionContext: ExecutionContext) extends ActionFilter[Request] {
override protected def filter[A](request: Request[A]): Future[Option[Result]] = Future.successful {
// here I want to get the request body which I know is a form url encoded request body
val body = request.body //problem here is that body is of type A
}
}
What I really want is to get request.body to be of type Option[Map[String, Seq[String]]] which is what a form url encoded body is. I could do this, ie swap the type parameter A with AnyContent like this and then I can get at a request.body.asFormUrlEncoded
class SomeActionFilter #Inject()(val executionContext: ExecutionContext) extends ActionFilter[Request] {
override protected def filter[AnyContent](request: Request[AnyContent]): Future[Option[Result]] = Future.successful {
encoded request body
val body = request.body.asFormUrlEncoded
}
}
Is that the right thing to do here, to swap the type parameter like this? Or do I check if the body is of type Option[Map[String, Seq[String]]] using asInstanceOf and reject the request if it isn't? I'm a bit lost on how to approach this.
Related
My play application has an endpoint for receiving webhooks from Stripe.
In order to verify the webhooks, the request body needs to be compared against a signature and a signing key. This requires that I have access to the raw request body, as sent.
However, it seems that Play alters the request body, and I can't get access to the raw contents. This causes the computed signature to change, and the verification fails. More info: https://stackoverflow.com/a/43894244/49153
Here's my code:
#Singleton
class WebhookController #Inject()(cc : ControllerComponents,
env: Env)
(implicit ec: ExecutionContext)
extends AbstractController(cc) {
private val log = Logger("WebhookController")
def index(): Action[AnyContent] = Action.async { implicit req =>
val signature =
req.headers.headers.find(_._1 == "Stripe-Signature").map(_._2).getOrElse("").trim
if (verifySignature(req.body.toString, signature, env.webhookSecretKey))
Future.successful(ok("ok"))
else
Future.successful(ok("Couldn't verify signature"))
}
}
Here I'm trying to access the body using req.body.toString but it looks to be the deserialized json rather than the raw body.
Using req.body.asRaw returns a none.
Any ideas?
Solved this by using Action.async(parse.raw) and then doing req.body.asBytes().map(_.utf8String).getOrElse("") to obtain the raw string of the body. Some more info: https://www.playframework.com/documentation/2.7.x/ScalaBodyParsers
I'm developing a scala Web application with play framework, the first time i used filter in order to validate the request but i had no result then i tried to use action builder i had to override 2 methods here is my ActionBuilder Object
object MyJsonAction extends ActionBuilder[Request, Response] with Results {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
println (request.body)// returning null everytime why ?
block(request)
}
override def parser = { // what does this method do, i think the problem started from here :/ ?
null;
}
override protected def executionContext = {
null;
}
}
Well, there are no much resource with play framework just simple examples and there is no example briefly explain what those methods are doing, they tell that you can get request body without telling you how ! everything is ambiguous ! im stuck with it since 3 days a go, and i have no idea what should i do now. thanks
An ActionBuilder is an object that build an Action. An Action combines a BodyParser[T], which reads the request body and constructs a T, with a function Request[T] => Future[Result] to process the T.
The default ActionBuilder does this in a very simple way. It chains together the BodyParser's result and feeds it to the function. If you make a custom ActionBuilder then you can override this process, perhaps by injecting your own logic before or after the function call.
If you're making your own ActionBuilder I'd suggest starting with something like the following as a template:
#Singleton
class MyJsonAction #Inject() (
bodyParsers: PlayBodyParsers,
ec: ExecutionContext) extends ActionBuilder[Request, JsValue] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
println(request.body) // DO SOMETHING HERE
block(request)
}
override def parser = bodyParsers.json
override protected def executionContext = ec
}
Then you can use it in your controllers like this:
class MyController #Inject() (myJsonAction: MyJsonAction) {
def index = myJsonAction { req: Request[JsValue] => ??? }
}
The important piece is the parser: BodyParser[A] it takes the incoming bytes and convert them into a type A.
For instance BodyParser[JsValue] will produce a body of type JsValue. It is used to read Json.
If you are trying to validate an object, maybe an action builder is not the right place to start. You may focus more on the BodyParsers and the json validation
I'm developing a web service using Scala and Play Framework 2.5. My application has typical layered architecture. I have the following classes: model.User, repository.UserRepository, service.UserService and controllers.UserController and I'm trying to a good way to handle buisness logic errors without using Exception.
Consider the following case: a request for registration a new user was received. There are two parameters in the request body: email and password. These parameters are fed to UserService#registerUser which checks if the email is valid and if user with such email already exists. My solution is to make UserService#registerUser return as a result an Either[BuisnessFailure, Int] object. BuisnessFailure is a trait and is inherited by WrongEmailFormatFailure and UserAlreadyExistFailure.
If the email is not valid, UserService#registerUser returns Left(WrongEmailFormatFailure). If a user with such email already exists, UserService#registerUser returns Left(UserAlreadyExistFailure). And in case of success, UserService#registerUser returns Right(userRepository.create(User(email, password)).Afterwards, in controllers.UserController I can handle this case using pattern matching and send an appropriate response.
So, is this approach good enough to handle similar cases? Please, find my code below:
User:
package model
case class User(email: String, password: String)
UserRepository:
package repository
import model.User
class UserRepository {
def create(user: User): Int = ???
def find(email: String): Option[User] = ???
}
UserService:
package service
import model.User
import repository.UserRepository
import util.{BuisnessFailure, UserAlreadyExistFailure, WrongEmailFormatFailure}
class UserService {
private val userRepository: UserRepository = ???
def registerUser(email: String, password: String): Either[BuisnessFailure, Int] = {
if (userAlreadyExists(email))
Left(UserAlreadyExistFailure)
else
if (!isEmailValid(email))
Left(WrongEmailFormatFailure)
else
Right(userRepository.create(User(email, password)))
}
private def isEmailValid(email: String): Boolean = ???
private def userAlreadyExists(email: String): Boolean = ???
}
UserController:
package controller
import service.UserService
import util.{UserAlreadyExistFailure, WrongEmailFormatFailure}
class UserController extends play.api.Controller {
private val userService = new UserService
def signUp() = Action(parse.json) { implicit request =>
//obtaining email and password parameters from request body
val email = ???
val password = ???
userService.registerUser(email, password) match {
case Left(WrongEmailFormatFailure) => // send 400 code and appropriate error message
case Left(UserAlreadyExistFailure) => // send 400 code and appropriate error message
case Right(_) => // send response with 200 code
}
}
}
BuisnessFailure:
package util
sealed trait BuisnessFailure
case object UserAlreadyExistFailure extends BuisnessFailure
case object WrongEmailFormatFailure extends BuisnessFailure
This is exactly what we've done regarding error handling for one of our biggest projects and we didn't have any problem. Either should be used exactly like that. Left for errors and Right for results.
It's typesafe
No need to worry about concurrency
The code is scalable and maintainable
The only point is that, as most of Scala applications are non-block (async) people would use Future[Either[Error, Int]] rather than Either[Error, Int]. But still, it's OK, as whenever you decided to go for non-blocking you can easily wrap Either inside a Future and as I told you, no worries about concurrency issues.
Our Play application uses Slick as a data access layer. This means that in almost every action in our app we need to have both the current Request and Slick's database Session implicitly available on the scope.
I want to write a custom Action to do this so we only need one line to do this. What I want to do is write it in such a way that I can write something like this:
def someAction = DBAction { implicit request, session =>
// body with implicit request and session on scope
But this is not valid syntax. Using a tuple does not work because it cannot implicitly unpack the tuple in action body. Is it possible to create a custom action that passes multiple implicit arguments to the body? How do I do this?
You cannot implicit 2 variables like that.
But your Custom action can return a WrappedRequest (an object which encapsulates the request and your session), and you can define an implicit conversion between this wrapped request and your Session.
Try this example, derived from this class.
sealed case class DBRequest(session: Session, private val request: Request[AnyContent])
extends WrappedRequest(request)
trait DBController extends Controller {
// Implicit conversion from DBRequest to Session
implicit def session(implicit request: DBRequest) = request.session
def DBAction(action: DBRequest => Result) = Action { request =>
database.withSession { session =>
action(DBRequest(session, request))
}
}
}
object MyController extends Controller with DBController {
def myAction = DBAction { implicit request =>
println(session)
}
}
#senia was right, currying needs to be used to do this. This is actually addressed in the Play docs but it's a recent addition I missed.
For future reference for people looking for this, my custom action now looks like this:
def DBAction(action: Request[AnyContent] => Session => Result) = {
Action { request =>
database.withSession { session =>
action(request)(session)
}
}
}
Which I can then use in the following way:
def someAction = DBAction { implicit request => implicit session => /* body */ }
Im using play2 and seem to do the following alot:
def someFunction(request: RequestHeader) = {...}
is there a way to implicitly define the request so that I don't have to always pass it in to various functions that require having the request?
thanks.
You should use implicits, that way you dont have to pass the request explicitly.
def index = Action { implicit req =>
someOtherFunction("hi")
Ok(someFunction)
}
def someFunction(implicit request: RequestHeader) = {...}
def someOtherFunction(otherArgs:String)(implicit req: RequestHeader) = { .. }