값 표현식 (Value Expressions)

Script에서 값이 필요한 모든 자리(URL, 요청 body, 필드 값, 조건, 필터 값, 대상 id 등)는 아래 세 형태 중 하나입니다. 예외는 둘뿐입니다. RegexpatternCachekey는 리터럴로만 쓰며 그 안의 { /pointer }는 값으로 바뀌지 않습니다. 이 문서는 그 세 형태와, 값이 어디서 오는지(컨텍스트 루트), 그리고 WEEGLOO 데이터 특유의 로케일 맵 규칙을 설명합니다. Statement 카탈로그의 모든 필드가 이 규칙을 따릅니다.

세 가지 형태

형태규칙
참조 (reference)문자열 안의 { /json-pointer }를 컨텍스트에서 resolve합니다."{ /payload/fields/title }"
리터럴 (literal){ /ptr }가 없는 값(문자열, 숫자, 불리언, 객체, 배열)입니다. 그대로 사용합니다."draft", 42, true, { "a": 1 }
연산과 조건 (JsonLogic)연산자 하나를 키로 갖는 객체입니다. 피연산자는 다시 값 표현식(참조, 리터럴, 중첩)입니다. 자리에 따라 연산자에 $가 필요합니다.{ "$+": [ "{ /vars/n }", 1 ] }

세 형태는 중첩됩니다. JsonLogic 피연산자에 참조를, 참조 결과를 다시 연산에 넣는 식으로 조합합니다.

데이터 자리와 식 자리: $를 언제 붙이나

같은 JSON이 자리에 따라 다르게 읽힙니다. 갈리는 기준은 그 자리의 키를 누가 소유하는가입니다. fields의 키는 Content Type의 필드 id이고 Http.body의 키는 상대 API의 스키마이므로, 그런 자리에서 cat이나 in은 연산자가 아니라 필드 이름이어야 합니다.

자리해당 필드읽는 방식
데이터 자리fields(ResourceCreate, ResourceUpdate, ResourcePatch), Http.body, Return.value, SetVar.value, Cache.value, Cache.defaultValue$가 없는 키는 언제나 필드 이름입니다. 연산을 쓰려면 $를 붙입니다.
식 자리If.condition, Loop.while, version값 전체가 식입니다. 연산자는 cat$cat도 됩니다.
템플릿 자리그 밖의 전부(url, method, headers[].value, locale, order, over, target.sys.id, EmailSend의 필드들, Signature·Hash·Regex의 값 필드)문자열이므로 { /pointer }만 들어갑니다.
리터럴 전용Regex.pattern, Cache.key값 표현식이 아닙니다. Regex.pattern에 적은 { /pointer }는 치환되지 않고 패턴의 일부가 됩니다.

규칙은 두 줄입니다.

  1. 데이터 자리에서 $가 없는 키는 언제나 필드 이름입니다. 연산을 쓰려면 연산자에 $를 붙입니다.
  2. 한번 $로 식에 들어가면 그 안쪽은 전부 식입니다. 중첩된 연산자에는 $가 필요 없습니다(붙여도 됩니다).

헷갈리면 모든 연산자에 $를 붙이세요. 어느 자리에서나 옳습니다.

// 데이터 자리: cat 은 Content Type 의 필드 이름입니다 (연결 연산이 아닙니다)
"fields": { "cat": { "en-US": "hello" } }
 
// 데이터 자리에서 계산: 경계에만 $, 그 안쪽은 그대로
"fields": { "tier": { "en-US": { "$if": [ { ">=": [ "{ /p/score }", 700 ] }, "gold", "silver" ] } } }
 
// 식 자리: 그대로 씁니다
"condition": { "and": [ { "<": [ "{ /a/body/risk }", 0.5 ] }, { ">=": [ "{ /b/body/score }", 700 ] } ] }

$로 시작하는 필드 이름이 필요할 때: $$

JSON Schema의 $ref, $schema처럼 키가 실제로 $로 시작해야 하면 $를 두 번 씁니다. "$$ref"는 데이터 키 $ref를 뜻합니다. 맨 앞의 $ 하나만 벗겨지고($$$ref$$ref), 키에만 적용됩니다(값 안의 $는 그대로입니다).

"body": { "$$ref": "#/components/schemas/Item", "topK": { "$min": [ "{ /payload/fields/k }", 50 ] } }

거부되는 두 가지

아래 두 경우는 조용히 다른 뜻으로 해석되지 않고 오류로 거부됩니다.

  • $ 키가 같은 객체의 다른 키와 함께 있으면 오류입니다. 연산은 그 객체의 유일한 키여야 하며, 형제 데이터는 한 단계 밖으로 빼면 됩니다.
  • 모르는 $는 오류입니다. $catt$catt라는 필드가 아닙니다. $ 네임스페이스는 연산자용으로 예약되어 있습니다.

식 자리에서는 연산자 이름이 형제 키와 함께 있는 것도 오류입니다({ "and": […], "or": […] }). 그 자리에는 데이터라는 해석이 없고 모든 객체는 참으로 판정되므로, 그대로 두면 조건이 조용히 항상 참이 됩니다.

참조: { /json-pointer }

중괄호 안에 RFC 6901 JSON Pointer(반드시 /로 시작)를 넣습니다. 중괄호 주변 공백은 허용됩니다({ /a/b }{/a/b}와 같습니다).

단일 포인터와 혼합 템플릿: 타입 규칙

  • 문자열 전체가 단일 포인터면 그 값의 원래 타입을 그대로 유지합니다(숫자면 숫자, 객체면 객체, 배열이면 배열).
  • 리터럴 텍스트와 섞이면 문자열로 연결(concatenation) 됩니다.
"{ /payload/fields/count }"                 // 숫자 값이면 숫자 그대로 (예: 42)
"{ /payload/fields/tags }"                  // 배열이면 배열 그대로
"page-{ /payload/fields/n }-of-10"          // 문자열 연결 → "page-42-of-10"
"Bearer { /payload/fields/token }"          // 문자열 연결 → "Bearer abc123"

없는 값

  • 경로가 없거나 값이 비면 단일 포인터는 null, 혼합 템플릿은 빈 문자열로 처리됩니다.

컨텍스트 루트: 값은 어디서 오나

{ /pointer }의 최상위 세그먼트는 아래 일곱 중 하나입니다.

루트내용
/payload호출 시 전달된 JSON payload(입력)입니다. 예: { /payload/fields/email }
/rawPayload같은 입력을 호출자가 보낸 본문 문자열 그대로 담습니다(파싱 전). 예: { /rawPayload }
/headers호출 시 전달된 요청 HTTP 헤더입니다. 키는 소문자이고 이름당 단일 값입니다. 예: { /headers/authorization }
/now실행이 시작된 시각입니다. { /now/seconds }·{ /now/millis }·{ /now/iso }
/<name>name이 붙은 앞선 statement의 결과입니다. 예: { /order/sys/id }
/vars/<name>SetVar로 선언한 script-scoped 가변 변수입니다. 예: { /vars/total }
/errorTrycatch 블록 안에서만 씁니다. 잡힌 에러 { message }입니다. 예: { /error/message }

/<name>을 뺀 여섯 이름(payload·rawPayload·headers·now·vars·error)은 예약되어 있어 statement의 name으로 쓸 수 없습니다. 같은 이름을 쓰면 그 루트를 덮어써 버리므로 저장 시점에 거부됩니다(공통 필드의 바인딩 이름 규칙).

/rawPayload: 보낸 그대로의 본문

/payload는 파싱된 값이고, /rawPayload같은 본문의 원문 문자열입니다. 둘은 같은 것을 가리키지만 같지 않습니다. 파싱된 값을 다시 문자열로 만들면 공백, 숫자 표기, 이스케이프, 중복 키가 모두 정규화되어 보낸 바이트로 돌아오지 않습니다.

그래서 보낸 바이트 위에서 계산되는 값은 /rawPayload로만 다룰 수 있습니다. 대표적인 경우가 결제 대행사 웹훅의 서명 검증입니다(Signature). 값을 꺼내 쓰는 평소의 참조는 /payload로 합니다.

호출 본문은 JSON 객체만 받습니다. 본문이 비면 없는 것으로 보고, JSON 객체가 아니면(깨진 JSON, 배열, 스칼라, 리터럴 null) 실행하지 않고 거부합니다(오류 참조).

/now: 실행이 시작된 시각

/now는 이 실행이 시작된 시각을 세 가지 형태로 담습니다.

포인터
{ /now/seconds }epoch 초(정수)
{ /now/millis }epoch 밀리초(정수)
{ /now/iso }sys.createdAt 같은 플랫폼의 시각 표기 문자열(UTC)
  • 한 실행에는 시각이 하나뿐입니다. 시계를 읽는 statement가 아니라 실행이 시작될 때 심어 두는 값이므로, 문 두 개가 서로 다른 값을 볼 일이 없습니다. Parallel의 각 브랜치도 같은 시각을 물려받습니다. 문이 아니라서 statement 개수에도 세지 않습니다.
  • 표준 시간대를 고르는 필드는 없습니다. epoch 값은 어디서나 같은 수이고, iso는 UTC 표기입니다.
  • 웹훅의 replay window(서명이 실린 타임스탬프가 지금으로부터 몇 초 안인지) 검증에 씁니다. 타임스탬프는 보통 문자열로 들어오지만 산술 연산이 숫자로 바꿔 주므로 그대로 비교합니다.
// 서명에 실린 타임스탬프가 5분(300초) 안인가
{ "<": [ { "-": [ "{ /now/seconds }", "{ /sig/1 }" ] }, 300 ] }

statement 결과의 모양

name을 붙인 statement의 결과 형태는 타입마다 다릅니다.

statement결과 모양참조 예
Http{ status, body }{ /resp/status }, { /resp/body/choices/0/message/content }
ResourceCreate, ResourceRead(단건), ResourceFind(단건)리소스 그 자체{ /post/sys/id }, { /post/fields/title/en-US }
ResourceForEach(순회 중) name현재 항목 = 리소스 그 자체. onEach 안에서만 참조{ /post/sys/id }, { /post/fields/title/en-US }
ResourceCount매치한 건수(정수){ /commentCount }
ParseJson파싱된 값 그 자체(객체·배열·스칼라){ /quote/items/0/price }
SignatureBoolean(검증 통과 여부){ /verified }
Hash문자열(선언한 표기의 다이제스트){ /expectedSign }
RegexMatchBoolean. Capture는 배열(0=매치 전체, 1부터 캡쳐 그룹) 또는 매치가 없으면 null{ /isOrderId }, { /sig/1 }
  • ResourceFind는 매치가 없으면 null을 바인딩합니다. { "==": [ "{ /found }", null ] }로 존재 여부를 분기합니다.
  • ResourceRead(단건)는 대상이 없으면 에러입니다(Try로 처리 가능). 자세한 내용은 Statement 카탈로그의 리소스 읽기에서 다룹니다.
  • ServiceUser를 읽으면 결과는 회원 리소스 그 자체입니다({ /member/sys/id }). Content·Media와 달리 필드가 로케일 맵이 아니라 값 그대로입니다. 규칙은 회원 디렉터리 읽기에서 다룹니다.

연산과 조건: JsonLogic

계산이나 조건이 필요하면 jsonlogic.com 스펙의 연산자 객체를 씁니다.

  • 데이터 접근은 vanilla var(dot-path)가 아니라 { /ptr } 참조로 통일합니다. 엔진이 피연산자의 포인터를 먼저 resolve한 뒤 연산자를 적용합니다.
  • 연산자는 그 객체의 유일한 키여야 합니다. 데이터 자리에서는 $를 붙인 키만 연산이고, 식 자리에서는 $ 유무에 관계없이 연산입니다(데이터 자리와 식 자리 참조).

연산자 표

표의 이름은 연산자 토큰입니다. 데이터 자리에 쓸 때는 앞에 $를 붙입니다(cat$cat). 식 자리에서는 둘 다 됩니다.

분류연산자의미와 예
조건if (별칭 ?:){ "if": [조건, 참값, 조건2, 참값2, …, 기본값] }. 첫 참 조건의 값, 없으면 마지막 기본값.
논리and, or단축 평가. and는 첫 falsy(또는 마지막), or는 첫 truthy(또는 마지막)를 값으로 돌려줍니다.
논리! (not), !! (to-bool){ "!": x }는 truthy 부정, { "!!": x }는 truthy 여부. 존재 검사에 !!를 자주 씁니다.
동등==, !=느슨한 비교(숫자 강제 변환 후 비교. "1"==1은 참).
동등===, !==엄격한 비교(타입까지).
비교<, <=, >, >=연쇄 가능: { "<": [1,2,3] }1<2 AND 2<3. 숫자화 불가(NaN)면 false.
산술+모든 피연산자의 합.
산술-피연산자 1개면 음수화, 2개면 뺄셈.
산술*, /, %곱, 나눗셈, 나머지.
집계min, max피연산자들의 최소, 최대.
문자열cat모든 피연산자를 문자열로 이어 붙임.
포함in{ "in": [needle, haystack] }. haystack이 문자열이면 부분문자열, 컬렉션이면 원소 포함.
배열merge여러 배열이나 값을 하나의 배열로 평탄화(누적 수집에 씀).
날짜date{ "date": [값, 출력 단위] }. 값을 비교 가능한 순간으로 정규화. 출력 단위는 millis(기본), seconds, iso, day. 날짜 정규화 참조.

배열 순회 연산자(map, filter, reduce, all, some, none)는 지원하지 않습니다. Script는 배열을 Loop로 순회합니다(Statement 카탈로그의 Loop). 목록에서 날짜 조건에 맞는 항목만 골라내는 것도 순회가 아니라 읽기 문이 하는 일입니다. ResourceFindResourceForEachwhere에 조건을 주면 서버가 걸러서 돌려줍니다(쓸 수 있는 연산자는 연산자 목록에 있습니다).

숫자 변환과 예시

숫자 변환 규칙은 다음과 같습니다. 숫자는 그대로 두고, true는 1, false는 0, 문자열은 파싱하며(파싱할 수 없으면 계산이 실패합니다), null은 0으로 변환합니다.

날짜 문자열은 숫자가 아닙니다. "2026-10-03"은 숫자로 파싱되지 않으므로 비교 연산자가 오류 없이 언제나 false를 돌려줍니다. 날짜를 견주려면 date로 먼저 정규화합니다.

아래 스니펫은 식 자리 기준입니다. 데이터 자리(fields, Http.body, Return.value, SetVar.value)에 넣을 때는 최상위 연산자에 $를 붙이고 안쪽 피연산자는 그대로 둡니다.

{ "-":  [ "{ /wallet/fields/balance/en-US }", "{ /payload/fields/cost }" ] }   // 잔액 - 비용
{ "<":  [ "{ /wallet/fields/balance/en-US }", "{ /payload/fields/cost }" ] }   // 잔액 < 비용 → boolean
{ "and": [ { "<": [ "{ /a/body/risk }", 0.5 ] }, { ">=": [ "{ /b/body/score }", 700 ] } ] }
{ "cat": [ "id-", "{ /payload/sys/id }" ] }                                    // "id-<uuid>"
{ "!!": "{ /found/sys/id }" }                                                  // 존재하면 true
{ "$merge": [ "{ /vars/ids }", [ "{ /row/sys/id }" ] ] }                       // 배열 누적: SetVar.value 는 데이터 자리라 $
{ "if": [ "{ /payload/fields/next }", "{ /payload/fields/next }", "END" ] }     // next가 있으면 next, 없으면 "END"

날짜 정규화 (date)

비교 연산자는 피연산자를 숫자로 바꾼 뒤 견줍니다. 날짜 문자열은 숫자가 아니므로 그 비교는 오류 없이 언제나 false가 됩니다. ==로 바꿔도 해결되지 않습니다. 양쪽이 숫자가 아니면 텍스트를 그대로 견주므로, 같은 순간을 다르게 적은 "2026-10-03""2026-10-03T00:00:00.000Z"가 서로 다른 값이 됩니다. 날짜는 견주기 전에 date로 정규화합니다.

{ "date": [ , 출력 단위 ] }     // 출력 단위는 생략할 수 있습니다
{ "date": "2026-10-03" }          // 값 하나만 넘길 때는 배열을 벗겨도 됩니다

before, after, equal 전용 연산자는 없습니다. 정규화한 값은 숫자이므로 이미 있는 비교, 산술, 집계 연산자를 그대로 쓰면 됩니다.

판정하려는 것쓰는 식
a가 b보다 이전{ "<": [ { "date": a }, { "date": b } ] }
a가 b보다 이후{ ">": [ { "date": a }, { "date": b } ] }
같은 순간{ "==": [ { "date": a }, { "date": b } ] }
같은 날(시각은 무시){ "==": [ { "date": [a, "day"] }, { "date": [b, "day"] } ] }
from과 to 사이{ "<=": [ { "date": from }, { "date": x }, { "date": to } ] } (연쇄 비교)
일주일 뒤{ "date": [ { "+": [ { "date": x }, 604800000 ] }, "iso" ] }
두 날짜의 일수 차이{ "/": [ { "-": [ { "date": a }, { "date": b } ] }, 86400000 ] }
여러 날짜 중 가장 이른 것{ "min": [ { "date": a }, { "date": b } ] }

산술 결과는 다시 밀리초 숫자이므로 date에 한 번 더 넣어 isoday로 출력할 수 있습니다(위 표의 "일주일 뒤").

// 식 자리: 쿠폰이 유효기간 안인가. 세 값의 표기가 서로 달라도 됩니다
{ "<=": [
  { "date": "{ /coupon/fields/startsAt/en-US }" },
  { "date": "{ /now/iso }" },
  { "date": "{ /coupon/fields/endsAt/en-US }" }
] }
 
// 식 자리: HTTP Date 헤더가 지금으로부터 5분(300초) 안인가
{ "<": [ { "-": [ "{ /now/seconds }", { "date": [ "{ /headers/date }", "seconds" ] } ] }, 300 ] }

읽는 입력

아래 값은 모두 같은 순간으로 읽힙니다.

형식
ISO-8601, RFC 33392026-10-03T00:00:00Z, 2026-10-03T00:00:00.000Z, 2026-10-03T09:00:00+09:00
초나 소수점 이하를 생략한 시각2026-10-03T00:00
T 자리에 공백을 둔 시각2026-10-03 00:00:00
날짜만(UTC 자정으로 읽습니다)2026-10-03
RFC 1123(HTTP Date 헤더의 표기)Sat, 03 Oct 2026 00:00:00 GMT
epoch 숫자와 숫자 문자열1790985600, 1790985600000, "1790985600"
  • offset이 없으면 UTC로 읽습니다. offset은 +09:00, +0900, +09, Z를 모두 받습니다.
  • 파싱은 엄격합니다. 자릿수가 맞아도 실제로 없는 날짜(2026-13-45)면 실패합니다.
  • epoch은 절댓값의 크기로 단위를 가립니다. 100,000,000,000 미만이면 초, 그 이상이면 밀리초입니다. 그래서 { /now/seconds }{ /now/millis } 중 어느 것을 넣어도 각각 맞게 읽힙니다.
  • epoch으로 인정하는 범위는 절댓값 100,000,000 이상 100,000,000,000,000 미만입니다. 단위를 크기로 가려야 하므로 범위를 양쪽에서 막아 둡니다. 그 밖의 숫자는 1970년으로 읽히는 대신 실패합니다. 구분자 없는 날짜 20261003, 연도 2026, 값이 없다는 뜻으로 넘어오는 0이 여기에 해당합니다.

출력 단위

두 번째 피연산자가 출력 형태를 정합니다. 단위 이름은 대소문자를 가리지 않습니다.

결과쓰는 자리
생략, millisepoch 밀리초(숫자)비교와 산술
secondsepoch 초(숫자). 초 미만은 버립니다epoch 초를 받는 외부 API
iso2026-10-03T00:00:00.000ZContentDate 필드에 쓰기
day2026-10-03(UTC 기준)같은 날 비교, 화면 표기

목록에 없는 이름을 주면 실패하고, 오류 메시지가 쓸 수 있는 이름을 나열해 줍니다.

iso 출력과 Date 필드 쓰기

ContentDate 필드는 쓸 때 yyyy-MM-ddTHH:mm:ss[.소수점]Z 한 가지 형식만 받습니다. T와 초와 끝의 Z가 모두 있어야 하고, 소수점 이하는 넣어도 되고 빼도 되며, 값은 UTC로 읽힙니다. 그래서 payload로 받은 2026-10-03이나 2026-10-03T09:00:00+09:00을 그대로 넣으면 값이 유효하지 않다고 거부됩니다. dateiso 출력이 정확히 이 형식이므로, 받은 날짜를 필드에 쓰기 전에 date로 한 번 통과시킵니다.

// 데이터 자리: payload 의 "2026-10-03" 을 쿠폰의 만료일에 씁니다
"fields": { "endsAt": { "en-US": { "$date": [ "{ /payload/fields/endsAt }", "iso" ] } } }

읽을 수 없는 값

아래 세 경우에는 그 문이 실패합니다(status 400). 실행 중에 나는 실패라서 Trycatch로 국소 처리할 수 있습니다.

  • 첫 피연산자가 없거나, 참조가 값을 찾지 못했습니다.
  • 값을 날짜로 읽을 수 없습니다. 빈 문자열, 공백뿐인 문자열, 날짜가 아닌 문자열, 없는 날짜, 불리언, 객체, 인정 범위 밖의 숫자가 여기에 해당합니다.
  • 출력 단위 이름이 목록에 없습니다.

값이 없을 때 null을 돌려주지 않는 것은 의도한 계약입니다. null은 숫자 변환에서 0이 되어 1970년으로 견주어지므로, 날짜가 빠진 검사는 실패하는 것이 아니라 결과가 뒤집힙니다. 유효기간을 벗어난 쿠폰이 통과해 버리는 쪽이 실행이 멈추는 것보다 나쁩니다.

참과 거짓 판정 (Truthiness)

if, and, or, !, !!If.condition, Loop.while은 아래 규칙으로 참과 거짓을 가립니다.

  • falsy: null, false, 숫자 0, 빈 문자열 "", 빈 컬렉션(빈 배열).
  • truthy: 그 외 전부(0이 아닌 숫자, 비어 있지 않은 문자열과 배열, 모든 객체).

키도 참조할 수 있습니다

fields 같은 맵의 { /ptr } 참조를 지원합니다. 키가 런타임에 resolve됩니다.

"fields": { "{ /payload/fields/fieldName }": { "en-US": "{ /payload/fields/fieldValue }" } }

두 키가 같은 값으로 resolve되면 충돌이 나고 엔진 에러입니다.

로케일 맵: Content와 Media 특유 규칙

WEEGLOO ContentMedia의 각 필드는 값이 아니라 로케일별 맵입니다(예: balance{ "en-US": 1, "ko-KR": 10 }). 따라서 읽고 쓸 때 로케일을 함께 다뤄야 합니다. Mediatitledescription(스칼라), file(인제스트 지시)이 로케일 맵입니다. /payload나 HTTP 응답처럼 ContentMedia가 아닌 JSON은 이 규칙과 무관합니다(스키마가 정한 구조 그대로이고, 스칼라면 스칼라입니다).

읽기

  • 스칼라를 얻으려면 로케일까지 지정합니다: { /<name>/fields/<field>/<locale> }(예: { /post/fields/title/en-US }).
  • 로케일 없이 { /<name>/fields/<field> }면 로케일 맵 객체 전체가 나옵니다.
  • localized:false 필드는 기본 로케일 버킷에만 있으므로 그 기본 로케일 코드로 읽습니다.

쓰기 (ResourceCreate, ResourceUpdate, ResourcePatch의 fields)

값은 로케일 맵 { "<locale>": <스칼라 값표현식> }입니다. 읽기와 대칭입니다.

"fields": {
  "title":  { "en-US": "Hello", "ko-KR": "안녕" },   // 여러 로케일은 버킷 나열
  "status": { "en-US": "paid" }
}
  • ResourceCreate는 populate하는 모든 필드에 Space 기본 로케일 버킷을 반드시 포함해야 합니다(default-locale 규칙).
  • ResourceUpdate는 전체 교체입니다. fields에 없는 필드와 로케일은 제거됩니다(file 포함).
  • ResourcePatch는 지정한 필드와 버킷만 갱신합니다(나머지 필드와 로케일은 유지).
  • 리터럴 null로 삭제합니다: 값이 리터럴 null이면 그 (field, locale) 버킷을 삭제합니다(Patch에서 특정 로케일 비우기의 표준). ""(빈 문자열)은 삭제가 아니라 빈 값 설정입니다. 값표현식({ /ptr })이 런타임에 null로 평가되면 삭제가 아니라 에러입니다(payload 누락을 조용히 삼키지 않음). 삭제는 리터럴 null만 해당합니다.
  • Media file: 값이 스칼라가 아니라 인제스트 지시 { "source": …, "encoding": "url"|"base64" }입니다. 인제스트가 실제로 무엇을 하는지는 Statement 카탈로그의 ResourceCreate에서 다룹니다.
  • localized:false 필드는 기본 로케일 버킷에만 넣습니다.
  • 로케일 코드(맵 키)도 { /ptr } 참조가 가능합니다(위 키도 참조할 수 있습니다 참조). 동적 로케일을 만들 때 씁니다.

locale 편의 필드

ResourceCreate, ResourceUpdate, ResourcePatchlocale을 주면 엔진이 fields각 값을 자동으로 { <locale>: 값 } 버킷으로 감쌉니다. 즉 스칼라만 주면 됩니다.

// 아래 두 개는 동일하다
{ "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_post" } },
  "locale": "en-US", "fields": { "title": "Hello" } }
 
{ "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_post" } },
  "fields": { "title": { "en-US": "Hello" } } }

locale을 주면서 값에 이미 로케일 맵({ "en-US": … })을 중첩하면 { <locale>: { "en-US": … } }이중 중첩됩니다(작성자 실수). locale을 쓰면 스칼라만, 안 쓰면 명시 로케일 맵만 쓰도록 하나로 통일합니다.

where와 order의 로케일

  • whereorder에서 fields.X는 엔진이 Space 기본 로케일을 자동 적용합니다(CMA 조회와 동일).
  • 특정 로케일을 지정하려면 fields.X.<locale>로 명시합니다.
"where": { "fields.slug": { "eq": "{ /payload/fields/slug }" } }   // 기본 로케일 slug
"where": { "fields.title.ko-KR": { "prefix": "안" } }              // 특정 로케일

오류

값 표현식의 규칙을 어겼을 때 나오는 코드입니다. 저장 시 검사하며, 정의의 다른 정적 제약을 어긴 코드는 실행 시맨틱, 제약, 보안의 오류에, 호출 시 나오는 코드는 엔드포인트의 오류에 있습니다. 모든 리소스에 공통인 코드는 공통 오류를 참조하세요.

코드조건
WGL400056데이터 자리에서 $ 연산 키를 같은 객체의 다른 키와 함께 두었습니다.
WGL400055데이터 자리에 연산자로 정의되지 않은 $ 키를 적었습니다.