Sanity 스키마 타입
Sanity 스키마 타입
Sanity 스튜디오에서 에디터가 어떤 문서와 필드를 작성할 수 있는지, 그 틀을 잡아주는 게 **스키마(schema)**예요. 스키마는 곧 "어떤 타입의 문서와 필드를 담을 수 있는가"를 미리 선언해 두는 것이고, 이 선언이 스튜디오의 입력 화면과 데이터 기록의 모양을 함께 결정해요. 이 글에서는 스키마의 최상위 설정이 어떻게 생겼는지, 기본으로 제공되는 스키마 타입에는 어떤 것들이 있는지, 그리고 실제로 필드를 정의할 때 쓰는 공통 속성들을 하나씩 살펴볼게요.
처음에는 "타입을 하나하나 다 외워야 하나?" 싶을 수 있는데요, 걱정하지 않아도 돼요. 흐름만 이해하면 타입은 카탈로그처럼 필요한 순간에 찾아 쓰면 되거든요. 핵심은 타입이 문서의 구조를 미리 정해 주고, 스튜디오는 그 구조 그대로 편집 화면을 만들어 준다는 연결고리에요. 이 연결고리를 잡으면 스키마가 훨씬 친숙하게 다가와요.
출처: 문서
본문
스키마 설정의 뼈대: templates와 types
최상위 스키마 설정은 두 개의 속성을 받아요. 바로 templates와 types예요.
templates— 초기 값 템플릿(Initial Value Template) 설정 객체의 배열이에요. 문서를 새로 만들 때 미리 채워 넣을 기본 값을 정의해요.types— 스키마 정의 객체의 배열이에요. 문서, 필드에 쓰일 모든 타입을 이 배열로 선언해요.
두 속성 모두 배열 대신 콜백 함수를 넘길 수도 있어요. 콜백은 첫 번째 인자로 현재 값을, 두 번째 인자로 컨텍스트 객체를 받아요. 이 덕분에 플러그인이 제공하는 스키마 정의나 초기 값 템플릿에 접근할 수 있어요.
templates에 대한 자세한 설명은 이 문서에서, 레퍼런스는 초기 값 템플릿 레퍼런스에서 확인할 수 있어요. 이 글의 나머지 부분은 스튜디오가 기본으로 지원하는 스키마 타입 세트를 중심으로 다룰게요.
기본 스키마 타입 종류
기본으로 제공되는 주요 스키마 타입들은 다음과 같아요. 각각이 어떤 용도로 쓰이는지 한 줄씩 정리할게요.
| 타입 | 설명 |
|---|---|
| string | 문자열과 선택 가능한 문자열 목록을 위한 타입이에요. |
| number | 숫자를 표현하는 타입이에요. |
| boolean | 참/거짓 같은 truthy 값을 표현하는 타입이에요. |
| object | 문서 안에서 재사용할 커스텀 타입을 만들 때 쓰는 타입이에요. |
| array | 다른 타입들의 배열을 위한 타입이에요. |
| reference | 다른 문서를 참조하는 타입이에요. |
| document | 문서 자체를 표현하는 타입이에요. |
| block / span | 블록 콘텐츠를 위한 리치 텍스트 에디터를 제공하는 타입과 그 안의 스팬 타입이에요. |
| date / datetime | 날짜와 정확한 시각을 표현하는 타입이에요. |
| file / image | 파일을 올리고, 이미지를 업로드·선택·편집하는 타입이에요. |
| geopoint | 지리적 좌표를 위한 타입이에요. |
| slug | URL에 주로 쓰이는 유니크한 슬러그를 만드는 타입이에요. |
| text | 긴 문자열을 위한 타입이에요. |
| url | URL을 표현하는 타입이에요. |
| cross-dataset references | 데이터셋을 넘나들며 문서를 참조할 때 필요한 타입이에요. |
| global document reference | globalDocumentReference 스키마 타입의 레퍼런스 문서예요. |
각 타입마다 옵션과 사용법이 조금씩 달라서, 세부 내용은 타입별 스키마 레퍼런스 문서를 참고하는 게 좋아요. 전체 목록은 이 문서의 왼쪽 메뉴에서도 확인할 수 있어요.
모든 타입 공통 필드 속성
타입과 무관하게 모든 필드 정의에 공통으로 쓰이는 속성들이 있어요. 먼저 이 공통 속성을 알면 어떤 타입이든 기본기를 갖춘 필드를 만들 수 있어요.
type(required, string) — 유효한 스키마 타입의 이름이에요. 데이터 기록에서 값의 타입이 됩니다.name(required, string) — 필드 이름이에요. 데이터 기록에서 키(key)가 됩니다.title(string) — 필드에 표시될, 사람이 읽을 수 있는 라벨이에요.hidden(boolean 또는() => boolean) — 정적 값 또는 콜백 함수로 필드를 숨길지 결정해요. 조건부로 필드를 보여주고 싶을 때 유용해요.readOnly(boolean 또는() => boolean) —true로 설정하면 콘텐츠 스튜디오에서 편집할 수 없는 필드가 돼요. 콜백 함수를 반환해서 조건부로도 쓸 수 있어요.description(string) — 에디터에게 필드를 어떻게 쓰면 좋을지 설명하는 짧은 문구예요.deprecated(object) — 문서 타입이나 필드를 더 이상 쓰지 않는다고 표시해요. 필드를 읽기 전용으로 렌더링하면서reason속성에 정의한 메시지를 함께 보여줘요. 예:deprecated: { reason: 'no longer used' }GraphQL API 스키마를 배포하면 이 속성이@deprecated지시어로 변환돼요.options(object) — 타입에 따라 달라지는 옵션 모음이에요. 타입별 스키마 레퍼런스에서 사용 가능한 옵션을 확인할 수 있어요.validation(RuleBuilder) — 필드에 하나 이상의 검증 규칙을 추가할 수 있어요. 자세한 건 검증 가이드를 참고해요.
검증(validation)의 기본 메서드
validation으로 자주 쓰는 몇 가지 기본 메서드를 정리할게요.
required()— 필드가 존재해야 한다는 규칙이에요. 예:(Rule) => Rule.required()skip()— 체인에서 그 전에 설정된 검증 규칙을 건너뛰게 하고, 필드를 선택 사항으로 만들어요. 그 뒤에 체이닝된 규칙은 여전히 적용돼요.either([rule, rule, ...])— 규칙 배열을 받아요. 그중 하나라도 truthy면 검증을 통과해요. 예:(rule) => rule.either([rule.required().min(1), rule.custom((_, context) => context.document?.category !== 'bicycle')])all([rule, rule, ...])— 여러 규칙 배열을 받고, 그 모두가 true여야 검증을 통과해요. 예:(rule) => rule.all([rule.required(), rule.custom((value, context) => { ... })])custom(value, context)— 커스텀 검증 규칙을 만들 때 써요. 필드 값과 컨텍스트를 받고, 검증이 통과하면true를, 실패하면 오류 메시지를 반환해야 해요. 예:rule => rule.custom(value => { ... })
위 속성들은 모든 데이터 타입에 공통이에요. 각 타입에 맞는 더 자세한 사용법은 개별 스키마 타입 레퍼런스에서 확인할 수 있어요.
스튜디오와의 관계: 스키마를 스튜디오에 연결하기
스튜디오는 studio.config.js의 schema.types에 선언된 스키마를 모두 불러와요. 아래 예시를 보면 문서 타입 하나를 정의해 types 배열에 넣는 모습을 볼 수 있어요.
//sanity.config.js
import {defineConfig} from 'sanity'
export default defineConfig({
/* ... */
schema: {
types: [
{
title: "My Example Document Type",
name: "exampleDocumentType",
type: "document",
fields: [
{
title: "Greeting",
name: "greeting",
type: "string"
}
]
}
]
}
})
여기서 주의할 점이 하나 있어요. type: "document"가 문서 타입을 선언하는 부분이고, 그 안에 fields로 필드들을 나열해요. 이 문서를 만들면 에디터는 greeting이라는 문자열 필드가 있는 입력 화면을 보고, 데이터에는 greeting 키가 생겨요.
스키마를 파일로 분리해서 관리하기
프로젝트가 커지면 types 배열을 별도 파일로 분리해 두는 게 정리하는 데 도움이 돼요. 이렇게 분리해 두면 스튜디오 설정 파일이 깔끔해져요.
//schemaTypes.js
export const schemaTypes = [
{
title: "My Example Document Type",
name: "exampleDocumentType",
type: "document",
fields: [
{
title: "Greeting",
name: "greeting",
type: "string"
}
]
}
]
//sanity.config.js
import {defineConfig} from 'sanity'
import {schemaTypes} from './schemaTypes'
export default defineConfig({
/* ... */
schema: {
types: schemaTypes
}
})
이렇게 분리하면 sanity.config.js에서는 types: schemaTypes처럼 임포트한 배열을 그대로 넘기기만 하면 돼요.
defineType과 도우미 함수로 타입 정의하기
최신 Sanity 스튜디오는 defineType, defineField, defineArrayMember 같은 도우미 함수를 함께 써서 타입을 정의해요. 도우미 함수를 쓰면 타입스크립트 타입 추론도 잘 잡혀서, 더 안전하게 스키마를 짤 수 있어요. 아래 예시는 문자열 배열을 필드로 가진 문서 타입이에요.
import {defineType, defineField, defineArrayMember} from 'sanity'
export const someDocumentType = defineType({
title: "Some Document Type",
name: "exampleDocumentType",
type: "document",
fields: [
defineField({
title: "String array",
name: "strings",
type: "array",
of: [
defineArrayMember({ type: "string" })
]
})
]
})
type: "array" 필드가 어떤 요소를 담을지는 of 배열로 정해요. 여기서는 defineArrayMember({ type: "string" })로 "문자열만 담는 배열"임을 선언했어요.
플러그인이 제공하는 타입
스키마 타입은 플러그인도 제공할 수 있어요. 스튜디오에서 커스텀으로 정의한 타입과 똑같이 사용할 수 있거든요. 플러그인으로 코드를 조직화하면 스튜디오 코드베이스가 커질수록 관리하기 편해져요. 공식 @sanity/presets 패키지(현재는 실험 단계)가 그 예시인데, 페이지·링크·이미지·SEO 메타데이터·리치 텍스트를 위한 스키마 타입을 미리 만들어 제공해요.
// pluginWithSchema.js
import {definePlugin, defineType, defineField} from 'sanity'
export const pluginWithSchema = definePlugin({
name: 'plugin-with-schema',
schema: {
types: [
defineType({
title: "Plugin object",
name: "exampleObject",
type: "document",
fields: [
defineField({
title: "Title",
name: "title",
type: "string"
})
]
})
]
}
})
//sanity.config.js
import {defineConfig} from 'sanity'
import {pluginWithSchema} from './pluginWithSchema'
export default defineConfig({
/* ... */
plugins: [pluginWithSchema()]
})
플러그인은 definePlugin의 schema.types로 타입을 선언하고, 스튜디오 설정의 plugins 배열에 그 플러그인을 넣으면 돼요. 이렇게 하면 플러그인이 제공하는 타입이 스튜디오에서 바로 사용 가능해져요.