GraphQL Magic
Houdini adds a number of runtime definitions to your GraphQL schema in order to support its declarative API.
Fragments
List Operations
A field marked with @list
or by passing a name to @paginate
can use the following fragments in mutations or subscriptions to update the list:
[ListName]_insert
: insert the reference into the list[ListName]_remove
: remove the reference from the list[ListName]_toggle
: if the reference is already in the list, remove it; otherwise, add it to the list
Some things worth mentioning:
- Insert locations for for the
insert
andtoggle
fragments can be specified using theprepend
orappend
directives specified below - Conditions for the operations can be specified with
@when
or@when_not
shown below. - These fragments can be applied to lists and single values.
- Sometimes the runtime needs a little help to hunt down the list you want to mutate. For more information on how to use
@parentID
to help, see below.
For more information on using these fragments, head over to the mutation docs.
Directives
@list(name: String!)
@list
marks a field as the target for list operations. Must be passed a name which defines the fragments that can be used to mutate the list. See the list operations for more information.
@prepend
@prepend
is used in conjunction with the list operation fragments to tell the runtime to add the element at the start of the list. Can be used with both _insert
and _toggle
fragments. If the list is a member of a fragment, don’t forget to specify @parentID
directive.
@append
@append
is used in conjunction with the list operation fragments to tell the runtime to add the element at the end of the list. Can be used with both _insert
and _toggle
fragments. If the list is a member of a fragment, don’t forget to specify @parentID
directive.
@allLists
@allLists
is used in conjunction with the list operation fragments to tell the runtime to that it should apply to all lists. Can be used with _insert
, _toggle
and _remove
fragments. You can’t have parentID
at the same time.
@when
@when
provides a conditional under which the list operation should be executed. It takes arguments that match the arguments of the field tagged with @list
or @paginate
. For more information, check out the mutation docs.
mutation UncompleteItem($id: ID!) {
uncheckItem(item: $id) {
item {
# only remove the item from the list of filtered items
# if we are only showing the completed ones
...All_Items_remove @when(completed: true)
}
}
}
@dedupe(cancelFirst: Boolean)
@dedupe
lets you control wether or not multiple copies of the same operation (query or mutation) are allowed to run at the same time.
If you pass true
for the cancelFirst
argument then the first copy of the operation will be canceled (including any in-flight requests).
If you pass false
(or pass nothing at all) then the second request won’t trigger if there is already one pending.
@when_not
@when
provides a conditional under which the list operation should not be executed. It takes arguments that match the arguments of the field tagged with @list
or @paginate
. For more information, check out the mutation docs
mutation NewItem($input: AddItemInput!) {
addItem(input: $input) {
# only add the item to the list if we can see uncompleted items
...All_Items_insert @when_not(completed: true)
}
}
@cache(policy: CachePolicy, partial: Boolean)
@cache
is used on a query document to customize the cache behavior. This includes informaton like what cache policy should be used by the runtime or if you are okay with partial results from the cache. For a full list of cache policies, check out the caching guide and for more information on partial responses, see the section on partial data.
@paginate(name: String, mode: PaginateMode)
A field marked with @paginate
is updated with calls to the page loaders returned by the pagination function. For more information on pagination check out the guide. If you pass a value for the name
argument, the underlying list can be updated using the operation fragments.
You can overwrite the default pagination behavior on a per-list basis by passing a value to the mode
argument:
Infinite
: new results are added to the existing list.SinglePage
: new results will replace the contents of the existing list.
@blocking
A query marked with @blocking
will always await the fetch.
@blocking_disable
A query marked with @blocking_disable
won’t block while the fetch resolves when navigating on the client. Keep in mind this will prevent throwOnError
from capturing the error.
@loading(count: Int, cascade: Boolean)
Used to define the shape of your loading state. For more information, please visit this guide. Setting cascade
to true
will implicitly add @loading
the entire sub-selection under the marked field.
@required
Customizes the behavior of null values at runtime. When a value is null that’s marked with @required
, the parent object is set to null
instead. For more information, check out this post on the relay blog.
@[TypeName]_delete
@[TypeName]_delete
(ie, something like @User_delete
) is used to delete the user with an id found in the body of a subscription or mutation. Like the operation fragments, this directive can be applied to lists or singular values. For more information see the mutation docs.
mutation DeleteItem($input: DeleteItemInput!) {
deleteItem(input: $input) {
# this will delete the item with the matching id from the cache
# and remove it from all lists
deletedID @Item_delete
}
}
@parentID(value: String!)
@parentID
is used to identify the parent ID for the field marked with @list
or @paginate
when it cannot be inferred. For example, imagine a situation where there are multiple users rendered on a view that shows their top 5 bands. That listing is retrieved with a query containing @list(name: "Favorite_Bands")
:
query MyFriendsBandList {
viewer {
friends {
favoriteBands @list(name: "Favorite_Bands") {
name
}
}
}
}
If you want to add a band to the list of a specific user, you need to pass the id
field of the user found in the friend
list:
mutation FavoriteBand($input: FavoriteBandInput!, $userID: String!) {
setFavorite(input: $input) {
# only add the item to the list if we can see uncompleted items
...Favorite_Bands_insert @parentID(value: $userID)
}
}
Enums
Houdini generates runtime representations of every enum in your schema. When passing enum values as inputs to your requests you can use a raw string value or use a utility object if you prefer:
import { MyEnum } from '$houdini'
const update = graphql(`
mutation Update($input: MyEnum!) {
update(input: $input)
}
`)
function onClick() {
// could use a utility object
update.mutate({ variables: { input: MyEnum.Value1 } })
// or pass a string directly
update.mutate({ variables: { input: 'Value1' } })
}
Enum Value Types
Sometimes you want to define the types for function or component and you need to refer to the list of all values for
a particular enum. To do this, import the $options
variation on your enum:
import type { MyEnum$options } from '$houdini'
function (val: MyEnum$options) {
}