blob: bf7c92e8e6205c1157d28108d7bdd64b3893d51b [file] [log] [blame]
package org.apache.s2graph.http
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server._
import org.apache.s2graph.core.S2Graph
import org.apache.s2graph.graphql.GraphQLServer
import org.slf4j.LoggerFactory
import sangria.ast.Document
import sangria.execution.{ErrorWithResolver, QueryAnalysisError}
import sangria.parser.QueryParser
import spray.json.{JsNull, JsObject, JsString, JsValue}
import scala.util.{Failure, Left, Right, Success, Try}
object S2GraphQLRoute {
def parseJson(jsStr: String): Either[Throwable, JsValue] = {
import spray.json._
val parsed = Try(jsStr.parseJson)
parsed match {
case Success(js) => Right(js)
case Failure(e) => Left(e)
}
}
}
trait S2GraphQLRoute extends SprayJsonSupport with SangriaGraphQLSupport {
import S2GraphQLRoute._
import spray.json.DefaultJsonProtocol._
import sangria.marshalling.sprayJson._
val s2graph: S2Graph
val logger = LoggerFactory.getLogger(this.getClass)
lazy val graphQLServer = new GraphQLServer(s2graph)
private val exceptionHandler = ExceptionHandler {
case error: QueryAnalysisError =>
logger.error("Error on execute", error)
complete(StatusCodes.BadRequest -> error.resolveError)
case error: ErrorWithResolver =>
logger.error("Error on execute", error)
complete(StatusCodes.InternalServerError -> error.resolveError)
}
lazy val updateEdgeFetcher = path("updateEdgeFetcher") {
entity(as[spray.json.JsValue]) { body =>
graphQLServer.updateEdgeFetcher(body)(s2graph.ec) match {
case Success(_) => complete(StatusCodes.OK -> JsString("Update fetcher finished"))
case Failure(e) =>
logger.error("Error on execute", e)
complete(StatusCodes.InternalServerError -> spray.json.JsObject("message" -> JsString(e.toString)))
}
}
}
lazy val graphql = parameters('operationName.?, 'variables.?) { (operationNameParam, variablesParam) =>
implicit val ec = s2graph.ec
entity(as[Document]) { document ⇒
variablesParam.map(parseJson) match {
case None ⇒ complete(graphQLServer.executeQuery(document, operationNameParam, JsObject()))
case Some(Right(js)) ⇒ complete(graphQLServer.executeQuery(document, operationNameParam, js.asJsObject))
case Some(Left(e))
logger.error("Error on execute", e)
complete(StatusCodes.BadRequest -> GraphQLServer.formatError(e))
}
} ~ entity(as[spray.json.JsValue]) { body ⇒
val fields = body.asJsObject.fields
val query = fields.get("query").map(js => js.convertTo[String])
val operationName = fields.get("operationName").filterNot(_ == JsNull).map(_.convertTo[String])
val variables = fields.get("variables").filterNot(_ == JsNull)
query.map(QueryParser.parse(_)) match {
case None ⇒ complete(StatusCodes.BadRequest -> GraphQLServer.formatError("No query to execute"))
case Some(Failure(error))
logger.error("Error on execute", error)
complete(StatusCodes.BadRequest -> GraphQLServer.formatError(error))
case Some(Success(document)) => variables match {
case Some(js) ⇒ complete(graphQLServer.executeQuery(document, operationName, js.asJsObject))
case None ⇒ complete(graphQLServer.executeQuery(document, operationName, JsObject()))
}
}
}
}
// expose routes
lazy val graphqlRoute: Route =
get {
getFromResource("assets/graphiql.html")
} ~
post {
handleExceptions(exceptionHandler) {
concat(
updateEdgeFetcher,
graphql
)
}
}
}