Content modelling

Schema types

Documents, objects and fields, defined with defineType and defineField exactly as in any Sanity project — and validated by the platform where it matters.

Schemas are ordinary Sanity schema definitions. If you have written one before, there is nothing new here — which is the point.

schema/documents/post.tsts
import { defineArrayMember, defineField, defineType } from '@neworange/content-studio'

export const post = defineType({
  name: 'post',
  title: 'Post',
  type: 'document',
  fields: [
    defineField({
      name: 'title',
      type: 'string',
      validation: (Rule) => Rule.required().min(1).max(120),
    }),
    defineField({
      name: 'slug',
      type: 'slug',
      options: { source: 'title', maxLength: 96 },
      validation: (Rule) => Rule.required(),
    }),
    defineField({
      name: 'author',
      type: 'reference',
      to: [{ type: 'author' }],
      validation: (Rule) => Rule.required(),
    }),
    defineField({ name: 'body', type: 'blockContent' }),
  ],
  preview: { select: { title: 'title', subtitle: 'author.name' } },
})

Where validation actually runs

This is the one thing worth internalising, because it is the same in Sanity and it surprises people:

  • Schema validation runs in the Studio. It is advisory. It shapes the editing experience, marks fields, and blocks the publish button.
  • It does not gate the API. A mutation posted straight to /data/mutate with a missing required field will be stored.

What the platform enforces, on every write and publish regardless of who is writing, is a much smaller set: strong references must resolve, published slugs must be unique, and optimistic-concurrency conditions must hold.

Registering types

Every type — documents, objects, array member objects — is registered once in a single array, and the example schema's tests assert that the set is internally consistent: every reference.to target and every custom array member resolves to a name in the same array. A typo in a type name is otherwise the sort of thing that shows up as an empty editor pane weeks later.

Groups, orderings and previews

All supported, and all worth using:

  • groups splits a long document form into tabs.
  • orderings gives a document list a sort that means something (an order field, rather than the title).
  • preview.select decides what a document looks like in a list — including media, which is what makes a picture-heavy list usable.