Как создать схему graphql, которую можно будет искать в разных полях?

Я тестирую sangria для создания сервера graphql / relay. У меня очень простой класс User:

case class User(
  id: Int,
  username: String,
  gender: Gender.Value)

Я хочу разрешить запросы по идентификатору или имени пользователя. Я создал схему, которая позволяет это, но поля имеют разные имена:

val Query = ObjectType(
  "Query", fields[UserRepo, Unit](
    Field("user", OptionType(User),
      arguments = ID :: Nil,
      resolve = ctx => ctx.ctx.getUser(ctx arg ID)),
    Field("userByUsername", OptionType(User),
      arguments = Username :: Nil,
      resolve = ctx => ctx.ctx.getUserByUsername(ctx arg Username))
  ))

К сожалению, мне нужно запросить их с разными именами полей, user и userByUsername, например:

curl -G localhost:8080/graphql     
  --data-urlencode 'query={userByUsername(username: "Leia Skywalker") {id, username, gender}}'

or

curl -G localhost:8080/graph    
  --data-urlencode "query={user(id: 1025) {id, username, gender}}"

Как я могу создать схему, которая позволяет запрашивать одно поле с именем user по идентификатору или имени пользователя? Например. оба следующих элемента должны возвращать один и тот же объект пользователя:

curl -G localhost:8080/graphql     
  --data-urlencode 'query={user(username: "Leia Skywalker") {id, username, gender}}'

or

curl -G localhost:8080/graph    
  --data-urlencode "query={user(id: 1025) {id, username, gender}}"

person jbrown    schedule 23.08.2015    source источник


Ответы (1)


Наконец-то я разобрался:

val ID = Argument("id", OptionInputType(IntType), description = "id of the user")
val Username = Argument("username", OptionInputType(StringType), description = "username of the user")

val Query = ObjectType(
  "Query", fields[UserRepo, Unit](
    Field("user", OptionType(User),
      arguments = List(ID, Username),
      resolve = ctx => ctx.ctx.getUser(ctx.argOpt(ID), ctx.argOpt(Username)))
  ))

И getUser выглядит так:

def getUser(id: Option[Int], username: Option[String]): Option[User] = {

  if (id.isEmpty && username.isEmpty) {
    None
  }
  else {
    id.flatMap(i => users.find(_.id == i))
      .orElse(username.flatMap(u => users.find(_.username == u)))
  }
}
person jbrown    schedule 23.08.2015
comment
Стоит отметить, что прямо сейчас реле выйдет из строя с ошибкой проверки, если ему задана такая схема. См. github.com/facebook/relay/issues/112. - person jbrown; 25.08.2015