4
\$\begingroup\$

I have a piece of code that I would like to refactor but can't figure how to do it. This is a method from a Play controller where I have to verify many precondition and respond different status for each case :

  1. resource should exist or 404
  2. revision should match the If-Match value or 412
  3. payload should be valid or 422

The first attempt looks like below. How do you implement such a suite of verifications?

service.find(key).map { resource => 
  request.headers.get("If-Match").map { expected =>
    if ( resource.revision == expected ) {
      val payload = request.body.validate[Model]
      payload match {
        case JsSuccess(model, _) =>
          Ok()
        case JsError(errors) => 
          UnprocessableEntity()
      }
    } else {
      PreconditionFailed()
    }
  }
} getOrElse {
  NotFound()
}

My best attempt is now to have one method who create a triplet of Option[Resource], String, JsResult[Model] and use pattern matching for each case :

 condition match {
   case (None, _, _) =>
     NotFound()
   case (Some(resource), expected, _) if ( resource.revision!=expected ) =>
     PreconditionFailed()
   case (_, _, JsError(errors)) =>
     UnprocessableEntity()
   case (Some(resource), _, JsSuccess(model, _)) =>
     Ok()
 }
\$\endgroup\$
0

1 Answer 1

3
\$\begingroup\$

You should learn more about partial functions. Everything you need to know is written in the documentation.

It is a structure that allows you to do a basic check on something and if it succeed, it does something. It is composed of two methods :

  • apply(v1: A): B
  • isDefinedAt(x: A): Boolean

It applies the apply method on your input parameter only if the isDefinedAt method returned true when called with your input parameter.

The great thing about partial functions is that you can chain them easily with the andThen, compose and applyOrElse operators. Also, they can be written very easily by using the case syntax :

val divideByTwo: PartialFunction[Int, Int] = { case d: Int if d%2 == 0 => d/2 }

But there is another way to write it :

val divideByTwo = new PartialFunction[Int, Int] {
  def apply(d: Int) = d / 2
  def isDefinedAt(d: Int) = (d%2 == 0)
}

Here is a great article about it.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.