Reputation: 1371
there is Person
model case class
which is exposed to the client via REST endpoint.
scala> case class Person(firstname: String, lastname: String)
defined class Person
Now one of the internal service wants to "enrich" this Person case class
and add social security number to it. BUT that enrichment is only to populate social security number from one service and pass it along to another one.
Immediate thought is to add ssn
property to Person
as follow - but that's not desired given Person
is exposed to endpoint consumer and SSN MUST NOT be visible to any user calling REST endpoint which exposes Person
data.
case class Person(firstname: String, lastname: String, ssn: String)
So another thought is to enrich Person
case class as follow
scala> implicit class ExtendedPerson(person: Person){
| val SSN : String = ""
| }
defined class ExtendedPerson
then Service1.findPerson
API will have implicit
in the scope and will want to prepare Person
as follow
val person = Person(firstName="Joe",lastname="Doe", ssn ="123-456-0000")
and then
Service2.moreWorkWithPerson(person,other arguments)
then Service2.moreWorkWithPerson
will want to get ssn=123-456-0000
from person
argument.
what's the right way to achieve this in Scala without modifying definition of Person case class
? Can shapeless help? any pointers would be appreciated?
Upvotes: 0
Views: 268
Reputation: 15086
Maybe you should just expose a different class to the client.
case class Person(firstname: String, lastname: String, ssn: String) {
def toClient = ClientPerson(firstname, lastname)
}
case class ClientPerson(firstname: String, lastname: String)
object RESTService {
def getPerson(id: String): ClientPerson = {
val p: Person = DB.getPerson(id)
p.toClient
}
}
Upvotes: 0
Reputation: 357
SSN as val in ExtendedPerson makes not much sense, instead it should be a function which queries your DB using the persons first and lastname. Given the fact that your DB is slow and you might call Person.SSN more than once I would suggest not to use this pattern as it will query your DB everytime you call .SSN. Instead I would write an implicit converter for Person to convert more explicitly.
case class ExtendedPerson(basicInfo: Person,ssn: String)
implicit class PersonHelper(person: Person) extends AnyVal{
def extended = {
val ssn = DB.querySSN(...)
ExtendedPerson(person,ssn)
}
}
val person: ExtendedPerson = Person("John","Doe").extended
//person = ExtendedPerson(Person("John","Doe"),"123-456-0000"")
Note: The code is written out of mind but should be logically correct
Upvotes: 1
Reputation: 40500
It seems that you are overthinking this. What's wrong with this?
case class Person(firstname: String, lastname: String, ssn: Option[String] = None);
Now, in REST handler you do return Person("John", "Doe")
, and in the other service: return Person("John", "Doe", Some("111-11-1111"))
Upvotes: 0