feat(executor): expose ctx.request.method to scripts (F4)

The request map exposed path/headers/body/params/query/rest but not the
HTTP method, forcing one script per verb (the E2E app needed 7 scripts
where ~3 would do). Add a `method` field to ExecRequest (populated from
the HTTP method on the sync-execute bypass and the HTTP outbox payload;
empty for non-HTTP triggers) and surface it as `ctx.request.method`,
uppercased. A single script can now branch GET/POST on one route.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-12 20:43:10 +02:00
parent 04a24ea0b7
commit ae2134e62d
21 changed files with 49 additions and 0 deletions

View File

@@ -485,6 +485,7 @@ fn build_ctx_map(req: &ExecRequest) -> Map {
let mut request = Map::new();
request.insert("path".into(), req.path.clone().into());
request.insert("method".into(), req.method.clone().into());
let mut headers = Map::new();
for (k, v) in &req.headers {

View File

@@ -171,6 +171,7 @@ fn invoke_blocking(
script_name: resolved.name.clone(),
invocation_type: InvocationType::Function,
path: "/invoke".into(),
method: String::new(),
headers: BTreeMap::new(),
body: args_json,
params: BTreeMap::new(),

View File

@@ -27,6 +27,15 @@ pub struct ExecRequest {
pub script_name: String,
pub invocation_type: InvocationType,
pub path: String,
/// HTTP method of the originating request, uppercased (`GET`, `POST`,
/// …). Exposed to scripts as `ctx.request.method` so a single script
/// can branch on the verb instead of needing one script per method.
/// Empty for non-HTTP trigger invocations (cron/kv/docs/…), matching
/// how `path`/`rest` are empty there.
#[serde(default)]
pub method: String,
pub headers: BTreeMap<String, String>,
pub body: serde_json::Value,

View File

@@ -15,6 +15,7 @@ fn req(body: serde_json::Value) -> ExecRequest {
script_name: "test".into(),
invocation_type: InvocationType::Http,
path: "/test".into(),
method: String::new(),
headers: BTreeMap::new(),
body,
params: BTreeMap::new(),
@@ -103,6 +104,7 @@ fn ctx_exposes_request_data() {
";
let r = ExecRequest {
path: "/payments".into(),
method: String::new(),
body: json!({ "amount": 1234 }),
script_name: "payments".into(),
..req(json!(null))
@@ -114,6 +116,19 @@ fn ctx_exposes_request_data() {
);
}
#[test]
fn ctx_exposes_request_method() {
// A single script can branch on the verb instead of needing one
// script per method (E2E report F4).
let src = r"#{ statusCode: 200, body: #{ method: ctx.request.method } }";
let r = ExecRequest {
method: "PATCH".into(),
..req(json!(null))
};
let resp = engine().execute(src, r).unwrap();
assert_eq!(resp.body, json!({ "method": "PATCH" }));
}
#[test]
fn captures_log_calls() {
let src = r#"

View File

@@ -66,6 +66,7 @@ fn req(app_id: AppId) -> ExecRequest {
script_name: "redaction-test".into(),
invocation_type: InvocationType::Http,
path: "/x".into(),
method: String::new(),
headers: BTreeMap::new(),
body: Value::Null,
params: BTreeMap::new(),

View File

@@ -120,6 +120,7 @@ fn req(app_id: AppId) -> ExecRequest {
script_name: "test".into(),
invocation_type: InvocationType::Http,
path: "/test".into(),
method: String::new(),
headers: BTreeMap::new(),
body: serde_json::Value::Null,
params: BTreeMap::new(),

View File

@@ -43,6 +43,7 @@ fn baseline_request() -> ExecRequest {
script_name: "contract".into(),
invocation_type: InvocationType::Http,
path: "/contract-test".into(),
method: String::new(),
headers: BTreeMap::new(),
body: Value::Null,
params: BTreeMap::new(),

View File

@@ -248,6 +248,7 @@ fn baseline_request(app_id: AppId) -> ExecRequest {
script_name: "docs-test".into(),
invocation_type: InvocationType::Http,
path: "/docs-test".into(),
method: String::new(),
headers: BTreeMap::new(),
body: Value::Null,
params: BTreeMap::new(),

View File

@@ -57,6 +57,7 @@ fn baseline_request(app_id: AppId) -> ExecRequest {
script_name: "email-test".into(),
invocation_type: InvocationType::Http,
path: "/email-test".into(),
method: String::new(),
headers: BTreeMap::new(),
body: Value::Null,
params: BTreeMap::new(),

View File

@@ -185,6 +185,7 @@ fn baseline_request(app_id: AppId) -> ExecRequest {
script_name: "files-test".into(),
invocation_type: InvocationType::Http,
path: "/files-test".into(),
method: String::new(),
headers: BTreeMap::new(),
body: Value::Null,
params: BTreeMap::new(),

View File

@@ -108,6 +108,7 @@ fn baseline_request(app_id: AppId, script_id: ScriptId) -> ExecRequest {
script_name: "http-test".into(),
invocation_type: InvocationType::Http,
path: "/http-test".into(),
method: String::new(),
headers: BTreeMap::new(),
body: Value::Null,
params: BTreeMap::new(),

View File

@@ -105,6 +105,7 @@ fn baseline_request(app_id: AppId) -> ExecRequest {
script_name: "caller".into(),
invocation_type: InvocationType::Http,
path: "/caller".into(),
method: String::new(),
headers: BTreeMap::new(),
body: Value::Null,
params: BTreeMap::new(),

View File

@@ -127,6 +127,7 @@ fn baseline_request(app_id: AppId) -> ExecRequest {
script_name: "kv-test".into(),
invocation_type: InvocationType::Http,
path: "/kv-test".into(),
method: String::new(),
headers: BTreeMap::new(),
body: Value::Null,
params: BTreeMap::new(),

View File

@@ -65,6 +65,7 @@ fn baseline_request(app_id: AppId) -> ExecRequest {
script_name: "pubsub-test".into(),
invocation_type: InvocationType::Http,
path: "/pubsub-test".into(),
method: String::new(),
headers: BTreeMap::new(),
body: Value::Null,
params: BTreeMap::new(),

View File

@@ -79,6 +79,7 @@ fn baseline_request(app_id: AppId) -> ExecRequest {
script_name: "queue-test".into(),
invocation_type: InvocationType::Http,
path: "/queue-test".into(),
method: String::new(),
headers: BTreeMap::new(),
body: Value::Null,
params: BTreeMap::new(),

View File

@@ -43,6 +43,7 @@ fn baseline_request(app_id: AppId) -> ExecRequest {
script_name: "retry-test".into(),
invocation_type: InvocationType::Http,
path: "/retry-test".into(),
method: String::new(),
headers: BTreeMap::new(),
body: Value::Null,
params: BTreeMap::new(),

View File

@@ -118,6 +118,7 @@ fn baseline_request(app_id: AppId) -> ExecRequest {
script_name: "secrets-test".into(),
invocation_type: InvocationType::Http,
path: "/secrets-test".into(),
method: String::new(),
headers: BTreeMap::new(),
body: Value::Null,
params: BTreeMap::new(),

View File

@@ -112,6 +112,7 @@ fn request(app_id: AppId, with_principal: bool) -> ExecRequest {
script_name: "token-test".into(),
invocation_type: InvocationType::Http,
path: "/token-test".into(),
method: String::new(),
headers: BTreeMap::new(),
body: Value::Null,
params: BTreeMap::new(),

View File

@@ -29,6 +29,7 @@ fn baseline_request() -> ExecRequest {
script_name: "stdlib".into(),
invocation_type: InvocationType::Http,
path: "/stdlib-test".into(),
method: String::new(),
headers: BTreeMap::new(),
body: Value::Null,
params: BTreeMap::new(),