Script

Script 是前端通过 HTTP 调用的声明式后端端点。无需编写服务器代码,只要用 JSON 声明"要做什么",WEEGLOO 引擎便会代为执行。目标是用一个 Script 取代支撑前端的典型后端中间层(BFF,Backend-for-Frontend):认证、条件检查(guard)、连锁 CRUD、外部 API 调用、值加工等。

这组文档是 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 模板流动。 用 { /pointer } 引用前一步的结果、输入 payload、变量,并传给下一步。需要条件或计算时使用 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。指定后会在执行前用此 schema 校验请求 body(payload),校验失败则不执行并拒绝。
statements必填要执行的 Statement 的有序数组。至少 1 个。
secrets选填外部 API 密钥、签名密钥这类不能直接写进 Statement 的机密值列表。每个项目包含 key、value、description,在 Statement 中以 { /secrets/<key> } 读取该 value。值由 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 值之所以是 locale 映射({ "en-US": ... }),其原因在值表达式的 locale 映射中讲解。

更多样的场景在Cookbook中。

本组文档

  • 值表达式:讲解 { /pointer } 引用、字面量、JsonLogic 运算与条件、上下文根、locale 映射。是语法的核心。
  • Statement 目录:讲解 25 种 Statement(资源 CRUD 与读取、Http、EmailSend、SetVar、Cache、ParseJson、Signature、Hash、Regex、If、Loop、Parallel、Try、Return)的字段与结果。
  • 执行语义、约束与安全:讲解执行顺序、guard、补偿、乐观锁、错误、静态约束与套餐限额、安全模型。
  • Cookbook:讲解 upsert、额度 guard、LLM 代理、分页、并行、支付 saga、Webhook 签名校验等完整示例。
  • Script 资源与端点:讲解 Script 资源的 sys 结构与编写、执行(/execute) HTTP 端点规格,以及执行日志 ScriptLog。

初次接触的话,建议在本页之后按值表达式、Statement 目录的顺序阅读。Cookbook可以整体通览一遍。