The @Mutation
property wrapper lets you use a GraphQL mutation to make changes on the server, and tracks the state of the request in your view.
Unlike queries and fragments, you don't define mutations in the same file as the view that uses them. Mutations are not specific to a particular view, so they are defined in their own files.
// ChangeTodoStatus.swift
import Relay
private let mutation = graphql("""
mutation ChangeTodoStatusMutation($input: ChangeTodoStatusInput!) {
changeTodoStatus(input: $input) {
todo {
id
complete
}
}
}
""")
Once the mutation is defined and the Relay compiler has generated the types for the mutation, you can use @Mutation
to use the mutation from a SwiftUI view.
// ToDoItem.swift
import SwiftUI
import RelaySwiftUI
private let itemFragment = graphql("""
fragment ToDoItem_item on Item {
id
text
complete
}
""")
struct ToDoItem: View {
@Fragment<ToDoItem_item> var item
@Mutation<ChangeTodoStatusMutation> var changeStatus
var body: some View {
if let item = item {
HStack {
Button {
changeStatus.commit(variables: .init(
input: .init(id: item.id, complete: !item.complete)
))
} label: {
Image(systemName: item.complete ? "checkmark.square" : "square")
}
.disabled(changeStatus.isInFlight)
Text("\\(item.text)")
}
}
}
}
Operation
: A type parameter (surrounded in <>) for the type of the mutation to use. This type will be generated by the Relay compiler with a name matching the operation name in the GraphQL mutation. The Relay compiler will enforce that the operation name is <FileName>Mutation
.The @Mutation
property will be a read-only Mutator
structure with the following API:
commit
: A function that will execute the mutation. This function takes a number of different parameters, so its API is described in more detail below.isInFlight: Bool
: Returns true
if any network requests for the mutation are in flight. This can be used to conditionally show progress UI or disable buttons while the mutation is being executed.commit
functionThe commit
function takes several possible parameters, most of them optional:
variables
: The input variables for the mutation. The type for this structure and any fields within are generated by the Relay compiler.optimisticResponse: [String: Any]
: (optional) A response payload for the mutation that will be committed to the local Relay store immediately. For certain kinds of mutations where a successful response is predictable, this can make the app feel more responsive. When the actual response comes back from the server, the optimistic response will be rolled back and the real one will be applied.optimisticUpdater: (RecordSourceSelectorProxy, SelectorData?) -> Void
: (optional) An updater function that updates the Relay store immediately as though the mutation succeeded. This function runs after the optimisticResponse
, if any, has been applied. You can use this to make updates to the store that go beyond updating the fields of existing records (which will already be handled by an optimistic response). In most cases, this can be the same function as updater
.updater: (RecordSourceSelectorProxy, SelectorData?) -> Void
: (optional) An updater function that updates the Relay store once the mutation has succeeded and the response from the server has been committed to the Relay store. You can use this to make updates to the store that go beyond updating the fields of existing records (which will already be handled by Relay).completion: (Result<Operation.Data?, Error>) -> Void
: (optional) A function that will be called once the mutation has completed. You can use this to make imperative actions when the mutation completes or to update state that exists outside of Relay's store and therefore won't be updated automatically.See Updater functions for more information about how to use the optimisticUpdater
and updater
parameters.