Virtual
The Virtual field type allows you to define a read-only field which you define the resolver for.
This can be used to return computed values, values combining multiple fields, or custom formated values.
The resolver function used in the Virtual field type is an apollo server resolver, and supports the same arguments.
Usage
The most basic usage is to provide a resolver function which returns a String value.
The first argument to the resolver function is the list item.
Basic
const { Virtual, Text } = require('@keystonejs/fields');
keystone.createList('Example', {
fields: {
firstName: { type: Text },
lastName: { type: Text },
name: {
type: Virtual,
resolver: item => `${item.firstName} ${item.lastName}`
};
},
},
});
Return type
If the return type is not String then you need to define graphQLReturnType.
const { Virtual } = require('@keystonejs/fields');
keystone.createList('Example', {
fields: {
fortyTwo: {
type: Virtual,
graphQLReturnType: `Int`,
resolver: () => 42,
},
},
});
Complex return types
For more complex types you can define a graphQLReturnFragment as well as extendGraphQLTypes. Resolver functions can be async so you can even fetch data from the file system or an external API:
const { Virtual } = require('@keystonejs/fields');
keystone.createList('Example', {
fields: {
movies: {
type: Virtual,
extendGraphQLTypes: [`type Movie { title: String, rating: Int }`],
graphQLReturnType: `[Movie]`,
graphQLReturnFragment: `{
title
rating
}`,
resolver: async () => {
const response = await fetch('http://example.com/api/movies/');
const data = await response.json();
return data.map(({ title, rating }) => ({ title, rating }));
},
},
},
});
Field arguments
The GraphQL arguments to a Virtual field can be specified using the args option, which takes a list of { name, type } values.
The values for these arguments are made available in the second argument to the resolver function.
const { Virtual, CalendarDay } = require('@keystonejs/fields');
const { format, parseISO } = require('date-fns');
keystone.createList('Example', {
fields: {
date: { type: CalendarDay },
formattedDate: {
type: Virtual,
resolver: (item, { formatAs = 'do MMMM, yyyy' }) =>
item.date && format(parseISO(item.date), formatAs),
args: [{ name: 'formatAs', type: 'String' }],
},
},
});
Server-side queries
The item argument to the resolver function is the raw database representation of the item, so related items will not be directly available on this object.
If you need to access data beyond what lives on the item you can execute a server-side GraphQL query using context.executeGraphQL().
const { Virtual, CalendarDay } = require('@keystonejs/fields');
const { format, parseISO } = require('date-fns');
keystone.createList('Example', {
fields: {
virtual: {
type: Virtual,
resolver: async (item, args, context) => {
const { data, errors } = await context.executeGraphQL({ query: `{ ... }` })
...
}
},
},
});
Config
| Option | Type | Default | Description |
|---|---|---|---|
resolver | Function | async (item, args, context, info) | |
graphQLReturnType | String | String | A GraphQL Type String |
graphQLReturnFragment | String | '' | A GraphQL Fragment String - Used by the Admin UI and required if using a nested graphQLReturnType. |
extendGraphQLTypes | Array | [] | An array of custom GraphQL type definitions |
args | Array | [] | An array of { name, type } indicating the supported arguments for the field |