1
\$\begingroup\$

I'm working on a webapp in ScalaJS and want to create a query url for requesting some JSON.

Right now I'm using a method called urlBuilder to take the query options from an Options case class and return a String that represents a usable query URL. The urlBuilder method, despite my best efforts, has become somewhat ugly.

Am I missing out on any syntactic sugar or language features that could make this a little easier to understand/cleaner looking? Is pattern matching + string interpolation the best strategy here?

case class GameRegions(americas: Boolean, europe: Boolean, asia: Boolean)

case class Options(startRank: Option[Int], endRank: Option[Int], startDate: Option[Date], endDate: Option[Date], startTime: Option[Date], endTime: Option[Date], regions: GameRegions, gameMode: Boolean)

//Builds the URL based on the provided options object
def urlBuilder(baseUrl: String, o: Options): String = {
  baseUrl + "?" + (o.startRank match {
    case Some(x) => s"rank[0]=$x&"
    case None => ""
  }) + (o.endRank match {
    case Some(x) => s"rank[1]=$x&"
    case None => ""
  }) + (o.startDate match {
    case Some(x) => s"added[0]=@${x.getTime / 1000}&"
    case None => ""
  }) + (o.endDate match {
    case Some(x) => s"added[1]=@${x.getTime / 1000}&"
    case None => ""
  }) + (o.startTime match {
    case Some(x) => s"time[0]=@${x.getTime / 1000}&"
    case None => ""
  }) + (o.endTime match {
    case Some(x) => s"time[1]=@${x.getTime / 1000}&"
    case None => ""
  }) + (o.regions match {
    case GameRegions(false, false, false) => ""
    case GameRegions(x, y, z) => {
      var i: Int = -1
      if (x) {
        i = i + 1
        s"region[$i]=Americas&"
      } else {
        ""
      } + (if (y) {
        i = i + 1
        s"region[$i]=Europe&"
      } else {
        ""
      }) + (if (z) {
        i = i + 1
        s"region[$i]=Asia&"
      } else {
        ""
      }) + "&"
    }
  }) + s"format[0]=${if (o.gameMode) "Standard" else "Wild"}"
}
\$\endgroup\$
1
\$\begingroup\$

Sometimes pattern matching over Option could be replaced with fold or map/getOrElse

o.startRank.fold("")(x => s"rank[0]=$x&")

o.startRank.map(x => s"rank[0]=$x&").getOrElse("")

You could notice that url parameters have a pattern key=value joined with &. To leverage this pattern url builder could be split into separate steps:

  • create a map Map[String,String] of parameters i.e.

    Map(
      "rank[0]" -> o.startRank.fold("")(_.toString),      
      ...
      "time[0]" -> o.startTime.map(time => time.getTime/1000).map(_.toString).getOrElse("")
    
  • join parameters into string

    map.filter(_._2.nonEmpty).map { 
      case (key, value) => s"$key=$value" 
    }.mkString("&")
    
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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