API for looking up Japanese postal code Most of my experience is in Python, Java and embedded C, and I need to learn Scala and Play for a new job. As an exercise, I decided to create a very simple API for looking up area by postal code, backed by Redis. It's just a single controller with a couple of routes.

I'm hoping for feedback from experienced Scala or Play users. Please suggest any improvements to make the code more readable, maintainable, idiomatic, performant, secure etc. As a starting point, I enabled several static analysis tools in my build and fixed the issues reported.

controllers/JPI.scala

package controllers

// Scala imports
import util.control.Breaks._

// Play imports
import play.api.mvc._
import play.api.Play.current
import play.api.cache.Cache
import play.api.libs.json._
import com.typesafe.plugin.RedisPlugin

// Java imports
import java.io.{BufferedReader, InputStreamReader}
import java.net.URL
import java.util.zip.ZipInputStream



object JPI extends Controller {

  final val JapaneseURI = "http://www.post.japanpost.jp/zipcode/dl/kogaki/zip/ken_all.zip"
  final val TestURI = "http://localhost:9000/assets/ken_all.zip"
  final val CSVEncoding = "SJIS"

  final val PostalCodeMin = 0
  final val PostalCodeMax = 9999999
  final val PostalCodeFmt = "%07d"

  final val CSVFields = List(
    ("prefecture_kana", 3),
    ("municipality_kana", 4),
    ("neighbourhood_kana", 5),
    ("prefecture_kanji", 6),
    ("municipality_kanji", 7),
    ("neighbourhood_kanji", 8)
  )

  /**
   Lookup a numeric postal code in the Redis cache
  */
  def lookup(postalCode: Integer) = Action {
    if (postalCode &lt; PostalCodeMin || postalCode &gt; PostalCodeMax) {
      NotFound(
        "Postal code outside valid range (%s to %s)".format(
          fmt(PostalCodeMin), fmt(PostalCodeMax)
        )
      )
    } else {
      val json: Option[String] = Cache.getAs[String](postalCode.toString)
      json match {
        case None =&gt; NotFound("Postal code not found")
        case Some(j) =&gt; Ok(j).as("application/json; charset=utf-8")
      }
    }
  }

  /**
    Imports postal codes from a zipped CSV reference as follows:
    - Download the complete code directory from the specified URL
    - Unzips the first file and parses the CSV rows
    - Serializes CSV rows into JSON
    - Inserts JSON objects into Redis hash
   */
  def buildCache() = Action {
    val inStream = new ZipInputStream(new URL(TestURI).openStream)
    val csvFile = Option(inStream.getNextEntry)
    csvFile match {
      case Some(f) =&gt; {
        val reader = new BufferedReader(new InputStreamReader(inStream, CSVEncoding))
        for (line &lt;- Iterator.continually(Option(reader.readLine)).takeWhile(!_.isEmpty)) {
          breakable {
            val elements = line.getOrElse(break).split(",")
            val code = stripQuotes(elements(2))
            Cache.set(code, Json.stringify(parseCSVRow(elements)))
          }
        }
        Ok("Cache rebuilt")
      }
      case None =&gt; InternalServerError("Cache rebuild failed")
    }
  }

  /**
    Format a numeric postal code as a String
  */
  private def fmt(postalCode: Integer) : String = {
    PostalCodeFmt.format(postalCode)
  }

  /**
    Strip trailing and leading quotes from a String
  */
  private def stripQuotes(s : String) : String = {
    s.stripPrefix("\"").stripSuffix("\"")
  }

  /**
    Parse and convert a CSV row into a JSON object according to mapping in CSVFields
  */
  private def parseCSVRow(row : Array[String]) : JsObject = {
    val strippedRow = row map { stripQuotes(_) }
    val fields = CSVFields map {
      f =&gt; f._1 -&gt; Json.toJsFieldJsValueWrapper(strippedRow(f._2))
    }
    Json.obj( fields: _* )
  }

}


Building and running this code is as simple as:

git clone https://github.com/bsutherland/jpi.git
cd jpi
sbt compile
sbt run
I'm skeptical of accepting postal codes as Integers.  Japanese postal codes are of the format NNN-NNNN.  Accepting a String, which may contain an optional hyphen and leading zeros, would be more appropriate.

Furthermore, an API that is designed to take an integer could never be extended to countries like the UK and Canada, where postal codes are alphanumeric.  It would also be problematic for US ZIP+4 codes, which, despite being mostly numeric like Japanese codes, may overflow an Integer.  (It's odd that you take an Integer instead of an Int, but that's a moot point.)