0

I am currently Implementing business logic code which is dependent on the custom scala library which has a lot of impure functions and we have a lot of code with is dependent on this library and cannot refactor as it will affect others. So I am trying to write my scala code as pure as possible and need suggestions for few use cases.

I have an LDAP utility library that does the following Authenticate based on username and password and returns Boolean, However, if there is a Connection exception or user not found it directly throws an exception. Reading and updating data based on UUID and parameters like first name and last name does pretty much the same thing My approach for the authentication use case is below

  def authenticateToUpdate(userName:String,password:String):Option[Boolean] =
    Some(ldapService.authenticate(username,password))

// or using either type to get the message as well
  def authenticateToUpdate(userName:String,password:String):Either[String,Boolean]=
    (ldapService.authenticate(username,password)) match {
      case true => Right(true)
      case false => Left("Validation failed, Invalid Password")
      case exception: Exception => Left(exception.toString)
    }

//##for Some type
  authenticateToUpdate(userName,password).fold(InvalidPassword)(updateOrder(orderId,userName))

//##for Either type
// Looking into how to implement

So I want to write my code as functional and close to pure function as possible need help and suggestions on how can I approach such scenario to write functional scala code.

  • The above code sample closely resembles my working code but not the same, please ignore unknow variable names and others. As I want to show my approach and and want to know that I am doing it correct – SlightlyUsual Aug 18 '21 at 09:26
  • 3
    If the library throws exceptions, wrap the calls in a `Try` – Tim Aug 18 '21 at 10:58

2 Answers2

3

As Tim says, when handling errors in Scala the easiest thing to do is to wrap the exception-throwing code in a Try block. For example:

import scala.util.{Try, Success, Failure}

Try {
  connector.makeCall()
} match {
  case Success(value) if value => Right("yay")
  case Success(value)          => Left("â˜šī¸")
  case Failure(ex)             => Left("An exception was thrown")
}

This will return a Right if the connector.makeCall() line returns true or a Left if that line returns false or an exception.

It's a bit of a contrived example but here's one way you'd use this - https://scastie.scala-lang.org/irmbBQ9ISeqgitRubC8q5Q

James Whiteley
  • 3,363
  • 1
  • 19
  • 46
-1

Actually, the provided piece of code cannot be pure because the result of authenticateToUpdate depends not only on its arguments (username, password) but also depends on the ldapService service.

Having said that I'd suggest the following definition for authenticateToUpdate:

def authenticateToUpdate(userName:String, password:String)(ldapService: (String, String) => Boolean): Either[String, String] = {
  Try(ldapService(userName, password)) match {
    case Success(value) if value => Right("OK")
    case Success(_) => Right("Failed to authenticate")
    caseFailure(ex) => Left(s"Something wrong: ${ex}")
  }
}

authenticateToUpdate("user", "password"){ case (user, password) =>
 ldapService.authenticate(username,password)
}

In the provided example we just wrap an impure function with a pure one.

Bondarenko
  • 225
  • 1
  • 7