add PlayJsonSupport
diff --git a/build.sbt b/build.sbt
index c4d2c35..1052ac6 100755
--- a/build.sbt
+++ b/build.sbt
@@ -47,7 +47,7 @@
   .enablePlugins(sbtdocker.DockerPlugin, JavaAppPackaging)
 
 lazy val s2http = project
-  .dependsOn(s2core)
+  .dependsOn(s2core, s2graphql)
   .settings(commonSettings: _*)
   .settings(dockerSettings: _*)
   .enablePlugins(sbtdocker.DockerPlugin, JavaAppPackaging)
diff --git a/s2http/src/main/scala/org/apache/s2graph/http/PlayJsonSupport.scala b/s2http/src/main/scala/org/apache/s2graph/http/PlayJsonSupport.scala
new file mode 100644
index 0000000..8b4e91c
--- /dev/null
+++ b/s2http/src/main/scala/org/apache/s2graph/http/PlayJsonSupport.scala
@@ -0,0 +1,34 @@
+package org.apache.s2graph.http
+
+import java.nio.charset.Charset
+
+import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller}
+import akka.http.scaladsl.model._
+import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
+import akka.util.ByteString
+import play.api.libs.json.{JsValue, Json}
+
+trait PlayJsonSupport {
+
+  val mediaTypes: Seq[MediaType.WithFixedCharset] =
+    Seq(MediaType.applicationWithFixedCharset("json", HttpCharsets.`UTF-8`, "js"))
+
+  val unmarshallerContentTypes: Seq[ContentTypeRange] = mediaTypes.map(ContentTypeRange.apply)
+
+  implicit val playJsonMarshaller: ToEntityMarshaller[JsValue] = {
+    Marshaller.oneOf(mediaTypes: _*) { mediaType =>
+      Marshaller.withFixedContentType(ContentType(mediaType)) {
+        json => HttpEntity(mediaType, json.toString)
+      }
+    }
+  }
+
+  implicit val playJsonUnmarshaller: FromEntityUnmarshaller[JsValue] = {
+    Unmarshaller.byteStringUnmarshaller
+      .forContentTypes(unmarshallerContentTypes: _*)
+      .map {
+        case ByteString.empty => throw Unmarshaller.NoContentException
+        case data => Json.parse(data.decodeString(Charset.forName("UTF-8")))
+      }
+  }
+}
diff --git a/s2http/src/main/scala/org/apache/s2graph/http/S2GraphAdminRoute.scala b/s2http/src/main/scala/org/apache/s2graph/http/S2GraphAdminRoute.scala
index c2b832e..8efd2ab 100644
--- a/s2http/src/main/scala/org/apache/s2graph/http/S2GraphAdminRoute.scala
+++ b/s2http/src/main/scala/org/apache/s2graph/http/S2GraphAdminRoute.scala
@@ -10,21 +10,20 @@
 import org.slf4j.LoggerFactory
 import play.api.libs.json._
 
-import scala.util.Try
+import scala.util._
 
 object S2GraphAdminRoute {
 
-  import scala.util._
-
   trait AdminMessageFormatter[T] {
     def toJson(msg: T): JsValue
   }
 
   import scala.language.reflectiveCalls
 
-  type ToPlayJson = {def toJson: JsValue}
-
   object AdminMessageFormatter {
+    type ToPlayJson = {
+      def toJson: JsValue
+    }
 
     implicit def toPlayJson[A <: ToPlayJson] = new AdminMessageFormatter[A] {
       def toJson(js: A) = js.toJson
@@ -56,7 +55,7 @@
   }
 }
 
-trait S2GraphAdminRoute {
+trait S2GraphAdminRoute extends PlayJsonSupport {
 
   import S2GraphAdminRoute._
 
@@ -80,8 +79,7 @@
   }
 
   lazy val createService = path("createService") {
-    entity(as[String]) { body =>
-      val params = Json.parse(body)
+    entity(as[JsValue]) { params =>
 
       val parseTry = Try(requestParser.toServiceElements(params))
       val serviceTry = for {
@@ -94,8 +92,7 @@
   }
 
   lazy val createLabel = path("createLabel") {
-    entity(as[String]) { body =>
-      val params = Json.parse(body)
+    entity(as[JsValue]) { params =>
 
       val labelTry = for {
         label <- requestParser.toLabelElements(params)
diff --git a/s2http/src/main/scala/org/apache/s2graph/http/S2GraphTraversalRoute.scala b/s2http/src/main/scala/org/apache/s2graph/http/S2GraphTraversalRoute.scala
index 1814436..01b7a76 100644
--- a/s2http/src/main/scala/org/apache/s2graph/http/S2GraphTraversalRoute.scala
+++ b/s2http/src/main/scala/org/apache/s2graph/http/S2GraphTraversalRoute.scala
@@ -6,10 +6,10 @@
 import akka.http.scaladsl.server.Route
 import akka.http.scaladsl.server.Directives._
 import akka.http.scaladsl.model.headers.RawHeader
-import akka.http.scaladsl.model.{HttpHeader, StatusCodes}
+import akka.http.scaladsl.model._
 import org.apache.s2graph.core.GraphExceptions.{BadQueryException, JsonParseException}
 import org.apache.s2graph.core.rest.RestHandler
-
+import play.api.libs.json._
 
 object S2GraphTraversalRoute {
 
@@ -20,7 +20,7 @@
   }
 }
 
-trait S2GraphTraversalRoute {
+trait S2GraphTraversalRoute extends PlayJsonSupport {
 
   import S2GraphTraversalRoute._
 
@@ -40,15 +40,13 @@
         val result = restHandler.doPost(request.uri.toRelative.toString(), body, request.headers)
         val responseHeaders = result.headers.toList.map { case (k, v) => RawHeader(k, v) }
 
-        val f = result.body.map(StatusCodes.OK -> _.toString).recover {
-          case BadQueryException(msg, _) => StatusCodes.BadRequest -> msg
-          case JsonParseException(msg) => StatusCodes.BadRequest -> msg
-          case e: Exception => StatusCodes.InternalServerError -> e.toString
+        val f = result.body.map(StatusCodes.OK -> _).recover {
+          case BadQueryException(msg, _) => StatusCodes.BadRequest -> Json.obj("error" -> msg)
+          case JsonParseException(msg) => StatusCodes.BadRequest -> Json.obj("error" -> msg)
+          case e: Exception => StatusCodes.InternalServerError -> Json.obj("error" -> e.toString)
         }
 
-        respondWithHeaders(responseHeaders) {
-          complete(f)
-        }
+        respondWithHeaders(responseHeaders)(complete(f))
       }
     }
   }
@@ -60,6 +58,5 @@
         delegated // getEdges, experiments, etc.
       )
     }
-
 }
 
diff --git a/s2http/src/test/scala/org/apache/s2graph/http/AdminRouteSpec.scala b/s2http/src/test/scala/org/apache/s2graph/http/AdminRouteSpec.scala
index 7e5d794..9239598 100644
--- a/s2http/src/test/scala/org/apache/s2graph/http/AdminRouteSpec.scala
+++ b/s2http/src/test/scala/org/apache/s2graph/http/AdminRouteSpec.scala
@@ -8,19 +8,19 @@
 import org.scalatest.concurrent.ScalaFutures
 import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpec}
 import org.slf4j.LoggerFactory
-import play.api.libs.json.{JsString, Json}
+import play.api.libs.json.{JsString, JsValue, Json}
 
-class AdminRoutesSpec extends WordSpec with Matchers with ScalaFutures with ScalatestRouteTest with S2GraphAdminRoute with BeforeAndAfterAll {
+class AdminRoutesSpec extends WordSpec with Matchers with ScalaFutures with ScalatestRouteTest with S2GraphAdminRoute with BeforeAndAfterAll with PlayJsonSupport {
+
   val config = ConfigFactory.load()
   val s2graph = new S2Graph(config)
+
   override val logger = LoggerFactory.getLogger(this.getClass)
 
   override def afterAll(): Unit = {
     s2graph.shutdown()
   }
 
-  import akka.http.scaladsl.server.Directives._
-
   lazy val routes = adminRoute
 
   "AdminRoute" should {
@@ -30,14 +30,14 @@
         "compressionAlgorithm" -> "gz"
       )
 
-      val serviceEntity = Marshal(serviceParam.toString).to[MessageEntity].futureValue
+      val serviceEntity = Marshal(serviceParam).to[MessageEntity].futureValue
       val request = Post("/createService").withEntity(serviceEntity)
 
       request ~> routes ~> check {
         status should ===(StatusCodes.Created)
         contentType should ===(ContentTypes.`application/json`)
 
-        val response = Json.parse(entityAs[String])
+        val response = entityAs[JsValue]
 
         (response \\ "name").head should ===(JsString("kakaoFavorites"))
         (response \\ "status").head should ===(JsString("ok"))
@@ -51,7 +51,7 @@
         status should ===(StatusCodes.OK)
         contentType should ===(ContentTypes.`application/json`)
 
-        val response = Json.parse(entityAs[String])
+        val response = entityAs[JsValue]
 
         (response \\ "name").head should ===(JsString("kakaoFavorites"))
       }