From f090a23bc3b40c0f4eefefda1e2d761c2516ea44 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Wed, 27 Aug 2025 07:44:29 +0530 Subject: [PATCH 1/6] feat: allow HEAD requests in function executions --- app/config/specs/open-api3-1.8.x-client.json | 3 ++- app/config/specs/open-api3-1.8.x-console.json | 3 ++- app/config/specs/open-api3-1.8.x-server.json | 3 ++- app/config/specs/open-api3-latest-client.json | 3 ++- app/config/specs/open-api3-latest-console.json | 3 ++- app/config/specs/open-api3-latest-server.json | 3 ++- app/config/specs/swagger2-1.8.x-client.json | 3 ++- app/config/specs/swagger2-1.8.x-console.json | 3 ++- app/config/specs/swagger2-1.8.x-server.json | 3 ++- app/config/specs/swagger2-latest-client.json | 3 ++- app/config/specs/swagger2-latest-console.json | 3 ++- app/config/specs/swagger2-latest-server.json | 3 ++- .../Platform/Modules/Functions/Http/Executions/Create.php | 2 +- 13 files changed, 25 insertions(+), 13 deletions(-) diff --git a/app/config/specs/open-api3-1.8.x-client.json b/app/config/specs/open-api3-1.8.x-client.json index 5d80f25da5..97dd04e518 100644 --- a/app/config/specs/open-api3-1.8.x-client.json +++ b/app/config/specs/open-api3-1.8.x-client.json @@ -5889,7 +5889,8 @@ "PUT", "PATCH", "DELETE", - "OPTIONS" + "OPTIONS", + "HEAD" ], "x-enum-name": "ExecutionMethod", "x-enum-keys": [] diff --git a/app/config/specs/open-api3-1.8.x-console.json b/app/config/specs/open-api3-1.8.x-console.json index 3013857712..6058252ac7 100644 --- a/app/config/specs/open-api3-1.8.x-console.json +++ b/app/config/specs/open-api3-1.8.x-console.json @@ -12799,7 +12799,8 @@ "PUT", "PATCH", "DELETE", - "OPTIONS" + "OPTIONS", + "HEAD" ], "x-enum-name": "ExecutionMethod", "x-enum-keys": [] diff --git a/app/config/specs/open-api3-1.8.x-server.json b/app/config/specs/open-api3-1.8.x-server.json index ce383d596c..4559eb972d 100644 --- a/app/config/specs/open-api3-1.8.x-server.json +++ b/app/config/specs/open-api3-1.8.x-server.json @@ -11584,7 +11584,8 @@ "PUT", "PATCH", "DELETE", - "OPTIONS" + "OPTIONS", + "HEAD" ], "x-enum-name": "ExecutionMethod", "x-enum-keys": [] diff --git a/app/config/specs/open-api3-latest-client.json b/app/config/specs/open-api3-latest-client.json index 5d80f25da5..97dd04e518 100644 --- a/app/config/specs/open-api3-latest-client.json +++ b/app/config/specs/open-api3-latest-client.json @@ -5889,7 +5889,8 @@ "PUT", "PATCH", "DELETE", - "OPTIONS" + "OPTIONS", + "HEAD" ], "x-enum-name": "ExecutionMethod", "x-enum-keys": [] diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index 3013857712..6058252ac7 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -12799,7 +12799,8 @@ "PUT", "PATCH", "DELETE", - "OPTIONS" + "OPTIONS", + "HEAD" ], "x-enum-name": "ExecutionMethod", "x-enum-keys": [] diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index ce383d596c..4559eb972d 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -11584,7 +11584,8 @@ "PUT", "PATCH", "DELETE", - "OPTIONS" + "OPTIONS", + "HEAD" ], "x-enum-name": "ExecutionMethod", "x-enum-keys": [] diff --git a/app/config/specs/swagger2-1.8.x-client.json b/app/config/specs/swagger2-1.8.x-client.json index de6564edaa..e512273091 100644 --- a/app/config/specs/swagger2-1.8.x-client.json +++ b/app/config/specs/swagger2-1.8.x-client.json @@ -5987,7 +5987,8 @@ "PUT", "PATCH", "DELETE", - "OPTIONS" + "OPTIONS", + "HEAD" ], "x-enum-name": "ExecutionMethod", "x-enum-keys": [] diff --git a/app/config/specs/swagger2-1.8.x-console.json b/app/config/specs/swagger2-1.8.x-console.json index c247b9d63d..6285e8a487 100644 --- a/app/config/specs/swagger2-1.8.x-console.json +++ b/app/config/specs/swagger2-1.8.x-console.json @@ -12845,7 +12845,8 @@ "PUT", "PATCH", "DELETE", - "OPTIONS" + "OPTIONS", + "HEAD" ], "x-enum-name": "ExecutionMethod", "x-enum-keys": [] diff --git a/app/config/specs/swagger2-1.8.x-server.json b/app/config/specs/swagger2-1.8.x-server.json index aac613600e..cfe7109ed4 100644 --- a/app/config/specs/swagger2-1.8.x-server.json +++ b/app/config/specs/swagger2-1.8.x-server.json @@ -11655,7 +11655,8 @@ "PUT", "PATCH", "DELETE", - "OPTIONS" + "OPTIONS", + "HEAD" ], "x-enum-name": "ExecutionMethod", "x-enum-keys": [] diff --git a/app/config/specs/swagger2-latest-client.json b/app/config/specs/swagger2-latest-client.json index de6564edaa..e512273091 100644 --- a/app/config/specs/swagger2-latest-client.json +++ b/app/config/specs/swagger2-latest-client.json @@ -5987,7 +5987,8 @@ "PUT", "PATCH", "DELETE", - "OPTIONS" + "OPTIONS", + "HEAD" ], "x-enum-name": "ExecutionMethod", "x-enum-keys": [] diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index c247b9d63d..6285e8a487 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -12845,7 +12845,8 @@ "PUT", "PATCH", "DELETE", - "OPTIONS" + "OPTIONS", + "HEAD" ], "x-enum-name": "ExecutionMethod", "x-enum-keys": [] diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index aac613600e..cfe7109ed4 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -11655,7 +11655,8 @@ "PUT", "PATCH", "DELETE", - "OPTIONS" + "OPTIONS", + "HEAD" ], "x-enum-name": "ExecutionMethod", "x-enum-keys": [] diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php index 64056b7db7..ef5be61384 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php @@ -80,7 +80,7 @@ class Create extends Base ->param('body', '', new Text(10485760, 0), 'HTTP body of execution. Default value is empty string.', true) ->param('async', false, new Boolean(true), 'Execute code in the background. Default value is false.', true) ->param('path', '/', new Text(2048), 'HTTP path of execution. Path can include query params. Default value is /', true) - ->param('method', 'POST', new Whitelist(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], true), 'HTTP method of execution. Default value is GET.', true) + ->param('method', 'POST', new Whitelist(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'], true), 'HTTP method of execution. Default value is GET.', true) ->param('headers', [], new AnyOf([new Assoc(), new Text(65535)], AnyOf::TYPE_MIXED), 'HTTP headers of execution. Defaults to empty.', true) ->param('scheduledAt', null, new Text(100), 'Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.', true) ->inject('response') From cc736218747428b5b28b0cf3d6fc2a48b8d9e080 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Wed, 27 Aug 2025 07:46:35 +0530 Subject: [PATCH 2/6] format --- src/Appwrite/Utopia/Request/Filters/V20.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Utopia/Request/Filters/V20.php b/src/Appwrite/Utopia/Request/Filters/V20.php index 939eeeabe7..30de1fb2d3 100644 --- a/src/Appwrite/Utopia/Request/Filters/V20.php +++ b/src/Appwrite/Utopia/Request/Filters/V20.php @@ -52,7 +52,7 @@ class V20 extends Filter if (empty($selections)) { $hasWildcard = true; $parsed[] = Query::select(['*']); - } else if (!$hasWildcard) { + } elseif (!$hasWildcard) { // check if any select includes a wildcard as we added one above foreach ($selections as $select) { if (\in_array('*', $select->getValues(), true)) { From c6c3a675d235f4a4ab0817ad86aff2cee25b166d Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Wed, 27 Aug 2025 15:20:20 +0530 Subject: [PATCH 3/6] update specs --- app/config/specs/open-api3-1.8.x-client.json | 2 +- app/config/specs/open-api3-1.8.x-console.json | 2 +- app/config/specs/open-api3-1.8.x-server.json | 2 +- app/config/specs/open-api3-latest-client.json | 2 +- app/config/specs/open-api3-latest-console.json | 2 +- app/config/specs/open-api3-latest-server.json | 2 +- app/config/specs/swagger2-1.8.x-client.json | 2 +- app/config/specs/swagger2-1.8.x-console.json | 2 +- app/config/specs/swagger2-1.8.x-server.json | 2 +- app/config/specs/swagger2-latest-client.json | 2 +- app/config/specs/swagger2-latest-console.json | 2 +- app/config/specs/swagger2-latest-server.json | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/config/specs/open-api3-1.8.x-client.json b/app/config/specs/open-api3-1.8.x-client.json index 6cea7c5ef3..553b7ce385 100644 --- a/app/config/specs/open-api3-1.8.x-client.json +++ b/app/config/specs/open-api3-1.8.x-client.json @@ -5881,7 +5881,7 @@ }, "method": { "type": "string", - "description": "HTTP method of execution. Default value is GET.", + "description": "HTTP method of execution. Default value is POST.", "x-example": "GET", "enum": [ "GET", diff --git a/app/config/specs/open-api3-1.8.x-console.json b/app/config/specs/open-api3-1.8.x-console.json index a5b0679437..7d33440d01 100644 --- a/app/config/specs/open-api3-1.8.x-console.json +++ b/app/config/specs/open-api3-1.8.x-console.json @@ -12791,7 +12791,7 @@ }, "method": { "type": "string", - "description": "HTTP method of execution. Default value is GET.", + "description": "HTTP method of execution. Default value is POST.", "x-example": "GET", "enum": [ "GET", diff --git a/app/config/specs/open-api3-1.8.x-server.json b/app/config/specs/open-api3-1.8.x-server.json index 923ff81974..d117377a21 100644 --- a/app/config/specs/open-api3-1.8.x-server.json +++ b/app/config/specs/open-api3-1.8.x-server.json @@ -11576,7 +11576,7 @@ }, "method": { "type": "string", - "description": "HTTP method of execution. Default value is GET.", + "description": "HTTP method of execution. Default value is POST.", "x-example": "GET", "enum": [ "GET", diff --git a/app/config/specs/open-api3-latest-client.json b/app/config/specs/open-api3-latest-client.json index 6cea7c5ef3..553b7ce385 100644 --- a/app/config/specs/open-api3-latest-client.json +++ b/app/config/specs/open-api3-latest-client.json @@ -5881,7 +5881,7 @@ }, "method": { "type": "string", - "description": "HTTP method of execution. Default value is GET.", + "description": "HTTP method of execution. Default value is POST.", "x-example": "GET", "enum": [ "GET", diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index a5b0679437..7d33440d01 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -12791,7 +12791,7 @@ }, "method": { "type": "string", - "description": "HTTP method of execution. Default value is GET.", + "description": "HTTP method of execution. Default value is POST.", "x-example": "GET", "enum": [ "GET", diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index 923ff81974..d117377a21 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -11576,7 +11576,7 @@ }, "method": { "type": "string", - "description": "HTTP method of execution. Default value is GET.", + "description": "HTTP method of execution. Default value is POST.", "x-example": "GET", "enum": [ "GET", diff --git a/app/config/specs/swagger2-1.8.x-client.json b/app/config/specs/swagger2-1.8.x-client.json index 92950a9cee..9b9a695896 100644 --- a/app/config/specs/swagger2-1.8.x-client.json +++ b/app/config/specs/swagger2-1.8.x-client.json @@ -5978,7 +5978,7 @@ }, "method": { "type": "string", - "description": "HTTP method of execution. Default value is GET.", + "description": "HTTP method of execution. Default value is POST.", "default": "POST", "x-example": "GET", "enum": [ diff --git a/app/config/specs/swagger2-1.8.x-console.json b/app/config/specs/swagger2-1.8.x-console.json index b6c848bd0c..d8fc57519f 100644 --- a/app/config/specs/swagger2-1.8.x-console.json +++ b/app/config/specs/swagger2-1.8.x-console.json @@ -12836,7 +12836,7 @@ }, "method": { "type": "string", - "description": "HTTP method of execution. Default value is GET.", + "description": "HTTP method of execution. Default value is POST.", "default": "POST", "x-example": "GET", "enum": [ diff --git a/app/config/specs/swagger2-1.8.x-server.json b/app/config/specs/swagger2-1.8.x-server.json index 4b0a1263e5..f9c84e4f2d 100644 --- a/app/config/specs/swagger2-1.8.x-server.json +++ b/app/config/specs/swagger2-1.8.x-server.json @@ -11646,7 +11646,7 @@ }, "method": { "type": "string", - "description": "HTTP method of execution. Default value is GET.", + "description": "HTTP method of execution. Default value is POST.", "default": "POST", "x-example": "GET", "enum": [ diff --git a/app/config/specs/swagger2-latest-client.json b/app/config/specs/swagger2-latest-client.json index 92950a9cee..9b9a695896 100644 --- a/app/config/specs/swagger2-latest-client.json +++ b/app/config/specs/swagger2-latest-client.json @@ -5978,7 +5978,7 @@ }, "method": { "type": "string", - "description": "HTTP method of execution. Default value is GET.", + "description": "HTTP method of execution. Default value is POST.", "default": "POST", "x-example": "GET", "enum": [ diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index b6c848bd0c..d8fc57519f 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -12836,7 +12836,7 @@ }, "method": { "type": "string", - "description": "HTTP method of execution. Default value is GET.", + "description": "HTTP method of execution. Default value is POST.", "default": "POST", "x-example": "GET", "enum": [ diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index 4b0a1263e5..f9c84e4f2d 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -11646,7 +11646,7 @@ }, "method": { "type": "string", - "description": "HTTP method of execution. Default value is GET.", + "description": "HTTP method of execution. Default value is POST.", "default": "POST", "x-example": "GET", "enum": [ From f4ea5fad4ad0b140c51c89d6d617ff8d123effa3 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Wed, 27 Aug 2025 17:22:08 +0530 Subject: [PATCH 4/6] add test case --- .../Functions/FunctionsCustomServerTest.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 916e41d8a4..751df5c65f 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -925,6 +925,19 @@ class FunctionsCustomServerTest extends Scope $executionId = $execution['body']['$id'] ?? ''; + /** Test create execution with HEAD method */ + $execution = $this->createExecution($data['functionId'], [ + 'async' => 'false', + 'method' => 'HEAD', + ]); + + $this->assertEquals(200, $execution['headers']['status-code']); + $this->assertEquals('completed', $execution['body']['status']); + $this->assertEquals(200, $execution['body']['responseStatusCode']); + $this->assertIsArray($execution['body']['responseHeaders']); + $this->assertEmpty($execution['body']['responseBody']); // For head requests, response body is empty + + /** Test create execution with 400 status code */ $execution = $this->createExecution($data['functionId'], [ 'async' => 'false', 'path' => '/?code=400' From a2eec2eac63e99bc1de0fbd4d66db1d2a416ac55 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Wed, 27 Aug 2025 17:30:24 +0530 Subject: [PATCH 5/6] fix: 201 --- tests/e2e/Services/Functions/FunctionsCustomServerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 751df5c65f..adc6c42994 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -931,7 +931,7 @@ class FunctionsCustomServerTest extends Scope 'method' => 'HEAD', ]); - $this->assertEquals(200, $execution['headers']['status-code']); + $this->assertEquals(201, $execution['headers']['status-code']); $this->assertEquals('completed', $execution['body']['status']); $this->assertEquals(200, $execution['body']['responseStatusCode']); $this->assertIsArray($execution['body']['responseHeaders']); From ee292d04a6b199da4f699357cf529fce4751b6f3 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Wed, 27 Aug 2025 17:32:21 +0530 Subject: [PATCH 6/6] delete execution --- .../Services/Functions/FunctionsCustomServerTest.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index adc6c42994..220ffb3cdb 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -935,7 +935,14 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals('completed', $execution['body']['status']); $this->assertEquals(200, $execution['body']['responseStatusCode']); $this->assertIsArray($execution['body']['responseHeaders']); - $this->assertEmpty($execution['body']['responseBody']); // For head requests, response body is empty + $this->assertEmpty($execution['body']['responseBody']); // For HEAD requests, response body is empty + + /** Delete execution */ + $execution = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/executions/' . $execution['body']['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), []); + $this->assertEquals(204, $execution['headers']['status-code']); /** Test create execution with 400 status code */ $execution = $this->createExecution($data['functionId'], [ @@ -947,11 +954,11 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals('completed', $execution['body']['status']); $this->assertEquals(400, $execution['body']['responseStatusCode']); + /** Delete execution */ $execution = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/executions/' . $execution['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); - $this->assertEquals(204, $execution['headers']['status-code']); return array_merge($data, ['executionId' => $executionId]);