I’d share a working approach that uses a custom node with execute()
to programmatically construct your x-www-form-urlencoded
body including the embedded JSON.
Since you’re aiming for a declarative solution, unfortunately INodeProperties
doesn’t support dynamic JSON composition within a single field natively (and expression: true
isn’t valid there either). But if you’re open to using a minimal programmatic node, this keeps things clean while giving you full control over the structure.
What This Node Does:
- Accepts three input fields:
name
, code
, and active
- Combines them into a JSON object
- Encodes that JSON object into a
x-www-form-urlencoded
body under a single field: major
- Outputs the result as a
body
string and appropriate headers for further HTTP use
Full Custom Node Code (TypeScript):
import { IExecuteFunctions } from 'n8n-workflow';
import { INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
export class JsonFormEncodeNode implements INodeType {
description: INodeTypeDescription = {
displayName: 'JSON Form Encode',
name: 'jsonFormEncode',
group: ['transform'],
version: 1,
description: 'Send x-www-form-urlencoded with embedded JSON in a single param',
defaults: {
name: 'JSON Form Encode',
},
inputs: ['main'],
outputs: ['main'],
properties: [
{
displayName: 'Name',
name: 'name',
type: 'string',
default: '',
},
{
displayName: 'Code',
name: 'code',
type: 'string',
default: '',
},
{
displayName: 'Active',
name: 'active',
type: 'boolean',
default: false,
},
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: INodeExecutionData[] = [];
for (let i = 0; i < items.length; i++) {
const name = this.getNodeParameter('name', i) as string;
const code = this.getNodeParameter('code', i) as string;
const active = this.getNodeParameter('active', i) as boolean;
const major = { name, code, active };
const formEncoded = new URLSearchParams();
formEncoded.append('major', JSON.stringify(major));
returnData.push({
json: {
body: formEncoded.toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
},
});
}
return [returnData];
}
}
Example Output:
The body
value from this node will look like:
major={"name":"Advanced Foobar","code":"Foo1","active":false}
And it includes a Content-Type: application/x-www-form-urlencoded
header so you can pipe this into an HTTP Request node or further downstream.
If you’re not building custom nodes or want help packaging this, I can share a .zip
or GitHub snippet too. Let me know!
Hope this clears it up and helps you move forward 