Docblock Format
Relay Resolvers allow you to define additional types and fields in your GraphQL schema that are backed by client-side data. To achieve this, the Relay compiler looks for special @RelayResolver
docblocks in your code. These docblocks define the types and fields in your schema and also tell Relay where to find the resolver functions that implement them.
For an overview of Relay Resolvers and how to think about them, see the Relay Resolvers guide. This page documents the different docblock tags that the Relay compiler looks for, and how to use them.
@RelayResolver
tag. Any other docblocks will be ignored.
@RelayResolver TypeName
The @RelayResolver
tag followed by a single name defines a new GraphQL type in your schema. By default it is expected to be followed by an exported function whose name matches the type name. The function should accept an ID as its sole argument and return the JavaScript model/object which is the backing data for the type. See @weak
for an alternative way to define the backing data for a type.
- Docblock
/**
* @RelayResolver User
*/
export function User(id): UserModel {
return UserModel.getById(id);
}
/**
* @RelayResolver
*/
export function User(id): UserModel {
return UserModel.getById(id);
}
See the Defining Types guide for more information.
@RelayResolver TypeName.fieldName: FieldTypeName
If the typename in a @RelayResolver
tag is followed by a dot and then a field definition, it defines a new field on the type. The portion following the .
is expected to follow GraphQL's
schema definition language.
Field definitions are expected to be followed by an exported function whose name matches the field name. The function should accept the model/object returned by the type resolver as its sole argument and return the value of the field.
- Docblock
/**
* @RelayResolver User.name: String
*/
export function name(user: UserModel): string {
return user.name;
}
/**
* @RelayResolver
*/
export function name(user: UserModel): string {
return user.name;
}
See the Defining Fields guide for more information.
@rootFragment
Relay Resolvers may also be used to model data that is derived from other data in the graph. These fields will be automatically recomputed by Relay when the data they depend on changes.
To define a derived field, use the @rootFragment
tag on an existing field
definition, and follow it with the name of a fragment that defines the data that the field depends on. The resolver function for the field will be passed a fragment key which can be used to read the fragment data using readFragment()
.
- Docblock
import {readFragment} from 'relay-runtime';
/**
* @RelayResolver User.fullName: String
* @rootFragment UserFullNameFragment
*/
export function fullName(key: UserFullNameFragment$key): string {
const user = readFragment(
graphql`
fragment UserFullNameFragment on User {
firstName
lastName
}
`,
key,
);
return `${user.firstName} ${user.lastName}`;
}
import {readFragment} from 'relay-runtime';
/**
* @RelayResolver
*/
export function fullName(key: UserFullNameFragment$key): string {
const user = readFragment(
graphql`
fragment UserFullNameFragment on User {
firstName
lastName
}
`,
key,
);
return `${user.firstName} ${user.lastName}`;
}
See Derived Fields for more information.
@live
When modeling client state that can change over time, a resolver function which returns a single value is not sufficient. To accommodate this, Relay Resolvers allow you to define a field that returns a stream of values over time. This is done by adding the @live
tag to a field or type definition.
@live
resolvers must return an object with the shape of a LiveStateValue
to allow Relay to read the current value and subscribe to changes.
- Docblock
import type {LiveState} from 'relay-runtime';
/**
* @RelayResolver Query.counter: Int
* @live
*/
export function counter(): LiveState<number> {
return {
read: () => store.getState().counter,
subscribe: cb => {
return store.subscribe(cb);
},
};
}
import type {LiveState} from 'relay-runtime';
/**
* @RelayResolver
*/
export function counter(): LiveState<number> {
return {
read: () => store.getState().counter,
subscribe: cb => {
return store.subscribe(cb);
},
};
}
See the Live Fields guide for more information.
@weak
By default, Relay Resolvers expect the backing data for a type to be returned by a resolver function. However, in some cases objects of a given type may not have identifiers. In this case, you can use the @RelayResolver TypeName
syntax described above followed by the tag @weak
to define a "weak" type.
Weak type declarations are expected to be followed by an exported type definition whose name matches the type name.
- Docblock
/**
* @RelayResolver ProfilePicture
* @weak
*/
export type ProfilePicture = {
url: string;
width: number;
height: number;
};
/**
* @RelayResolver
*/
export type ProfilePicture = {
url: string;
width: number;
height: number;
};
See the [Weak Types](/docs/next/guides/relay-resolvers/defining-types/#Defining a “weak” type) guide for more information including how to define an edge to a weak type.
@deprecated
Just like the GraphQL schema definition language, Relay Resolvers support the @deprecated
tag to mark a field as deprecated. The tag may be followed by a string which will be used as the deprecation reason. Deprecated fields will
receive special treatment in the editor if you are using the
Relay VSCode extension.
/**
* @RelayResolver User.name: String
* @deprecated Use `fullName` instead.
*/
export function name(user: UserModel): string {
return user.name;
}
See the Deprecated guide for more information.
Descriptions
Any free text in the docblock (text not following a tag) will be used as the description for the type or field. This description will be surfaced in the editor if you are using the Relay VSCode extension.
/**
* @RelayResolver User.name: String
*
* What's in a name? That which we call a rose by any other name would smell
* just as sweet.
*/
export function name(user: UserModel): string {
return user.name;
}
See the Descriptions guide for more information.