Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modeling with Scala case class

I'm attempting to model responses from REST APIs as case classes which I can use pattern matching on.

I thought it would be a good fit assuming inheritance, but I see that this is deprecated. I know there are already questions related to case classes and inheritance, but my question is more about how you would model the following the "right way" here without inheritance.

I started with the following two case classes, which work fine:

case class Body(contentType: String, content: String)
case class Response(statusCode: Int, body: Body)

i.e. a REST call would return with something like:

Response(200, Body("application/json", """{ "foo": "bar" }"""))

which I could pattern match like:

response match {
  case Response(200, Body("application/json", json)) => println(json)
  case Response(200, Body("text/xml", xml)) => println(xml)
  case Response(_,_) => println("Something unexpected")
}

etc. which works fine.

Where I ran into trouble is: I'd like helper extensions for these case classes, such as:

case class OK(body: Body) extends Response(200, body)
case class NotFound() extends Response(404, Body("text/plain", "Not Found"))

case class JSON(json: String) extends Body("application/json", json)
case class XML(xml: String) extends Body("text/xml", xml)

so that I can do simplified pattern matches like this:

response match {
  case OK(JSON(json)) => println(json)
  case OK(XML(xml)) => println(xml)
  case NotFound() => println("Something is not there")

  // And still drop down to this if necessary:
  case Response(302, _) => println("It moved")
}

and also which would also allow my REST code to directly use and return:

Response(code, Body(contentType, content))

which is easier to build a response dynamically.

so...

I can get it to compile (with deprecation warnings) via:

case class OK(override val body: Body) extends Response(200, body)

However, this doesn't seem to work with pattern matching.

Response(200, Body("application/json", "")) match {
  case OK(_) => ":-)"
  case _ => ":-("
}
res0: java.lang.String = :-(

Any ideas on how this could work? I'm open to different approaches, but this was my attempt to find a practical use for case classes

like image 401
7zark7 Avatar asked Jun 25 '12 01:06

7zark7


People also ask

What is the use of case class in Scala?

What is Scala Case Class? A Scala Case Class is like a regular class, except it is good for modeling immutable data. It also serves useful in pattern matching, such a class has a default apply() method which handles object construction. A scala case class also has all vals, which means they are immutable.

Can Scala case class have methods?

Case Classes You can construct them without using new. case classes automatically have equality and nice toString methods based on the constructor arguments. case classes can have methods just like normal classes.

What is the use of case class in spark?

The Scala interface for Spark SQL supports automatically converting an RDD containing case classes to a DataFrame. The case class defines the schema of the table. The names of the arguments to the case class are read using reflection and they become the names of the columns.


2 Answers

There are several reasons why case classes shouldn't be subclassed. In your case, the problem becomes that OK is another type than (a subtype of) Response, therefore the match fails (even if the arguments match, the type doesn't match).

You will want custom extractors, instead. For example:

case class Response(code: Int, body: String)
object OK {
  def apply(body: String) = Response(200, body)
  def unapply(m: Response): Option[String] = m match {
    case Response(200, body) => Some(body)
    case _                   => None
  }
}

def test(m: Response): String = m match {
   case OK(_) => ":-)"
   case _     => ":-("
}

test(Response(300, "Hallo"))  // :-(
test(Response(200, "Welt"))   // :-)
test(OK("Welt"))              // :-)

There are few more examples of custom extractors in this thread.

like image 147
0__ Avatar answered Sep 19 '22 15:09

0__


Have you looked at the scala library unfiltered? http://unfiltered.lessis.me/ It may help you with approaching you problem . HTH

like image 43
AndreasScheinert Avatar answered Sep 19 '22 15:09

AndreasScheinert