Script

Script는 프런트엔드가 HTTP로 호출하는 선언형 백엔드 엔드포인트입니다. 서버 코드를 작성하지 않고 "무엇을 할지"를 JSON으로 선언하면 WEEGLOO 엔진이 대신 실행합니다. 인증, 조건 검사(guard), 연쇄 CRUD, 외부 API 호출, 값 가공처럼 프런트엔드를 받치는 전형적인 백엔드 중간 계층(BFF, Backend-for-Frontend)을 Script 하나로 대체하는 것이 목표입니다.

이 문서 묶음은 Script 문법의 정본(reference)입니다. 개별 문법의 상세는 아래 이 그룹의 문서에서 나눠 다룹니다.

Script를 만들고 관리하는 일(생성·조회·수정·삭제)은 CMA(https://cma.weegloo.com/v1)에서 합니다. 실행은 전용 Script 호스트(https://script.weegloo.com/v1)의 실행 경로가 담당합니다. 이 실행 경로 하나가 Weegloo User 토큰과 제품에 가입한 회원(ServiceUser) 토큰을 둘 다 받습니다. ACMA에는 Script API가 없고, 읽기 전용 전달 API(CDA, ACDA)에도 없습니다.

멘탈 모델

  • 하나의 Script는 하나의 HTTP 엔드포인트입니다. 호출 메서드(method)로 어떤 Script를 실행할지 매칭합니다.
  • 본문은 statements 배열입니다. 위에서 아래로 순차 실행됩니다. 일반 프로그래밍의 함수 본문과 같습니다.
  • 코드가 아니라 선언입니다. 임의 코드(FaaS)를 넣는 것이 아니라, 정해진 Statement 타입을 조합합니다. 사람이 손으로 짜기보다 AI 에이전트가 MCP로 생성하는 쪽에 맞춰 설계됐습니다.
  • 값은 JSON Pointer 템플릿으로 흐릅니다. 앞 단계의 결과, 입력 payload, 변수를 { /pointer }로 참조해 다음 단계로 넘깁니다. 조건이나 계산이 필요하면 JsonLogic 연산자를 씁니다. 자세한 규칙은 값 표현식에서 다룹니다.

최상위 구조 (ScriptDefinition)

Script 하나는 다음 ScriptDefinition 구조로 정의합니다.

{
  "method": "Post",               // Get | Post | Put | Patch | Delete. 호출 시 매칭할 HTTP 메서드 (필수)
  "payloadSchema": { /* ... */ }, // (선택) JSON Schema. 있으면 실행 전에 요청 payload를 검증
  "statements": [ /* Statement[]. 위에서 아래로 실행 (필수, 1개 이상) */ ],
  "secrets": [ /* (선택) 비밀 값 목록. Statement에서 { /secrets/<key> }로 읽음 */ ]
}
필드필수설명
method필수이 Script를 호출할 HTTP 메서드입니다. 호출 시 이 값으로 매칭합니다.
payloadSchema선택JSON Schema입니다. 지정하면 실행 전에 요청 body(payload)를 이 스키마로 검증하고, 실패하면 실행하지 않고 거부합니다.
statements필수실행할 Statement의 순서 있는 배열입니다. 최소 1개입니다.
secrets선택외부 API 키나 서명 키처럼 Statement에 그대로 적으면 안 되는 비밀 값의 목록입니다. 항목마다 key·value·description을 두고, Statement에서는 그 value를 { /secrets/<key> }로 읽습니다. 값은 WEEGLOO가 암호화해 안전하게 저장합니다. 규칙은 보안 모델의 secrets에서 다룹니다.

payload는 JSON 객체만 받습니다. 호출 body는 /payload 컨텍스트 루트로 접근하고({ /payload/... }), 파싱 전 원문 문자열이 필요하면 /rawPayload로 접근합니다(서명 검증처럼 보낸 바이트 위에서 계산하는 경우). 호출의 요청 HTTP 헤더는 /headers 루트로 참조합니다({ /headers/... }, 키는 소문자). 실행이 시작된 시각은 /now 루트에 있습니다. secrets에 선언한 비밀 값은 /secrets 루트로 읽습니다({ /secrets/<key> }). 전체 컨텍스트 루트는 값 표현식에서 다룹니다.

요청과 응답

Script는 최종적으로 Return Statement의 값을 호출자에게 돌려줍니다. 응답의 형태는 다음과 같습니다.

{
  "requestId": "…",     // 실행 식별자
  "durationMs": 1234,   // 실행 소요(ms)
  "statusCode": 200,    // 도달한 Return의 statusCode (기본 200)
  "return": <value>     // Return.isError 가 false일 때만. 값이 null이면 ""
  // "error": <value>   // Return.isError 가 true일 때, 또는 실행이 실패했을 때(이때 "return"은 없음). 값이 null이면 ""
}
  • requestId는 이 실행의 식별자입니다. 같은 값이 그 실행이 남긴 ScriptLog의 sys.requestId에 들어가므로, 로그에서 이 실행을 찾을 때 이 값을 기준으로 씁니다.
  • return과 error는 동시에 나오지 않습니다. Return Statement의 isError가 어느 쪽인지 결정합니다.
  • Return Statement에 도달하지 못한 채 끝까지 실행됐다면 return과 error가 둘 다 없고 statusCode는 기본값(200)입니다.
  • 실행이 실패하면 Return 없이도 error가 담깁니다. 잘못된 payload처럼 호출 쪽 원인으로 실패하고 Try가 잡지 않으면, error에 실패 사유가 들어가고 statusCode는 그 실패에 해당하는 코드가 됩니다(잘못된 payload는 4xx, 외부 호출이나 메일 발송이 실패하면 502). 실제로 가장 자주 만나는 에러 응답이 이 모양입니다. 시간 예산을 넘긴 실행은 봉투가 아니라 408로 응답합니다.
  • 값이 null이면 해당 필드는 빈 문자열 ""로 나옵니다.

Return의 value, isError, statusCode로 응답 본문과 상태 코드를 제어합니다. 자세한 내용은 Statement 카탈로그의 Return에서 다룹니다.

한 번의 실행에 주어지는 시간

Script는 호출 요청을 처리하는 경로에서 인라인으로 실행됩니다. 백그라운드로 넘기거나 접수 응답을 먼저 돌려주는 흐름은 없고, 호출의 응답 본문이 곧 실행 결과입니다. 결과를 나중에 받아 가는 폴링 경로도 없습니다.

한 번의 실행에 허용되는 시간은 최대 180초입니다. 기본 30초에 외부 호출(Http·EmailSend)이 사용할 수 있는 시간을 더한 값이 허용되며, 파일을 보내는 Http는 파일마다 다운로드 시간이 함께 더해집니다.

  • 리소스를 읽고 쓰는 작업처럼 외부 호출이 아닌 작업은 기본 30초 안에서 처리됩니다.
  • 반복(Loop·ResourceForEach)은 그 안의 시간에 반복 횟수를 곱합니다. 따라서 외부 호출이 없는 반복은 기본 30초 안에 끝나야 합니다.
  • 계산한 값이 180초를 넘어도 저장과 실행은 되며, 실행이 180초에 도달하면 그 시점에서 중단됩니다.

Statement별로 더해지는 시간과 계산 예는 시간 예산에서 다룹니다.

최소 예시

요청 payload의 제목과 본문으로 게시글 Content를 만들고 바로 발행한 뒤, 만든 sys.id를 돌려줍니다.

{
  "method": "Post",
  "statements": [
    { "type": "ResourceCreate", "resource": "Content",
      "contentType": { "sys": { "id": "ct_post" } },
      "fields": {
        "title": { "en-US": "{ /payload/fields/title }" },
        "body":  { "en-US": "{ /payload/fields/body }" }
      },
      "publish": true,
      "name": "post" },
 
    { "type": "Return", "value": { "id": "{ /post/sys/id }" }, "statusCode": 201 }
  ]
}
  • ResourceCreate로 Content를 만들고 결과를 post라는 이름에 바인딩합니다.
  • Return이 { "id": <새 Content id> }를 201로 돌려줍니다.
  • Content의 fields 값이 로케일 맵({ "en-US": ... })인 이유는 값 표현식의 로케일 맵에서 다룹니다.

더 다양한 시나리오는 쿡북에 있습니다.

이 그룹의 문서

  • 값 표현식: { /pointer } 참조, 리터럴, JsonLogic 연산과 조건, 컨텍스트 루트, 로케일 맵을 다룹니다. 문법의 핵심입니다.
  • Statement 카탈로그: 25종 Statement(리소스 CRUD와 읽기, Http, EmailSend, SetVar, Cache, ParseJson, Signature, Hash, Regex, If, Loop, Parallel, Try, Return)의 필드와 결과를 다룹니다.
  • 실행 시맨틱, 제약, 보안: 실행 순서, guard, 보상, 낙관적 잠금, 에러, 정적 제약과 플랜 한도, 보안 모델을 다룹니다.
  • 쿡북: upsert, 크레딧 guard, LLM 프록시, 페이지네이션, 병렬, 결제 사가, 웹훅 서명 검증 등 완결된 예시를 다룹니다.
  • Script 리소스와 엔드포인트: Script 리소스의 sys 구조와 저작, 실행(/execute) HTTP 엔드포인트 명세, 실행 로그 ScriptLog를 다룹니다.

처음이라면 이 페이지에서 값 표현식, Statement 카탈로그 순서로 읽는 것을 권합니다. 쿡북은 통째로 훑어도 좋습니다.