Не указывайте идентификатор миграции GraphQL при создании ресурса с помощью Sangria
Я застрял, пытаясь определить то, что мне кажется очень простой мутацией. Я новичок во всех Scala, GraphQL, Akka HTTP, и не являюсь носителем языка, так что извините, если что-то ниже это чепуха! Извините за длинный пост, я постарался сделать его коротким с минимальными примерами, но я чувствую, что важен полный контекст.
контекст
У меня есть следующий код, который определяет Transaction
case-класс, поддельная БД для всех транзакций и схема для запроса и создания транзакций:
case class Transaction(id: Int, description: String, amount: BigDecimal)
object TransactionDB {
var transactions: List[Transaction] = Nil
}
class TransactionDB {
def transaction(id: Int): Option[Transaction] =
TransactionDB.transactions.find(_.id == id)
def createTransaction(transaction: Transaction) = {
TransactionDB.transactions = transaction :: TransactionDB.transactions
transaction
}
}
import sangria.macros.derive._
import sangria.marshalling.sprayJson._
import sangria.schema._
import spray.json._
import DefaultJsonProtocol._
object TransactionSchema {
val Id = Argument("id", IntType)
val TransactionType = deriveObjectType[Unit, Transaction]()
val QueryType = ObjectType("Query", fields[TransactionDB, Unit](
Field("transaction", OptionType(TransactionType),
arguments = Id :: Nil,
resolve = c ⇒ c.ctx.transaction(c.arg(Id))
)
))
implicit val transactionFormat = jsonFormat3(Transaction)
val TransactionInputType = deriveInputObjectType[Transaction](
InputObjectTypeName("TransactionInput")
)
val TransactionArg = Argument("transaction", TransactionInputType)
val MutationType = ObjectType("Mutation", fields[TransactionDB, Unit](
Field("createTransaction", TransactionType,
arguments = TransactionArg :: Nil,
resolve = c ⇒ c.ctx.createTransaction(c.arg(TransactionArg))
)
))
val schema = Schema(QueryType, Some(MutationType))
}
Результирующая схема GraphQL выглядит следующим образом:
type Mutation {
createTransaction(transaction: TransactionInput!): Transaction!
}
type Query {
transaction(id: Int!): Transaction
}
type Transaction {
id: Int!
description: String!
amount: BigDecimal!
}
input TransactionInput {
id: Int!
description: String!
amount: BigDecimal!
}
Затем я могу создать транзакцию и запросить ее с помощью следующих запросов:
mutation {
createTransaction(transaction: {
id: 1
description: "Electricity bill"
amount: 100
}) {
id
}
}
query {
transaction(id: 1) {
id
description
amount
}
}
проблема
Тем не мение, id
не должно быть частью мутации. В идеале я бы получил:
input TransactionInput {
description: String!
amount: BigDecimal!
}
type Mutation {
createTransaction(input: TransactionInput): Transaction
updateTransaction(id: Int!, input: TransactionInput): Transaction # For later
}
в graphql-js
документация, это делается с использованием чего-то вроде:
createTransaction({description, amount}) {
const id = generateId();
transactionRepo[id] = new Transaction(id, description, amount);
return transaction[id];
},
updateTransaction(id, {description, amount}) { // Assuming id exists
transactionRepo[id] = new Transaction(id, description, amount);
return transactionRepo[id];
},
Я нашел решение этой проблемы в Скала / Сангрия.
Попытки решения
Попытка 1: я думал о чем-то вроде этого:
def createTransaction(description: String, amount: BigDecimal) = {
val r = scala.util.Random // Or leave this to the DB layer
val transaction = Transaction(r.nextInt(10000), description, amount)
TransactionDB.transactions = transaction :: TransactionDB.transactions
transaction
}
Но это не будет работать как createTransaction
дается TransactionArg
который отображается на Transaction
,
Попытка 2: я также пытался переключиться на jsonFormat2
из-за удаленного id
, но это вызывает type mismatch
во время компиляции, потому что Transaction
имеет 3 атрибута.
Попытка 3: я попытался обновить производную InputObjectType
исключить id
с помощью:
val TransactionInputType = deriveInputObjectType[Transaction](
InputObjectTypeName("TransactionInput"),
ExcludeInputFields("id")
)
Это компилируется, но при попытке запустить указанную выше мутацию приводит к:
Argument 'transaction' has invalid value: Object is missing required member 'id'
при опусканииid
отcreateTransaction(transaction: {...})
поле.Argument 'transaction' expected type 'TransactionInput!' but got: {id: 42, description: \"Electricity bill\", amount: 100}. Reason: Unknown field 'id' is not defined in the input type 'TransactionInput'.
при добавлении обратно.
Что мне не хватает? Кажется, просто graphql-js
для меня, но я не могу найти, как это сделать в Scala, используя Сангрию. Я много раз читал документы и много смотрел в Google, потому что это казалось простой проблемой, но ничего подобного не нашел. Спасибо!
1 ответ
Похоже оба createTransaction
а также updateTransaction
вернуть тип Transaction
определяется как:
type Transaction {
id: Int!
description: String!
amount: BigDecimal!
}
id: Int!
говорится, что id
требуется (вот что !
значит) поэтому я начну с переопределения его как: id: Int
(без восклицательного знака).