Documentation Index
Fetch the complete documentation index at: https://docs.prism.byescaleira.com/llms.txt
Use this file to discover all available pages before exploring further.
Mutations
Mutations are the write side of your GraphQL API. They follow the same resolver pattern as queries but are conventionally used for operations that modify data.Defining Mutations
Create a mutation type the same way you create a query type:Mutation Type
let mutationType = PrismGraphQLObjectType(
name: "Mutation",
fields: [
"createUser": PrismGraphQLField(
name: "createUser",
type: .object("User"),
args: [
PrismGraphQLArgument(name: "name", type: .nonNull(.string)),
PrismGraphQLArgument(name: "email", type: .nonNull(.string))
],
resolver: { info in
let name = info.arguments["name"] as? String ?? ""
let email = info.arguments["email"] as? String ?? ""
let db = info.context as? PrismDatabase
try await db?.execute(
"INSERT INTO users (name, email) VALUES (?, ?)",
parameters: [.text(name), .text(email)]
)
let id = await db?.lastInsertID ?? 0
return ["id": "\(id)", "name": name, "email": email]
}
)
]
)
let schema = PrismGraphQLSchema(query: queryType, mutation: mutationType)
mutation {
createUser(name: "Alice", email: "alice@example.com") {
id
name
}
}
CRUD Example
Here’s a complete set of mutations for a Post resource:Post CRUD Mutations
let mutations = PrismGraphQLObjectType(
name: "Mutation",
fields: [
// CREATE
"createPost": PrismGraphQLField(
name: "createPost",
type: .object("Post"),
args: [
PrismGraphQLArgument(name: "title", type: .nonNull(.string)),
PrismGraphQLArgument(name: "body", type: .string),
PrismGraphQLArgument(name: "authorId", type: .nonNull(.id))
],
resolver: { info in
let title = info.arguments["title"] as? String ?? ""
let body = info.arguments["body"] as? String ?? ""
let authorId = info.arguments["authorId"] as? String ?? ""
let db = info.context as? PrismDatabase
try await db?.execute(
"INSERT INTO posts (title, body, author_id) VALUES (?, ?, ?)",
parameters: [.text(title), .text(body), .text(authorId)]
)
let id = await db?.lastInsertID ?? 0
return ["id": "\(id)", "title": title, "body": body, "authorId": authorId]
}
),
// UPDATE
"updatePost": PrismGraphQLField(
name: "updatePost",
type: .object("Post"),
args: [
PrismGraphQLArgument(name: "id", type: .nonNull(.id)),
PrismGraphQLArgument(name: "title", type: .string),
PrismGraphQLArgument(name: "body", type: .string)
],
resolver: { info in
let id = info.arguments["id"] as? String ?? ""
let title = info.arguments["title"] as? String
let body = info.arguments["body"] as? String
let db = info.context as? PrismDatabase
if let title {
try await db?.execute(
"UPDATE posts SET title = ? WHERE id = ?",
parameters: [.text(title), .text(id)]
)
}
if let body {
try await db?.execute(
"UPDATE posts SET body = ? WHERE id = ?",
parameters: [.text(body), .text(id)]
)
}
let row = try await db?.queryFirst(
"SELECT * FROM posts WHERE id = ?",
parameters: [.text(id)]
)
return row.map { ["id": $0["id"], "title": $0["title"], "body": $0["body"]] }
}
),
// DELETE
"deletePost": PrismGraphQLField(
name: "deletePost",
type: .boolean,
args: [
PrismGraphQLArgument(name: "id", type: .nonNull(.id))
],
resolver: { info in
let id = info.arguments["id"] as? String ?? ""
let db = info.context as? PrismDatabase
let affected = try await db?.execute(
"DELETE FROM posts WHERE id = ?",
parameters: [.text(id)]
)
return (affected ?? 0) > 0
}
)
]
)
Input Validation
Validate inputs before persisting data:Validation in Resolvers
"createUser": PrismGraphQLField(
name: "createUser",
type: .object("User"),
args: [
PrismGraphQLArgument(name: "name", type: .nonNull(.string)),
PrismGraphQLArgument(name: "email", type: .nonNull(.string)),
PrismGraphQLArgument(name: "age", type: .int)
],
resolver: { info in
let name = info.arguments["name"] as? String ?? ""
let email = info.arguments["email"] as? String ?? ""
let age = info.arguments["age"] as? Int
// Validate
guard name.count >= 2 else {
throw PrismAppError.badRequest("Name must be at least 2 characters")
}
guard email.contains("@") else {
throw PrismAppError.badRequest("Invalid email address")
}
if let age, age < 0 || age > 150 {
throw PrismAppError.badRequest("Age must be between 0 and 150")
}
// Persist...
return ["id": "1", "name": name, "email": email]
}
)
Always validate inputs in mutations. GraphQL type checking only verifies that arguments are the right type — it doesn’t enforce business rules like “email must be unique” or “name must be at least 2 characters.”
Error Handling
Mutations that throw errors return structured error responses:Error Responses
"transfer": PrismGraphQLField(
name: "transfer",
type: .boolean,
args: [
PrismGraphQLArgument(name: "from", type: .nonNull(.id)),
PrismGraphQLArgument(name: "to", type: .nonNull(.id)),
PrismGraphQLArgument(name: "amount", type: .nonNull(.float))
],
resolver: { info in
let amount = info.arguments["amount"] as? Double ?? 0
guard amount > 0 else {
throw PrismAppError.badRequest("Amount must be positive")
}
guard amount <= 10000 else {
throw PrismAppError.badRequest("Amount exceeds transfer limit", code: "TRANSFER_LIMIT")
}
// Process transfer...
return true
}
)
{
"data": { "transfer": null },
"errors": [{ "message": "Amount exceeds transfer limit", "path": ["transfer"] }]
}
What’s Next
Playground
Test your mutations interactively with the built-in playground
Schema
Refine your schema with more types and relationships