Description
The local dev server (aio app dev) does not parse the request body for PUT, PATCH, and DELETE HTTP methods. Only POST request bodies are parsed and merged into action parameters. This causes a discrepancy between the local dev environment and the actual Adobe I/O Runtime (OpenWhisk), where all HTTP methods with a body are correctly handled.
Environment
- @adobe/aio-cli: 11.0.2
- @adobe/aio-cli-plugin-app-dev: 2.2.0
- Node.js: v22.x
- OS: macOS (Darwin 24.6.0)
Steps to Reproduce
- Create a web action that accepts
PUT with a JSON body:
async function main(params) {
// params.myField should contain the body data
return { statusCode: 200, body: { received: params.myField } }
}
- Run aio app dev
- Send a PUT request with a JSON body:
curl -sk -X PUT "https://localhost:9080/api/v1/web//"
-H "Content-Type: application/json"
-d '{"myField": "hello"}'
- Expected: params.myField is "hello" (same behavior as deployed Runtime)
- Actual: params.myField is undefined — the body is silently discarded
Root Cause
In src/lib/run-dev.js, the function createActionParametersFromRequest (line 604) only processes the request body when the method is post:
// Current code (line 604)
if (params.__ow_method === 'post' && req.body !== null) {
This should include all HTTP methods that can carry a request body:
// Suggested fix
const methodsWithBody = ['post', 'put', 'patch', 'delete']
if (methodsWithBody.includes(params.__ow_method) && req.body !== null) {
The Express middleware (express.json()) already parses the body for all methods correctly. The issue is only in the condition that decides whether to merge req.body into the action params.
Impact
- PUT/PATCH/DELETE actions with JSON body fail locally but work correctly when deployed to Adobe I/O Runtime
- Developers cannot test REST APIs following standard HTTP conventions locally
- Workaround requires sending data as query strings, which is not standard for mutation operations
Suggested Fix
Change line 604 in src/lib/run-dev.js:
- if (params.__ow_method === 'post' && req.body !== null) {
- const methodsWithBody = ['post', 'put', 'patch', 'delete']
- if (methodsWithBody.includes(params.__ow_method) && req.body !== null) {
---- Recommended Format ;
#Expected Behaviour
The local dev server (aio app dev) should parse and merge the request body into action parameters for all HTTP methods that support a body — including PUT, PATCH, and DELETE — consistent with how Adobe I/O Runtime (OpenWhisk) handles these requests in production.
#Actual Behaviour
The local dev server only parses the request body for POST requests. When a PUT, PATCH, or DELETE request is made with a JSON body, the body is silently ignored and not merged into the action parameters. This causes the action to behave differently locally compared to when it is deployed to Adobe I/O Runtime.
#Steps to Reproduce
Create an Adobe App Builder project with a backend action that reads parameters from the request body (e.g. params.id, params.data).
Configure the action to be accessible via PUT, PATCH, or DELETE.
Start the local dev server with aio app dev.
Send a PUT, PATCH, or DELETE request to the local action endpoint with a JSON body:
bash curl -X PUT https://localhost:9080/api/v1/web/
-H "Content-Type: application/json"
-d '{"id": "123", "data": "updated-value"}'
Observe that the action receives an empty or incomplete parameter set — the body fields are missing.
Deploy the same action with aio app deploy and repeat the same curl request against the deployed Runtime URL — body parameters are received correctly.
#Sample Code that illustrates the problem
Action handler (actions/update/index.js):
javascriptasync function main(params) {
// Expected: { id: '123', data: 'updated-value' }
// Actual (local): {} — body not parsed for PUT/PATCH/DELETE
const { id, data } = params;
if (!id) {
return {
statusCode: 400,
body: { error: 'Missing required parameter: id' }
};
}
return {
statusCode: 200,
body: { message: Updated ${id} with ${data} }
};
}
module.exports = { main };
app.config.yaml (action configured for PUT):
yamlapplication:
actions: actions
runtimes:
default:
actions:
update:
function: actions/update/index.js
web: yes
annotations:
require-adobe-auth: false
Request that fails locally but works on Runtime:
bashcurl -X PUT https://localhost:9080/api/v1/web///update
-H "Content-Type: application/json"
-d '{"id": "123", "data": "updated-value"}'
Logs taken while reproducing problem
Local dev (aio app dev) — body params missing
{
"__ow_method": "put",
"__ow_headers": { "content-type": "application/json" },
"__ow_path": ""
❌ 'id' and 'data' are absent — body was not parsed
}
Adobe I/O Runtime (deployed) — body params correctly included
{
"__ow_method": "put",
"__ow_headers": { "content-type": "application/json" },
"__ow_path": "",
"id": "123", # ✅ present
"data": "updated-value" # ✅ present
}
Suspected source: The body-parsing middleware in aio-cli-plugin-app-dev likely has a condition that limits body parsing to POST only. The fix should extend this to also handle PUT, PATCH, and DELETE methods.
Environment Info
System:
OS: macOS 26.4
CPU: (10) arm64 Apple M1 Pro
Memory: 168.97 MB / 16.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 22.21.1 - /Users/allan/.nvm/versions/node/v22.21.1/bin/node
Yarn: 1.22.22 - /Users/allan/.nvm/versions/node/v22.21.1/bin/yarn
npm: 10.9.4 - /Users/allan/.nvm/versions/node/v22.21.1/bin/npm
Virtualization:
Docker: 24.0.6 - /usr/local/bin/docker
npmGlobalPackages:
@adobe/aio-cli: 11.0.2
Description
The local dev server (
aio app dev) does not parse the request body forPUT,PATCH, andDELETEHTTP methods. OnlyPOSTrequest bodies are parsed and merged into action parameters. This causes a discrepancy between the local dev environment and the actual Adobe I/O Runtime (OpenWhisk), where all HTTP methods with a body are correctly handled.Environment
Steps to Reproduce
PUTwith a JSON body:curl -sk -X PUT "https://localhost:9080/api/v1/web//"
-H "Content-Type: application/json"
-d '{"myField": "hello"}'
Root Cause
In src/lib/run-dev.js, the function createActionParametersFromRequest (line 604) only processes the request body when the method is post:
// Current code (line 604)
if (params.__ow_method === 'post' && req.body !== null) {
This should include all HTTP methods that can carry a request body:
// Suggested fix
const methodsWithBody = ['post', 'put', 'patch', 'delete']
if (methodsWithBody.includes(params.__ow_method) && req.body !== null) {
The Express middleware (express.json()) already parses the body for all methods correctly. The issue is only in the condition that decides whether to merge req.body into the action params.
Impact
Suggested Fix
Change line 604 in src/lib/run-dev.js:
---- Recommended Format ;
#Expected Behaviour
The local dev server (aio app dev) should parse and merge the request body into action parameters for all HTTP methods that support a body — including PUT, PATCH, and DELETE — consistent with how Adobe I/O Runtime (OpenWhisk) handles these requests in production.
#Actual Behaviour
The local dev server only parses the request body for POST requests. When a PUT, PATCH, or DELETE request is made with a JSON body, the body is silently ignored and not merged into the action parameters. This causes the action to behave differently locally compared to when it is deployed to Adobe I/O Runtime.
#Steps to Reproduce
Create an Adobe App Builder project with a backend action that reads parameters from the request body (e.g. params.id, params.data).
Configure the action to be accessible via PUT, PATCH, or DELETE.
Start the local dev server with aio app dev.
Send a PUT, PATCH, or DELETE request to the local action endpoint with a JSON body:
bash curl -X PUT https://localhost:9080/api/v1/web/
-H "Content-Type: application/json"
-d '{"id": "123", "data": "updated-value"}'
Observe that the action receives an empty or incomplete parameter set — the body fields are missing.
Deploy the same action with aio app deploy and repeat the same curl request against the deployed Runtime URL — body parameters are received correctly.
#Sample Code that illustrates the problem
Action handler (actions/update/index.js):
javascriptasync function main(params) {
// Expected: { id: '123', data: 'updated-value' }
// Actual (local): {} — body not parsed for PUT/PATCH/DELETE
const { id, data } = params;
if (!id) {
return {
statusCode: 400,
body: { error: 'Missing required parameter: id' }
};
}
return {
statusCode: 200,
body: { message:
Updated ${id} with ${data}}};
}
module.exports = { main };
app.config.yaml (action configured for PUT):
yamlapplication:
actions: actions
runtimes:
default:
actions:
update:
function: actions/update/index.js
web: yes
annotations:
require-adobe-auth: false
Request that fails locally but works on Runtime:
bashcurl -X PUT https://localhost:9080/api/v1/web///update
-H "Content-Type: application/json"
-d '{"id": "123", "data": "updated-value"}'
Logs taken while reproducing problem
Local dev (aio app dev) — body params missing
{
"__ow_method": "put",
"__ow_headers": { "content-type": "application/json" },
"__ow_path": ""
❌ 'id' and 'data' are absent — body was not parsed
}
Adobe I/O Runtime (deployed) — body params correctly included
{
"__ow_method": "put",
"__ow_headers": { "content-type": "application/json" },
"__ow_path": "",
"id": "123", # ✅ present
"data": "updated-value" # ✅ present
}
Suspected source: The body-parsing middleware in aio-cli-plugin-app-dev likely has a condition that limits body parsing to POST only. The fix should extend this to also handle PUT, PATCH, and DELETE methods.
Environment Info