Scala For Data Science 책에 소개된 json->객체, 객체 ->json 예제로서 내용이 좋아서 조금 수정해봤다.
Repo.scala
package models
case class Repo(
val name: String,
val language: String,
val size: Long
)
Api.scala
package controllers
import models.Repo
import play.api.libs.json._
import play.api.mvc._
class Api extends Controller {
implicit val writeRepos = new Writes[Repo] {
override def writes(repo: Repo) = Json.obj(
"name" -> repo.name,
"language" -> repo.language,
"size" -> repo.size
)
}
val data = List[Repo](
Repo("backend", "scala", 1),
Repo("frontend", "jquery", 2)
)
def repos(username: String) = Action {
val repoArray = Json.toJson(data)
Ok(repoArray)
}
}
conf/routes 파일에 다음을 추가한다.
GET /api/repos/:username controllers.Api.repos(username)
웹 브라우져에서 http://127.0.0.1:9000/api/repos/odersky을 호출한다.
결과
[{"name":"backend","language":"scala","size":1},{"name":"frontend","language":"jquery","size":2}]
Play 프레임워크에서는 Writes[T] 타입 클래스는 단 하나의 메소드를 가진다.
trait Writes[T] {
def writes(obj:T):Json
}
Writes 메소드는 Play 프레임워크에 내장되어 있어서 Writes를 직접 구현하지 않아도 된다.
Writes[Repo] 인스턴스는 Api controller 코드에서 정의해서 Api controller 내부에서 사용할 수 있도록 한다.
Writes[Repo] 타입 클래스는 Repo 인스턴스를 JSON으로 변환하는 방법을 안다. JSON HTTP 응답을 생성하는 방법을 알고 있기 때문에 깔끔한 코드를 짤 수 있다.
자바라면 맵/배열을 이용하거나 custom Serializer 를 사용해야 한다(예, http://www.baeldung.com/jackson-map)
이를 편하게 만들어준다고 할 수 있는 큰 기능인 것 같다.
이제는 json을 객체로 변환하는 코드 테스트이다.
controllers.Api 클래스의 코드를 다음과 같이 변경한다.
package controllers
import models.Repo
import play.api.mvc._
import play.api.libs.ws.WS
import play.api.Play.current
import play.api.libs.json._
import play.api.libs.functional.syntax._
import play.api.libs.concurrent.Execution.Implicits.defaultContext
class Api extends Controller {
// Repo -> json
implicit val writeRepos = new Writes[Repo] {
override def writes(repo: Repo) = Json.obj(
"name" -> repo.name,
"language" -> repo.language,
"size" -> repo.size
)
}
// json -> Repo
implicit val default:Reads[Repo] = (
(JsPath \ "name").read[String] and
(JsPath \ "language").read[String] and
(JsPath \ "size").read[Long]
)(Repo.apply _)
val data = List[Repo](
Repo("backend", "scala", 1),
Repo("frontend", "jquery", 2)
)
def repos(username:String) = Action.async {
val url = s"https://api.github.com/users/$username/repos"
val response = WS.url(url).get()
response.map { r =>
if (r.status == 200) {
val reposOpt = Json.parse(r.body).validate[List[Repo]]
reposOpt match {
case JsSuccess(repos, _) => Ok(Json.toJson(repos))
case _ => InternalServerError
}
}
else {
NotFound
}
}
}
}
https://api.github.com/users/odersky/repos의 코드를 실행해 json 파싱하고 Read[Repo]타입 클래스에 저장하도록 한다.
'scala' 카테고리의 다른 글
[scala] Boolean-ifThenElse (coursera 강의 발췌) (0) | 2017.06.28 |
---|---|
[sbt] sbt 버전 확인하기 (0) | 2017.06.26 |
[spark] spark streaming job 개발시 유익한 싸이트 (0) | 2017.06.07 |
[spark] parquet 사용 예제 (0) | 2017.05.26 |
[spark] zipWithIndex, for-yield 예제 (0) | 2017.05.25 |