我一直试图定义在我看来是一个非常基本的突变。我是 Scala、GraphQL、Akka HTTP 的新手,而且不是母语人士,所以如果下面的任何内容是胡说八道,请原谅我!很抱歉这篇冗长的文章,我确实试图用最少的例子来保持简短,但我觉得完整的上下文很重要。
语境
我有以下代码定义了一个Transaction
案例类、一个用于所有事务的假数据库以及一个用于查询和创建事务的模式:
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];
},
在 Scala / Sangria 中找到解决方案是我遇到的问题。
尝试的解决方案
尝试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
给定的 aTransactionArg
映射到 a Transaction
。
尝试 2:我也尝试切换到,jsonFormat2
因为已删除id
,但这会type mismatch
在编译时触发 a,因为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 中使用 Sangria 做到这一点。我多次阅读文档并在 Google 上广泛查看,因为这似乎是一个简单的问题,但没有找到任何类似的东西。谢谢!