Skip to content
KeystoneJS LogoKeystoneJS

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

JS
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.

JS
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:

JS
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.

JS
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().

JS
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(`{ ... }`)
        ...
      }
    },
  },
});

Config

OptionTypeDefaultDescription
resolverFunctionasync (item, args, context, info)
graphQLReturnTypeStringStringA GraphQL Type String
graphQLReturnFragmentString''A GraphQL Fragment String - Used by the Admin UI and required if using a nested graphQLReturnType.
extendGraphQLTypesArray[]An array of custom GraphQL type definitions
argsArray[]An array of { name, type } indicating the supported arguments for the field

On this page

  • Usage
  • Basic
  • Return type
  • Complex return types
  • Field arguments
  • Server-side queries
  • Config
Edit on GitHub