값 표현식 (Value Expressions)

최종 수정: 2026년 7월 20일

Script에서 값이 필요한 모든 자리(URL, 요청 body, 필드 값, 조건, 필터 값, 대상 id 등)는 아래 세 형태 중 하나입니다. 이 문서는 그 세 형태와, 값이 어디서 오는지(컨텍스트 루트), 그리고 WEEGLOO 데이터 특유의 로케일 맵 규칙을 설명합니다. Statement 카탈로그의 모든 필드가 이 규칙을 따릅니다.

세 가지 형태

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

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

참조: { /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 }
/headers호출 시 전달된 요청 HTTP 헤더입니다. 키는 소문자이고 이름당 단일 값입니다. 예: { /headers/authorization }
/<name>name이 붙은 앞선 statement의 결과입니다. 예: { /order/sys/id }
/vars/<name>SetVar로 선언한 script-scoped 가변 변수입니다. 예: { /vars/total }
/errorTrycatch 블록 안에서만 씁니다. 잡힌 에러 { message, statement }입니다. 예: { /error/message }

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 }
ResourcePageRead{ items, next }{ /page/items/0/sys/id }, { /page/next }
  • ResourceFind는 매치가 없으면 null을 바인딩합니다. { "==": [ "{ /found }", null ] }로 존재 여부를 분기합니다.
  • ResourceRead(단건)는 대상이 없으면 에러입니다(Try로 처리 가능). 자세한 내용은 Statement 카탈로그의 리소스 읽기에서 다룹니다.

연산과 조건: JsonLogic

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

  • 데이터 접근은 vanilla var(dot-path)가 아니라 { /ptr } 참조로 통일합니다. 엔진이 피연산자의 포인터를 먼저 resolve한 뒤 연산자를 적용합니다.
  • 단일 키 객체의 키가 등록된 연산자면 연산으로, 아니면 일반 객체로 취급합니다.

연산자 표

분류연산자의미와 예
조건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여러 배열이나 값을 하나의 배열로 평탄화(누적 수집에 씀).

배열 순회 연산자(map, filter, reduce, all, some, none)는 지원하지 않습니다. Script는 배열을 Loop로 순회합니다(Statement 카탈로그의 Loop).

숫자 변환과 예시

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

{ "-":  [ "{ /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 }" ] ] }                        // 배열에 원소 하나 누적
{ "if": [ "{ /page/next }", "{ /page/next }", "END" ] }                        // next가 있으면 next, 없으면 "END"

참과 거짓 판정 (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되면 충돌이 나고 엔진 에러입니다.

로케일 맵 (LocaleValueMap): 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" }입니다. 파일이 포함된 쓰기는 Async 전용입니다(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": "안" } }              // 특정 로케일