Скала, Сангрия и Скалатра

У нас есть приложение Scala, использующее Scalatra ( http://scalatra.org/) в качестве нашей веб-инфраструктуры. Мне интересно, есть ли какие-нибудь хорошие (или просто какие-либо) ресурсы о том, как реализовать конечную точку GraphQL с использованием Sangria ( http://sangria-graphql.org/) и Scalatra?

Я новичок в Scala и был бы признателен за любую помощь, чтобы начать в этом.

1 ответ

Решение

Я не знаю ни одного, но, поскольку Scalatra использует json4s, вы бы использовали маршаллер ssonria json4s.

В противном случае, если Сангрия может быть вам более понятна, вот рабочий лист scala с очень упрощенным примером, основанным на play + sangria - в этом случае вам просто нужно поменять библиотеку json.

БД проверяется (возможно, вы используете Slick?) И http-сервер, но это простой случай замены в определениях функций.

import sangria.ast.Document
import sangria.execution.{ErrorWithResolver, Executor, QueryAnalysisError}
import sangria.macros.derive.{ObjectTypeDescription, ObjectTypeName, deriveObjectType}
import sangria.parser.{QueryParser, SyntaxError}
import sangria.renderer.SchemaRenderer
import sangria.schema.{Argument, Field, IntType, ListType, ObjectType, OptionInputType, Schema, fields}

import scala.concurrent.Await
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

import scala.concurrent.Future
import scala.util.{Failure, Success}

// replace with another json lib
// eg https://github.com/sangria-graphql/sangria-json4s-jackson
import play.api.libs.json._
import sangria.marshalling.playJson._


case class User(name: String, age: Int, phone: Option[String])
class FakeDb {

  class UsersTable {
    def getUsers(limit: Int): List[User] = {
      // this would come from the db
      List(
        User("john smith", 23, None),
        User("Anne Schwazenbach", 45, Some("2134556"))
      )
    }
  }

  val usersRepo = new UsersTable

}

object MySchema {

  val limitArg: Argument[Int] = Argument("first", OptionInputType(IntType),
    description = s"Returns the first n elements from the list.",
    defaultValue = 10)

  implicit val UsersType: ObjectType[FakeDb, User] = {
    deriveObjectType[FakeDb, User](
      ObjectTypeName("Users"),
      ObjectTypeDescription("Users in the system")
    )
  }
  private val Query: ObjectType[FakeDb, Unit] = ObjectType[FakeDb, Unit](
    "Query", fields[FakeDb, Unit](
      Field("users", ListType(UsersType),
        arguments = limitArg :: Nil,
        resolve = c => c.ctx.usersRepo.getUsers(c.arg(limitArg))
      )
    ))
  val theSchema: Schema[FakeDb, Unit] = Schema(Query)
}

object HttpServer {

  def get(): String = {
    // Http GET  
    SchemaRenderer.renderSchema(MySchema.theSchema)
  }

  def post(query: String): Future[JsValue] = {
    // Http POST
    val variables = None
    val operation = None

    QueryParser.parse(query) match {
      case Success(q) => executeQuery(q, variables, operation)
      case Failure(error: SyntaxError) => Future.successful(Json.obj("error" -> error.getMessage))
      case Failure(error: Throwable) => Future.successful(Json.obj("error" -> error.getMessage))
    }
  }

  private def executeQuery(queryAst: Document, vars: Option[JsValue], operation: Option[String]): Future[JsValue] = {
    val schema: Schema[FakeDb, Unit] = MySchema.theSchema
    Executor.execute[FakeDb, Unit, JsValue](schema, queryAst, new FakeDb,
      operationName = operation,
      variables=vars.getOrElse(Json.obj()))
      .map((d: JsValue) => d)
      .recover {
        case error: QueryAnalysisError ⇒ Json.obj("error" -> error.getMessage)
        case error: ErrorWithResolver ⇒ Json.obj("error" -> error.getMessage)
      }
  }
}

HttpServer.get()

val myquery = """
  {
    users {
     name
    }
  }
  """

val res: JsValue = Await.result(HttpServer.post(myquery), 10.seconds)
Другие вопросы по тегам